diff -Nru python-pyface-4.5.2/appveyor-clean-cache.txt python-pyface-6.1.2/appveyor-clean-cache.txt --- python-pyface-4.5.2/appveyor-clean-cache.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/appveyor-clean-cache.txt 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru python-pyface-4.5.2/CHANGES.txt python-pyface-6.1.2/CHANGES.txt --- python-pyface-4.5.2/CHANGES.txt 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/CHANGES.txt 2019-07-20 11:50:06.000000000 +0000 @@ -1,8 +1,277 @@ +================ Pyface Changelog ================ +Release 6.1.2 +============= + +This is a bugfix release which fixes a number of minor issues with the 6.1.1 release. + +Thanks to: + +Mark Dickinson, Prabhu Ramachandran, Corran Webster. + +Change summary +-------------- + +Fixes + +* Don't try to open directories in PythonEditorTask (#428) +* Regression test for split editor area merge messages (#424) +* Fix some comments that should be Traits doc-comments. (#426) +* Fix some occurrences of PyFace (should be Pyface) (#420) +* Use decorator form of classmethod and staticmethod. (#417) +* Use equality rather than is when checking orientation. (#422) +* Fix timer issues. (#409, #414, #415) +* Remove use of etsdevtools in an example file. (#413) +* Fix a questionable version check. (#411) +* Fix error during tab completion on shell. (#410) + + +Release 6.1.1 +============= + +This is a bugfix release which fixes a number of minor issues with the 6.1.0 release. + +Thanks to: + +David Baddeley, Christian Brodbeck, Mark Dickinson, Rahul Poruri, Corran Webster. + +Change summary +-------------- + +Fixes + +* Remove use of deprecated Traits get() method (#403) +* Fix pyqt5 webkit imports (#396) +* Remove use of cmp in fix_introspection_bug (#395) +* Update CI infrastructure (#394, #399) +* Update unittest imports (#391) +* Fix bug in argspec usage (#393) +* Fix regression in DoLaterTimer API (#389) + + +Release 6.1.0 +============= + +This release introduces a number of new features and bugfixes. The most +prominent of these is a set of Application classes designed to smooth the +transition between Tasks applications which use only Pyface, and those that +take advantage of the Envisage plug-in framework. Developers can now write +a Pyface TasksApplication and then easily transition to an Envisage +TasksApplication as the needs of their codebase grows. This feature has been +a few years in development, and thanks is due to Jonathan Rocher for helping +push this through to completion. + +This release also includes a complete re-write of the Pyface timer code to +make it easier to use and to provide a consistent and more Pythonic API +shared by the different back-ends. A backwards compatible API is still +available, but users of the Pyface timer code are encouraged to update to +the new API. + +ToolBars can now embed simple widgets, such as text fields, integer spinners, +and comboboxes, as well as simple TraitsUI views. This is provided via a +new "widget" style for Actions as well as the utility subclasses FieldAction +and TraitsUIWidgetAction. + +Although not visible to most users of Pyface, this release removes the use +of 2to3 and now uses a unified codebase supported by the six library. Thanks +to Rahul Poruri for performing this transformation. This should help +significantly with ongoing development work in the coming years. + +We also include experimental support for PySide2 (also called "Qt for Python"). +We are running CI tests using the 5.11 release of PySide2 with success on OS X +and Linux for Python 3, but are experiencing failures with the 5.12 release. + +Finally, this release includes a number of bugfixes and minor enhancements +which should improve the reliability and utility of the codebase. + +Thanks to: + +Martin Bergtholdt, Mark Dickinson, Robert Kern, Eric Larson, Gregory Lee, +Eric McDonald, Rahul Poruri, Jonathan Rocher, Hamdi Sahloul, Roger Serwy, +Brian Teague, Corran Webster, John Wiggins. + +Apologies to any contributors that have been omitted. + +Change summary +-------------- + +Enhancements + +* Application classes (#334, #355, #345) +* New API for Timers (#340, #365) +* Support simple widgets in toolbars (#359, #360, #368) +* Experimental support of Pyside2 (#318, #335, #358) +* Support single codebase for Python 2 and 3 (#322, #351, #369, #370) +* Support ui dispatch for Traits even if TraitsUI not available (#363) + +Fixes + +* Fix context menu behaviour (#356) +* Remove TraitsUI dependency in GuiTestAssistant (#366) +* Fixes for ProgressDialog (#357) +* Fixes for toolbar and statusbar life cycles (#332) +* Fixes for CI (#342) +* Fix usages of event_loop() in tests (#336) +* Fix SplitEditorAreaPane tab dragging on Qt5 (#327) +* Fix resource warnings in test suite from un-closed files (#326) +* Remove uses of deprecated HasTraits.set() method (#320) +* Add Qt5 support for deprecated Qt Style options that Mayavi needs (#323) +* Various fixes around Qt API selection (#319, #344, #347, #371, #376, #381) +* Fixes for setup.py (#380) + + +Release 6.0.0 +============= + +This release introduces preliminary support for Qt5 via PyQt5, thanks to the +work of Gregor Thalhammer which got the ball rolling. Qt5 support is +not yet robustly tested in deployed applications, so there may yet be bugs to +find. As part of this effort all occurences of old-style signals and slots +have been removed; and this has greatly improved stability under Qt. + +In addition, thanks to the dedicated work of Rob McMullen, we now have Tasks +support for wxPython. + +This release also features a great deal of work at the API level to disentangle +the two-way dependencies between Pyface and TraitsUI. This has involved moving +a number of sub-packages between the two libraries, most notably the zipped +image resource support and a number of trait definitions. We have endeavored +to keep backwards compatibility via stub modules in the original locations, +but we can't guarantee that there will be no issues with third party code +caused by the change in locations. We haven't been able to remove all +dependencies, but as of this release on the dock and workbench submodules have +required dependencies on TraitsUI. + +Another long-desired feature was the ability to write toolkit backends for +Pyface and TraitsUI that are not part of the main codebase. This is now +possible by contributing new toolkit backends to the "pyface.toolkit" +pkg_resources entry point in a setup.py. This work was accompanied by an +overhaul of the toolkit discovery and loading infrastructure; in particular +Pyface and TraitsUI now share the same code for performing these searches +and loading the backends. + +Finally, the testing infrastructure has been overhauled to provide a one-stop +location to run tests in self-contained environments using Enthought's EDM +package management tool. Tests can be run from any python environment with the +"edm" command available and the "click" library installed with the "etstool.py" +script at the top level of the repository. In particular:: + + python etstool.py test_all + +will run all relevant tests for all available toolkits in all supported +python versions. The TravisCI and Appveyor continuous integration tools have +been updated to make use of these facilities as well. + +Thanks to Florian Bender, Kit Choi, Mark Dickinson, Simon Jagoe, Robert Kern, +Rob McMullen, @nprksh, Prabhu Ramachandran, Gregor Thalhammer, Senganal +Thirunavukkarasu, Ioannis Tziakos, Joris Vankerscharver, and Corran Webster. +Apologies to any contributors that have been omitted. + +Change summary +-------------- + +Enhancements + +* Tasks support for wxPython (#223, #247) +* Qt5 Support (#170, #256, #264, #265, #268, #271, #279, #292) +* Disentangling Pyface and TraitsUI (#221, #250) +* EDM-based test runner (#243, #296, #298) +* Improved toolkit selection (#259, #260, #276, #304, #305) +* Move wxPython-specific code to pyface.wx (#261) +* Single choice dialog for Qt toolkit (was already in wx toolkit) (#217) +* Add 'detail' and 'informative' to window dialog helpers (#181) +* Code coverage reporting (#214) +* All Pyface widgets now have visible and enabled traits (#284) +* Allow "qt" as a synonym for "qt4" (#304) +* PythonShell widget history exposed via the API (#314) +* Experimental PySide2 support (#303) + +Fixes + +* Documentation fixes (#220, #231) +* Testing and CI fixes (#224, #226, #239, #248, #252, #253, #257, #267, #270, + #277, #278, #281, #283) +* Fix bug updating Tasks window titles (#225) +* Python 3 compatibility fixes (#228) +* Remove use of cmp in the AdvancedEditorAreaPane (#237) +* AutoPEP8 of Pyface codebase (#241) +* Minor WxPython fixes (#230, #269, #275, #294) +* Don't use sendPostedEvents in Qt GUI.do_trait_later (#273) +* Fix ordering of items when appending to an ActionManager default group (#290) +* Explicit life-cycle for Qt event filters on Widgets (#300) +* Fixes to ensure demos and examples work (#308) + +Release 5.1.0 +============= + +Change summary since 5.0.0 +-------------------------- + +Enhancements + +* Added documentation on toolkit selection (#197) +* Clarify the purpose of LayoutContainer construction args (#189) +* Improve ETSConfig toolkit selection (#187) + +Fixes + +* Fix restoring show_editor_area from saved perspective(#207) +* Fix WorkbenchWindowLayout in Python 3 (#206) +* Update SplitEditorAreaPane's active editor when focus changes under Qt (#203, #204) +* Read-only CodeEditor should not allow adding newlines in View (#200) +* Fix exception when closing all docks in a workbench window (#199) +* Fix extended trait change description in qt dock pane (#194) +* Fix Qt Workbench dock widget control in a workbench window (#192) +* Fix double UnInit of AUI in ApplicationWindow under Wx (#184, #185) +* Fix IPythonWidget syntax error (#178, #186) +* Fix ProgressDialog timer labels #(183) +* Fix Qt CodeWidget when focus goes out of a widget (#176, #177) +* Fix Qt and Wx ProgressDialog for updating message (#176, #177) + + +Release 5.0.0 +============= + +This release introduces preliminary support for Python 3 with the Qt toolkit! + +This is based in large part on the work of Yves Delley and Pradyun Gedam, but +also owes a lot to Ioannis Tziakos for implementing container-based continuous +integration and Prabhu Ramachandran and Corran Webster for tracking down the +few remaining bugs. Python 3 support is probably not yet ready for production +use, but feedback and bug reports are welcome, and all future pull requests +will be expected to work with Python 3.4 and later. Python 3 support requires +Traits 4.5 or greater, and TraitsUI 5.0 or greater. + +This release also bring support for wxPython 3.0, while dropping support for +wxPython 2.6 and earlier. There are also a couple of minor bug fixes detailed +below. + +Finally, this release changes the default GUI toolkit from Wx to Qt. This +changes the behaviour of the library in the case where both WxPython and +PyQt/PySide are installed and the user or code doesn't specify the toolkit to +use explicitly. + +Change summary since 4.5.2 +-------------------------- + +Features + +* Experimental support for Python 3 (#160, #161, #162, #163). +* Experimental support for wxPython 3 (#168). + +Enhancements + +* Make Qt 4 the default GUI toolkit (#172). + +Fixes + +* Fix issue with reading unicode text from Qt clipboard (#159). +* Remove usage of `logging.warn` in favour of `logger.warning` (#167). + Release 4.5.2 -——————————— +============= This release includes a large number of additions to the test suite that provide at least basic smoke-test coverage of the core of the library. There @@ -42,7 +311,7 @@ Release 4.5.1 -------------- +============= Change summary since 4.5.0 -------------------------- @@ -55,7 +324,7 @@ Release 4.5.0 -------------- +============= Change summary since 4.4.0 -------------------------- @@ -79,7 +348,7 @@ Release 4.4.0 -------------- +============= This is a bug fix release. The biggest change in this release is support for the new adaptation mechanism in Traits 4.4.0. diff -Nru python-pyface-4.5.2/ci-src-requirements.txt python-pyface-6.1.2/ci-src-requirements.txt --- python-pyface-4.5.2/ci-src-requirements.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/ci-src-requirements.txt 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1 @@ +git+http://github.com/enthought/traitsui.git#egg=traitsui diff -Nru python-pyface-4.5.2/debian/changelog python-pyface-6.1.2/debian/changelog --- python-pyface-4.5.2/debian/changelog 2015-08-17 02:16:53.000000000 +0000 +++ python-pyface-6.1.2/debian/changelog 2019-12-09 20:51:04.000000000 +0000 @@ -1,3 +1,56 @@ +python-pyface (6.1.2-2) unstable; urgency=medium + + * Team upload. + - Mostly no-change but needed to let the package migrate to testing. + * Change pypi.python.org links to pypi.org. + + -- Dmitry Shachnev Mon, 09 Dec 2019 23:51:04 +0300 + +python-pyface (6.1.2-1) unstable; urgency=medium + + * Team Upload + + [ Ondřej Nový ] + * Fixed homepage (https) + * Fixed VCS URL (https) + * d/control: Set Vcs-* to salsa.debian.org + * d/watch: Use https protocol + * d/control: Remove ancient X-Python-Version field + * Remove debian/pycompat, it's not used by any modern Python helper + * Convert git repository from git-dpm to gbp layout + * Bump Standards-Version to 4.4.1. + + [ Andreas Tille ] + * New upstream version + * Fixed watch file (dropped unneeded get-orig-source stuff) + * debhelper-compat 12 + * Point Vcs fields to salsa.debian.org + * Standards-Version: 4.4.0 + * Testsuite: autopkgtest-pkg-python + * Use Python3 + Closes: #938063 + * python3-pyqt5 + Closes: #935349 + * Use dh-python and pybuild + Closes: #671217 + * d/changelog: Use DEP5 format + + [ Scott Talbert ] + * d/control: Switch to use PyQt5 backend which seems best supported + * d/rules: Get the tests working + + [ Dmitry Shachnev ] + * Add pyface/_version.py and some files from egg-info to debian/clean. + * Add pyface.egg-info to debian/pybuild.testfiles to get the tests running + without nose. + * Tell pybuild to install the original icons.zip and std.zip files. + Without this, the files get repacked during test, and differ between + python3.7 and python3.8 because of differing timestamps, so dh_python3 + does not remove the files in /usr/lib/python3.8/dist-packages. + * Update debian/copyright. + + -- Scott Talbert Fri, 06 Dec 2019 16:00:24 -0500 + python-pyface (4.5.2-1) unstable; urgency=medium * New upstream release diff -Nru python-pyface-4.5.2/debian/clean python-pyface-6.1.2/debian/clean --- python-pyface-4.5.2/debian/clean 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/debian/clean 2019-12-09 20:51:04.000000000 +0000 @@ -0,0 +1,4 @@ +pyface/_version.py +pyface.egg-info/PKG-INFO +pyface.egg-info/SOURCES.txt +pyface.egg-info/requires.txt diff -Nru python-pyface-4.5.2/debian/compat python-pyface-6.1.2/debian/compat --- python-pyface-4.5.2/debian/compat 2011-07-09 18:00:18.000000000 +0000 +++ python-pyface-6.1.2/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -7 diff -Nru python-pyface-4.5.2/debian/control python-pyface-6.1.2/debian/control --- python-pyface-4.5.2/debian/control 2015-08-17 02:11:33.000000000 +0000 +++ python-pyface-6.1.2/debian/control 2019-12-09 20:51:04.000000000 +0000 @@ -1,21 +1,41 @@ Source: python-pyface -Section: python -Priority: optional Maintainer: Debian Python Modules Team Uploaders: Varun Hiremath -Build-Depends: cdbs, debhelper, python-all -Build-Depends-Indep: python-setupdocs -Standards-Version: 3.9.6 -Homepage: http://pypi.python.org/pypi/pyface -X-Python-Version: >= 2.5 -Vcs-Svn: svn://anonscm.debian.org/python-modules/packages/python-pyface/trunk/ -Vcs-Browser: http://anonscm.debian.org/viewvc/python-modules/packages/python-pyface/trunk/ +Section: python +Testsuite: autopkgtest-pkg-python +Priority: optional +Build-Depends: debhelper-compat (= 12), + dh-python, + python3-all, + python3-mock , + python3-numpy , + python3-pygments , + python3-pyqt5 , + python3-pyqt5.qtopengl , + python3-pyqt5.qtsvg , + python3-pyqt5.qtwebkit , + python3-setuptools, + python3-six , + python3-traits , + xauth , + xvfb , +Standards-Version: 4.4.1 +Vcs-Browser: https://salsa.debian.org/python-team/modules/python-pyface +Vcs-Git: https://salsa.debian.org/python-team/modules/python-pyface.git +Homepage: https://pypi.org/project/pyface/ -Package: python-pyface +Package: python3-pyface Architecture: all -Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python-wxgtk3.0, python-qt4 -Breaks: python-traitsbackendqt, python-traitsbackendwx -Replaces: python-traitsbackendqt, python-traitsbackendwx +Depends: ${shlibs:Depends}, + ${misc:Depends}, + ${python3:Depends}, + python3-numpy, + python3-pygments, + python3-pyqt5, + python3-pyqt5.qtopengl, + python3-pyqt5.qtsvg, + python3-pyqt5.qtwebkit, + python3-traits, Description: traits-capable windowing framework The pyface project contains a toolkit-independent GUI abstraction layer, which is used to support the "visualization" features of the diff -Nru python-pyface-4.5.2/debian/copyright python-pyface-6.1.2/debian/copyright --- python-pyface-4.5.2/debian/copyright 2011-07-09 18:00:18.000000000 +0000 +++ python-pyface-6.1.2/debian/copyright 2019-12-09 20:51:04.000000000 +0000 @@ -1,271 +1,343 @@ -This package was debianized by Varun Hiremath on -Fri, 26 Sep 2008 17:51:35 -0400 - -It was downloaded from http://pypi.python.org/pypi/pyface - -Upstream Author: Enthought, Inc. - -Copyright: © 2003-2008, Enthought, Inc. All rights reserved. - © 2007-2008, Riverbank Computing Limited - -License: BSD - 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. - * Neither the name of Enthought, Inc. nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - - 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. - --------------------------------------------------------------------------------- -Icon License: - -The icons are mostly derived work from other icons. As such they are -licensed accordingly to the original license: - - Eclipse: Eclipse Public Licence - Nuvola: LGPL - Crystal: LGPL - OOo: LGPL - GV (Gael Varoquaux): Public Domain - -Unless stated explicitly, icons are work of Enthought, and are -released under the 3 clause BSD license (see above). - -On Debian systems, the complete text of the LGPL License can be -found in `/usr/share/common-licenses/LGPL-2'. - -Full text of Eclipse Public License follows: - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE - PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE - PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial code and documentation - distributed under this Agreement, and - b) in the case of each subsequent Contributor: - - i) changes to the Program, and - - ii) additions to the Program; - - where such changes and/or additions to the Program originate from and are - distributed by that particular Contributor. A Contribution 'originates' - from a Contributor if it was added to the Program by such Contributor itself - or anyone acting on such Contributor's behalf. Contributions do not include - additions to the Program which: (i) are separate modules of software - distributed in conjunction with the Program under their own license - agreement, and (ii) are not derivative works of the Program. - - "Contributor" means any person or entity that distributes the Program. - - "Licensed Patents " mean patent claims licensable by a Contributor which are - necessarily infringed by the use or sale of its Contribution alone or when - combined with the Program. - - "Program" means the Contributions distributed in accordance with this - Agreement. - - "Recipient" means anyone who receives the Program under this Agreement, - including all Contributors. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor hereby grants - Recipient a non-exclusive, worldwide, royalty-free copyright license to - reproduce, prepare derivative works of, publicly display, publicly perform, - distribute and sublicense the Contribution of such Contributor, if any, - and such derivative works, in source code and object code form. - - b) Subject to the terms of this Agreement, each Contributor hereby grants - Recipient a non-exclusive, worldwide, royalty-free patent license under - Licensed Patents to make, use, sell, offer to sell, import and otherwise - transfer the Contribution of such Contributor, if any, in source code and - object code form. This patent license shall apply to the combination of - the Contribution and the Program if, at the time the Contribution is added - by the Contributor, such addition of the Contribution causes such - combination to be covered by the Licensed Patents. The patent license shall - not apply to any other combinations which include the Contribution. No - hardware per se is licensed hereunder. - - c) Recipient understands that although each Contributor grants the licenses - to its Contributions set forth herein, no assurances are provided by any - Contributor that the Program does not infringe the patent or other - intellectual property rights of any other entity. Each Contributor disclaims - any liability to Recipient for claims brought by any other entity based on - infringement of intellectual property rights or otherwise. As a condition to - exercising the rights and licenses granted hereunder, each Recipient hereby - assumes sole responsibility to secure any other intellectual property rights - needed, if any. For example, if a third party patent license is required to - allow Recipient to distribute the Program, it is Recipient's responsibility - to acquire that license before distributing the Program. - - d) Each Contributor represents that to its knowledge it has sufficient - copyright rights in its Contribution, if any, to grant the copyright license - set forth in this Agreement. - - 3. REQUIREMENTS - - A Contributor may choose to distribute the Program in object code form under - its own license agreement, provided that: - - a) it complies with the terms and conditions of this Agreement; and - - b) its license agreement: - - i) effectively disclaims on behalf of all Contributors all warranties and - conditions, express and implied, including warranties or conditions of title - and non-infringement, and implied warranties or conditions of merchantability - and fitness for a particular purpose; - - ii) effectively excludes on behalf of all Contributors all liability for - damages, including direct, indirect, special, incidental and consequential - damages, such as lost profits; - - iii) states that any provisions which differ from this Agreement are offered - by that Contributor alone and not by any other party; and - - iv) states that source code for the Program is available from such - Contributor, and informs licensees how to obtain it in a reasonable manner on - or through a medium customarily used for software exchange. - - When the Program is made available in source code form: - - a) it must be made available under this Agreement; and - - b) a copy of this Agreement must be included with each copy of the Program. - - Contributors may not remove or alter any copyright notices contained within - the Program. - - Each Contributor must identify itself as the originator of its Contribution, - if any, in a manner that reasonably allows subsequent Recipients to identify - the originator of the Contribution. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain responsibilities with - respect to end users, business partners and the like. While this license is - intended to facilitate the commercial use of the Program, the Contributor who - includes the Program in a commercial product offering should do so in a manner - which does not create potential liability for other Contributors. Therefore, - if a Contributor includes the Program in a commercial product offering, such - Contributor ("Commercial Contributor") hereby agrees to defend and indemnify - every other Contributor ("Indemnified Contributor") against any losses, - damages and costs (collectively "Losses") arising from claims, lawsuits and - other legal actions brought by a third party against the Indemnified - Contributor to the extent caused by the acts or omissions of such Commercial - Contributor in connection with its distribution of the Program in a commercial - product offering. The obligations in this section do not apply to any claims - or Losses relating to any actual or alleged intellectual property - infringement. In order to qualify, an Indemnified Contributor must: - a) promptly notify the Commercial Contributor in writing of such claim, and - b) allow the Commercial Contributor to control, and cooperate with the - Commercial Contributor in, the defense and any related settlement - negotiations. The Indemnified Contributor may participate in any such claim - at its own expense. - - For example, a Contributor might include the Program in a commercial product - offering, Product X. That Contributor is then a Commercial Contributor. If - that Commercial Contributor then makes performance claims, or offers - warranties related to Product X, those performance claims and warranties are - such Commercial Contributor's responsibility alone. Under this section, the - Commercial Contributor would have to defend claims against the other - Contributors related to those performance claims and warranties, and if a - court requires any other Contributor to pay any damages as a result, the - Commercial Contributor must pay those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON - AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER - EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR - CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A - PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the - appropriateness of using and distributing the Program and assumes all - risks associated with its exercise of rights under this Agreement , - including but not limited to the risks and costs of program errors, - compliance with applicable laws, damage to or loss of data, programs or - equipment, and unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY - CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION - LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE - EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under - applicable law, it shall not affect the validity or enforceability of the - remainder of the terms of this Agreement, and without further action by - the parties hereto, such provision shall be reformed to the minimum extent - necessary to make such provision valid and enforceable. - - If Recipient institutes patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Program itself - (excluding combinations of the Program with other software or hardware) - infringes such Recipient's patent(s), then such Recipient's rights granted - under Section 2(b) shall terminate as of the date such litigation is filed. - - All Recipient's rights under this Agreement shall terminate if it fails to - comply with any of the material terms or conditions of this Agreement and - does not cure such failure in a reasonable period of time after becoming - aware of such noncompliance. If all Recipient's rights under this Agreement - terminate, Recipient agrees to cease use and distribution of the Program as - soon as reasonably practicable. However, Recipient's obligations under this - Agreement and any licenses granted by Recipient relating to the Program - shall continue and survive. - - Everyone is permitted to copy and distribute copies of this Agreement, but - in order to avoid inconsistency the Agreement is copyrighted and may only - be modified in the following manner. The Agreement Steward reserves the - right to publish new versions (including revisions) of this Agreement from - time to time. No one other than the Agreement Steward has the right to - modify this Agreement. The Eclipse Foundation is the initial Agreement - Steward. The Eclipse Foundation may assign the responsibility to serve as - the Agreement Steward to a suitable separate entity. Each new version of - the Agreement will be given a distinguishing version number. The Program - (including Contributions) may always be distributed subject to the version - of the Agreement under which it was received. In addition, after a new - version of the Agreement is published, Contributor may elect to distribute - the Program (including its Contributions) under the new version. Except as - expressly stated in Sections 2(a) and 2(b) above, Recipient receives no - rights or licenses to the intellectual property of any Contributor under - this Agreement, whether expressly, by implication, estoppel or otherwise. - All rights in the Program not expressly granted under this Agreement are - reserved. - - This Agreement is governed by the laws of the State of New York and the - intellectual property laws of the United States of America. No party to - this Agreement will bring a legal action under this Agreement more than - one year after the cause of action arose. Each party waives its rights to - a jury trial in any resulting litigation. ---------------------------------------------------------------------------- - -The Debian packaging is © 2008 Varun Hiremath and -is licensed under the GPL, see `/usr/share/common-licenses/GPL-3'. +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: pyface +Source: https://pypi.org/project/pyface/ + +Files: * +Copyright: © 2003-2019, Enthought, Inc. + © 2007-2008, Riverbank Computing Limited +License: BSD-3-clause + +Files: debian/* +Copyright: 2008-2015 Varun Hiremath +License: GPL-3 + +Files: pyface/action/images/action.png + pyface/dock/images/window.png +Copyright: 2007 Eclipse Foundation +License: EPL-1.0 + +Files: pyface/images/close.png + pyface/images/question.png + pyface/dock/images/close_drag.png + pyface/dock/images/close_tab.png + pyface/dock/images/feature_tool.png + pyface/ui/wx/grid/images/checked.png + pyface/ui/wx/grid/images/unchecked.png + pyface/tree/images/document.png + examples/images/document.png +Copyright: 2007 Gael Varoquaux +License: public-domain + This file has been put into public domain. + +Files: pyface/images/image_not_found.png + pyface/ui/wx/grid/images/image_not_found.png +Copyright: 2003 Jakub 'jimmac' Steiner +License: LGPL-2.1 + +Files: pyface/tree/images/closed_folder.png + pyface/tree/images/open_folder.png + examples/images/closed_folder_24x24.png + examples/images/closed_folder.png + examples/images/open_folder.png + examples/dock/images/folder.png + examples/dock/images/gear.png +Copyright: 2007 Nuvola +License: LGPL-2.1 + +Files: pyface/dock/images/tab_feature_no_drop.png + pyface/dock/images/tab_feature_normal.png + pyface/ui/wx/grid/images/table_edit.png +Copyright: 2007 OpenOffice.org +License: LGPL-3 + +Files: pyface/beep.py + pyface/ui/qt4/beep.py + pyface/ui/wx/beep.py +Copyright: 2012 Philip Chimento +License: BSD-3-clause + +Files: pyface/util/guisupport.py +Copyright: 2008-2010 The IPython Development Team +License: BSD-3-clause + +License: BSD-3-clause + 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. + * Neither the name of Enthought, Inc. nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + . + 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. + +License: GPL-3 + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License version 3, as + published by the Free Software Foundation. + . + 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. + . + On Debian systems, the complete text of the GNU General Public License + version 3 can be found in /usr/share/common-licenses/GPL-3. + +License: LGPL-2.1 + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1, as published by the Free Software Foundation. + . + 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. + . + On Debian systems, the complete text of the GNU Lesser General Public + License version 2.1 can be found in /usr/share/common-licenses/LGPL-2.1. + +License: LGPL-3 + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + as published by the Free Software Foundation. + . + 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 Lesser General Public License for more details. + . + On Debian systems, the complete text of the GNU Lesser General Public + License version 3 can be found in /usr/share/common-licenses/LGPL-3. + +License: EPL-1.0 + Eclipse Public License - v 1.0 + . + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC + LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM + CONSTITUTES RECIPIENT’S ACCEPTANCE OF THIS AGREEMENT. + . + 1. DEFINITIONS + . + "Contribution" means: + . + a) in the case of the initial Contributor, the initial code and + documentation distributed under this Agreement, and + b) in the case of each subsequent Contributor: + . + i)changes to the Program, and + . + ii)additions to the Program; + . + where such changes and/or additions to the Program originate from and + are distributed by that particular Contributor. A Contribution 'originates' + from a Contributor if it was added to the Program by such Contributor itself + or anyone acting on such Contributor’s behalf. Contributions do not + include additions to the Program which: (i) are separate modules of software + distributed in conjunction with the Program under their own license + agreement, and (ii) are not derivative works of the Program. + . + "Contributor" means any person or entity that distributes the Program. + . + "Licensed Patents " mean patent claims licensable by a Contributor which are + necessarily infringed by the use or sale of its Contribution alone or when + combined with the Program. + . + "Program" means the Contributions distributed in accordance with this + Agreement. + . + "Recipient" means anyone who receives the Program under this Agreement, + including all Contributors. + . + 2. GRANT OF RIGHTS + . + a) Subject to the terms of this Agreement, each Contributor hereby grants + Recipient a non-exclusive, worldwide, royalty-free copyright license to + reproduce, prepare derivative works of, publicly display, publicly perform, + distribute and sublicense the Contribution of such Contributor, if any, and + such derivative works, in source code and object code form. + . + b) Subject to the terms of this Agreement, each Contributor hereby grants + Recipient a non-exclusive, worldwide, royalty-free patent license under + Licensed Patents to make, use, sell, offer to sell, import and otherwise + transfer the Contribution of such Contributor, if any, in source code and + object code form. This patent license shall apply to the combination of the + Contribution and the Program if, at the time the Contribution is added by + the Contributor, such addition of the Contribution causes such combination + to be covered by the Licensed Patents. The patent license shall not apply to + any other combinations which include the Contribution. No hardware per se is + licensed hereunder. + . + c) Recipient understands that although each Contributor grants the licenses + to its Contributions set forth herein, no assurances are provided by any + Contributor that the Program does not infringe the patent or other + intellectual property rights of any other entity. Each Contributor disclaims + any liability to Recipient for claims brought by any other entity based on + infringement of intellectual property rights or otherwise. As a condition to + exercising the rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual property rights + needed, if any. For example, if a third party patent license is required to + allow Recipient to distribute the Program, it is Recipient’s + responsibility to acquire that license before distributing the Program. + . + d) Each Contributor represents that to its knowledge it has sufficient + copyright rights in its Contribution, if any, to grant the copyright license + set forth in this Agreement. + . + 3. REQUIREMENTS + . + A Contributor may choose to distribute the Program in object code form under + its own license agreement, provided that: + . + a) it complies with the terms and conditions of this Agreement; and + . + b) its license agreement: + . + i) effectively disclaims on behalf of all Contributors all warranties + and conditions, express and implied, including warranties or conditions of + title and non-infringement, and implied warranties or conditions of + merchantability and fitness for a particular purpose; + . + ii) effectively excludes on behalf of all Contributors all liability for + damages, including direct, indirect, special, incidental and consequential + damages, such as lost profits; + . + iii) states that any provisions which differ from this Agreement are + offered by that Contributor alone and not by any other party; and + . + iv) states that source code for the Program is available from such + Contributor, and informs licensees how to obtain it in a reasonable manner + on or through a medium customarily used for software exchange. + . + When the Program is made available in source code form: + . + a) it must be made available under this Agreement; and + . + b) a copy of this Agreement must be included with each copy of the + Program. + . + Contributors may not remove or alter any copyright notices contained within + the Program. + . + Each Contributor must identify itself as the originator of its Contribution, + if any, in a manner that reasonably allows subsequent Recipients to identify + the originator of the Contribution. + . + 4. COMMERCIAL DISTRIBUTION + . + Commercial distributors of software may accept certain responsibilities with + respect to end users, business partners and the like. While this license is + intended to facilitate the commercial use of the Program, the Contributor + who includes the Program in a commercial product offering should do so in a + manner which does not create potential liability for other Contributors. + Therefore, if a Contributor includes the Program in a commercial product + offering, such Contributor ("Commercial Contributor") hereby agrees to + defend and indemnify every other Contributor ("Indemnified Contributor") + against any losses, damages and costs (collectively "Losses") arising from + claims, lawsuits and other legal actions brought by a third party against + the Indemnified Contributor to the extent caused by the acts or omissions of + such Commercial Contributor in connection with its distribution of the + Program in a commercial product offering. The obligations in this section do + not apply to any claims or Losses relating to any actual or alleged + intellectual property infringement. In order to qualify, an Indemnified + Contributor must: a) promptly notify the Commercial Contributor in writing + of such claim, and b) allow the Commercial Contributor to control, and + cooperate with the Commercial Contributor in, the defense and any related + settlement negotiations. The Indemnified Contributor may participate in any + such claim at its own expense. + . + For example, a Contributor might include the Program in a commercial product + offering, Product X. That Contributor is then a Commercial Contributor. If + that Commercial Contributor then makes performance claims, or offers + warranties related to Product X, those performance claims and warranties are + such Commercial Contributor’s responsibility alone. Under this section, + the Commercial Contributor would have to defend claims against the other + Contributors related to those performance claims and warranties, and if a + court requires any other Contributor to pay any damages as a result, the + Commercial Contributor must pay those damages. + . + 5. NO WARRANTY + . + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON + AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER + EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR + CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A + PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the + appropriateness of using and distributing the Program and assumes all risks + associated with its exercise of rights under this Agreement , including but + not limited to the risks and costs of program errors, compliance with + applicable laws, damage to or loss of data, programs or equipment, and + unavailability or interruption of operations. + . + 6. DISCLAIMER OF LIABILITY + . + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY + CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION + LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE + EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGES. + . + 7. GENERAL + . + If any provision of this Agreement is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of the + remainder of the terms of this Agreement, and without further action by the + parties hereto, such provision shall be reformed to the minimum extent + necessary to make such provision valid and enforceable. + . + If Recipient institutes patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Program itself + (excluding combinations of the Program with other software or hardware) + infringes such Recipient’s patent(s), then such Recipient’s rights + granted under Section 2(b) shall terminate as of the date such litigation is + filed. + . + All Recipient’s rights under this Agreement shall terminate if it fails to + comply with any of the material terms or conditions of this Agreement and + does not cure such failure in a reasonable period of time after becoming + aware of such noncompliance. If all Recipient’s rights under this + Agreement terminate, Recipient agrees to cease use and distribution of the + Program as soon as reasonably practicable. However, Recipient’s + obligations under this Agreement and any licenses granted by Recipient + relating to the Program shall continue and survive. + . + Everyone is permitted to copy and distribute copies of this Agreement, but + in order to avoid inconsistency the Agreement is copyrighted and may only be + modified in the following manner. The Agreement Steward reserves the right + to publish new versions (including revisions) of this Agreement from time to + time. No one other than the Agreement Steward has the right to modify this + Agreement. The Eclipse Foundation is the initial Agreement Steward. The + Eclipse Foundation may assign the responsibility to serve as the Agreement + Steward to a suitable separate entity. Each new version of the Agreement + will be given a distinguishing version number. The Program (including + Contributions) may always be distributed subject to the version of the + Agreement under which it was received. In addition, after a new version of + the Agreement is published, Contributor may elect to distribute the Program + (including its Contributions) under the new version. Except as expressly + stated in Sections 2(a) and 2(b) above, Recipient receives no rights or + licenses to the intellectual property of any Contributor under this + Agreement, whether expressly, by implication, estoppel or otherwise. All + rights in the Program not expressly granted under this Agreement are + reserved. + . + This Agreement is governed by the laws of the State of New York and the + intellectual property laws of the United States of America. No party to this + Agreement will bring a legal action under this Agreement more than one year + after the cause of action arose. Each party waives its rights to a jury + trial in any resulting litigation. diff -Nru python-pyface-4.5.2/debian/orig-tar.sh python-pyface-6.1.2/debian/orig-tar.sh --- python-pyface-4.5.2/debian/orig-tar.sh 2011-07-09 18:00:18.000000000 +0000 +++ python-pyface-6.1.2/debian/orig-tar.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -#!/bin/sh -e - -# move to directory 'tarballs' -if [ -r .svn/deb-layout ]; then - . .svn/deb-layout - mv $3 $origDir - echo "moved $3 to $origDir" -fi diff -Nru python-pyface-4.5.2/debian/patches/series python-pyface-6.1.2/debian/patches/series --- python-pyface-4.5.2/debian/patches/series 2014-09-03 04:15:27.000000000 +0000 +++ python-pyface-6.1.2/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -wxpy3.0-compat.patch diff -Nru python-pyface-4.5.2/debian/patches/wxpy3.0-compat.patch python-pyface-6.1.2/debian/patches/wxpy3.0-compat.patch --- python-pyface-4.5.2/debian/patches/wxpy3.0-compat.patch 2015-08-17 02:16:08.000000000 +0000 +++ python-pyface-6.1.2/debian/patches/wxpy3.0-compat.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,116 +0,0 @@ -Description: Updates for wxPython 3.0 - These changes should maintain compatibility with wxPython 2.8. -Author: Olly Betts -Forwarded: no -Last-Update: 2015-03-26 - -Index: python-pyface-4.5.2/pyface/ui/wx/directory_dialog.py -=================================================================== ---- python-pyface-4.5.2.orig/pyface/ui/wx/directory_dialog.py -+++ python-pyface-4.5.2/pyface/ui/wx/directory_dialog.py -@@ -70,7 +70,7 @@ class DirectoryDialog(MDirectoryDialog, - - def _create_control(self, parent): - # The default style. -- style = wx.OPEN -+ style = 0 - - # Create the wx style depending on which buttons are required etc. - if self.new_directory: -Index: python-pyface-4.5.2/pyface/ui/wx/file_dialog.py -=================================================================== ---- python-pyface-4.5.2.orig/pyface/ui/wx/file_dialog.py -+++ python-pyface-4.5.2/pyface/ui/wx/file_dialog.py -@@ -105,11 +105,11 @@ class FileDialog(MFileDialog, Dialog): - default_filename = self.default_filename - - if self.action == 'open': -- style = wx.OPEN -+ style = wx.FD_OPEN - elif self.action == 'open files': -- style = wx.OPEN | wx.MULTIPLE -+ style = wx.FD_OPEN | wx.FD_MULTIPLE - else: -- style = wx.SAVE | wx.OVERWRITE_PROMPT -+ style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT - - # Create the actual dialog. - dialog = wx.FileDialog(parent, self.title, defaultDir=default_directory, -Index: python-pyface-4.5.2/pyface/ui/wx/init.py -=================================================================== ---- python-pyface-4.5.2.orig/pyface/ui/wx/init.py -+++ python-pyface-4.5.2/pyface/ui/wx/init.py -@@ -15,17 +15,17 @@ import wx - - - # Check the version number is late enough. --if wx.VERSION < (2, 6): -- raise RuntimeError, "Need wx version 2.6 or higher, but got %s" % str(wx.VERSION) -+if wx.VERSION < (2, 8): -+ raise RuntimeError, "Need wx version 2.8 or higher, but got %s" % str(wx.VERSION) - - # It's possible that it has already been initialised. - _app = wx.GetApp() - - if _app is None: -- _app = wx.PySimpleApp() -- -- # Before we can load any images we have to initialize wxPython's image -- # handlers. -- wx.InitAllImageHandlers() -+ # wx.PySimpleApp() is deprecated in wx3.0, but this is all it really does: -+ class PySimpleApp(wx.App): -+ def OnInit(self): -+ return True -+ _app = PySimpleApp() - - #### EOF ###################################################################### -Index: python-pyface-4.5.2/pyface/wx/dialog.py -=================================================================== ---- python-pyface-4.5.2.orig/pyface/wx/dialog.py -+++ python-pyface-4.5.2/pyface/wx/dialog.py -@@ -36,7 +36,7 @@ class OpenFileDialog(wx.FileDialog): - def __init__(self, parent=None, **kw): - """ Constructor. """ - -- style = wx.OPEN | wx.HIDE_READONLY -+ style = wx.FD_OPEN - - # Base-class constructor. - wx.FileDialog.__init__(self, parent, "Open", style=style, **kw) -@@ -49,7 +49,7 @@ class OpenDirDialog(wx.DirDialog): - def __init__(self, parent=None, **kw): - """ Constructor. """ - -- style = wx.OPEN | wx.HIDE_READONLY | wx.DD_NEW_DIR_BUTTON -+ style = wx.DD_NEW_DIR_BUTTON - - # Base-class constructor. - wx.DirDialog.__init__(self, parent, "Open", style=style, **kw) -@@ -62,7 +62,7 @@ class SaveFileAsDialog(wx.FileDialog): - def __init__(self, parent=None, **kw): - """ Constructor. """ - -- style = wx.SAVE | wx.OVERWRITE_PROMPT -+ style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT - - # Base-class constructor. - wx.FileDialog.__init__(self, parent, "Save As", style=style, **kw) -Index: python-pyface-4.5.2/pyface/util/guisupport.py -=================================================================== ---- python-pyface-4.5.2.orig/pyface/util/guisupport.py -+++ python-pyface-4.5.2/pyface/util/guisupport.py -@@ -81,7 +81,12 @@ def get_app_wx(*args, **kwargs): - if app is None: - if not kwargs.has_key('redirect'): - kwargs['redirect'] = False -- app = wx.PySimpleApp(*args, **kwargs) -+ # wx.PySimpleApp() is deprecated in wx3.0, but this is all it really -+ # does: -+ class PySimpleApp(wx.App): -+ def OnInit(self): -+ return True -+ app = PySimpleApp(*args, **kwargs) - return app - - def is_event_loop_running_wx(app=None): diff -Nru python-pyface-4.5.2/debian/pybuild.testfiles python-pyface-6.1.2/debian/pybuild.testfiles --- python-pyface-4.5.2/debian/pybuild.testfiles 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/debian/pybuild.testfiles 2019-12-09 20:51:04.000000000 +0000 @@ -0,0 +1 @@ +pyface.egg-info diff -Nru python-pyface-4.5.2/debian/pycompat python-pyface-6.1.2/debian/pycompat --- python-pyface-4.5.2/debian/pycompat 2011-07-09 18:00:18.000000000 +0000 +++ python-pyface-6.1.2/debian/pycompat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -2 diff -Nru python-pyface-4.5.2/debian/rules python-pyface-6.1.2/debian/rules --- python-pyface-4.5.2/debian/rules 2014-09-03 04:07:59.000000000 +0000 +++ python-pyface-6.1.2/debian/rules 2019-12-09 20:51:04.000000000 +0000 @@ -1,18 +1,18 @@ #!/usr/bin/make -f -include /usr/share/cdbs/1/rules/debhelper.mk -include /usr/share/cdbs/1/class/python-distutils.mk +# Uncomment this to turn on verbose mode. +export DH_VERBOSE=1 -DEB_COMPRESS_EXCLUDE := .py -DEB_PYTHON_INSTALL_ARGS_ALL += --single-version-externally-managed -PYSHARED = $(DEB_DESTDIR)/usr/share/pyshared -PYLIBS = $(DEB_DESTDIR)/usr/lib/python* +export PYBUILD_NAME=pyface +export PYBUILD_AFTER_INSTALL=cp -v {dir}/pyface/image/library/*.zip {destdir}{install_dir}/pyface/image/library -install/python-pyface:: - find $(DEB_DESTDIR) -name 'image_LICENSE.txt' -delete +## When trying better hardening the build fails +# export DEB_BUILD_MAINT_OPTIONS = hardening=+all -binary-predeb/python-pyface:: - find $(PYLIBS) -type f | xargs chmod 644 +%: + dh $@ --with python3 --buildsystem=pybuild -get-orig-source: - -uscan --force-download --rename +override_dh_auto_test: +ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) + xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" dh_auto_test +endif diff -Nru python-pyface-4.5.2/debian/watch python-pyface-6.1.2/debian/watch --- python-pyface-4.5.2/debian/watch 2015-08-17 02:12:16.000000000 +0000 +++ python-pyface-6.1.2/debian/watch 2019-12-09 20:51:04.000000000 +0000 @@ -1,4 +1,3 @@ -version=3 -opts="uversionmangle=s/([ab])/~$1/,dversionmangle=s/\+.*//" \ -http://pypi.debian.net/pyface/pyface-(.*).tar.gz \ -debian debian/orig-tar.sh +version=4 + +https://pypi.python.org/simple/pyface .*/pyface-@ANY_VERSION@@ARCHIVE_EXT@#sha256=.* diff -Nru python-pyface-4.5.2/docs/source/api/pyface.about_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.about_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.about_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.about_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.about\_dialog module +=========================== + +.. automodule:: pyface.about_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.action_controller.rst python-pyface-6.1.2/docs/source/api/pyface.action.action_controller.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.action_controller.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.action_controller.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.action\_controller module +======================================= + +.. automodule:: pyface.action.action_controller + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.action_event.rst python-pyface-6.1.2/docs/source/api/pyface.action.action_event.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.action_event.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.action_event.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.action\_event module +================================== + +.. automodule:: pyface.action.action_event + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.action_item.rst python-pyface-6.1.2/docs/source/api/pyface.action.action_item.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.action_item.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.action_item.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.action\_item module +================================= + +.. automodule:: pyface.action.action_item + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.action_manager_item.rst python-pyface-6.1.2/docs/source/api/pyface.action.action_manager_item.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.action_manager_item.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.action_manager_item.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.action\_manager\_item module +========================================== + +.. automodule:: pyface.action.action_manager_item + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.action_manager.rst python-pyface-6.1.2/docs/source/api/pyface.action.action_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.action_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.action_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.action\_manager module +==================================== + +.. automodule:: pyface.action.action_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.action.rst python-pyface-6.1.2/docs/source/api/pyface.action.action.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.action module +=========================== + +.. automodule:: pyface.action.action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.api.rst python-pyface-6.1.2/docs/source/api/pyface.action.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.api.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.api module +======================== + +.. automodule:: pyface.action.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.field_action.rst python-pyface-6.1.2/docs/source/api/pyface.action.field_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.field_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.field_action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.field\_action module +================================== + +.. automodule:: pyface.action.field_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.group.rst python-pyface-6.1.2/docs/source/api/pyface.action.group.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.group.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.group.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.group module +========================== + +.. automodule:: pyface.action.group + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.gui_application_action.rst python-pyface-6.1.2/docs/source/api/pyface.action.gui_application_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.gui_application_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.gui_application_action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.gui\_application\_action module +============================================= + +.. automodule:: pyface.action.gui_application_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.listening_action.rst python-pyface-6.1.2/docs/source/api/pyface.action.listening_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.listening_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.listening_action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.listening\_action module +====================================== + +.. automodule:: pyface.action.listening_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.menu_bar_manager.rst python-pyface-6.1.2/docs/source/api/pyface.action.menu_bar_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.menu_bar_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.menu_bar_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.menu\_bar\_manager module +======================================= + +.. automodule:: pyface.action.menu_bar_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.menu_manager.rst python-pyface-6.1.2/docs/source/api/pyface.action.menu_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.menu_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.menu_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.menu\_manager module +================================== + +.. automodule:: pyface.action.menu_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.rst python-pyface-6.1.2/docs/source/api/pyface.action.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,123 +1,39 @@ -action Package -============== - -:mod:`action` Package ---------------------- +pyface.action package +===================== .. automodule:: pyface.action :members: :undoc-members: :show-inheritance: -:mod:`action` Module --------------------- - -.. automodule:: pyface.action.action - :members: - :undoc-members: - :show-inheritance: - -:mod:`action_controller` Module -------------------------------- - -.. automodule:: pyface.action.action_controller - :members: - :undoc-members: - :show-inheritance: - -:mod:`action_event` Module --------------------------- - -.. automodule:: pyface.action.action_event - :members: - :undoc-members: - :show-inheritance: - -:mod:`action_item` Module -------------------------- - -.. automodule:: pyface.action.action_item - :members: - :undoc-members: - :show-inheritance: - -:mod:`action_manager` Module ----------------------------- - -.. automodule:: pyface.action.action_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`action_manager_item` Module ---------------------------------- +Subpackages +----------- -.. automodule:: pyface.action.action_manager_item - :members: - :undoc-members: - :show-inheritance: - -:mod:`api` Module ------------------ - -.. automodule:: pyface.action.api - :members: - :undoc-members: - :show-inheritance: +.. toctree:: -:mod:`group` Module -------------------- + pyface.action.tests -.. automodule:: pyface.action.group - :members: - :undoc-members: - :show-inheritance: - -:mod:`menu_bar_manager` Module ------------------------------- - -.. automodule:: pyface.action.menu_bar_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`menu_manager` Module --------------------------- - -.. automodule:: pyface.action.menu_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`status_bar_manager` Module --------------------------------- - -.. automodule:: pyface.action.status_bar_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`tool_bar_manager` Module ------------------------------- - -.. automodule:: pyface.action.tool_bar_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`tool_palette_manager` Module ----------------------------------- - -.. automodule:: pyface.action.tool_palette_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`window_action` Module ---------------------------- - -.. automodule:: pyface.action.window_action - :members: - :undoc-members: - :show-inheritance: +Submodules +---------- + +.. toctree:: + + pyface.action.action + pyface.action.action_controller + pyface.action.action_event + pyface.action.action_item + pyface.action.action_manager + pyface.action.action_manager_item + pyface.action.api + pyface.action.field_action + pyface.action.group + pyface.action.gui_application_action + pyface.action.listening_action + pyface.action.menu_bar_manager + pyface.action.menu_manager + pyface.action.status_bar_manager + pyface.action.tool_bar_manager + pyface.action.tool_palette_manager + pyface.action.traitsui_widget_action + pyface.action.window_action diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.status_bar_manager.rst python-pyface-6.1.2/docs/source/api/pyface.action.status_bar_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.status_bar_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.status_bar_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.status\_bar\_manager module +========================================= + +.. automodule:: pyface.action.status_bar_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.tests.rst python-pyface-6.1.2/docs/source/api/pyface.action.tests.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.tests.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.tests.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,24 @@ +pyface.action.tests package +=========================== + +.. automodule:: pyface.action.tests + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + + pyface.action.tests.test_action + pyface.action.tests.test_action_controller + pyface.action.tests.test_action_event + pyface.action.tests.test_action_item + pyface.action.tests.test_action_manager + pyface.action.tests.test_field_action + pyface.action.tests.test_group + pyface.action.tests.test_gui_application_action + pyface.action.tests.test_listening_action + pyface.action.tests.test_traitsui_widget_action + diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_action_controller.rst python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_action_controller.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_action_controller.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_action_controller.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.tests.test\_action\_controller module +=================================================== + +.. automodule:: pyface.action.tests.test_action_controller + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_action_event.rst python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_action_event.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_action_event.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_action_event.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.tests.test\_action\_event module +============================================== + +.. automodule:: pyface.action.tests.test_action_event + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_action_item.rst python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_action_item.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_action_item.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_action_item.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.tests.test\_action\_item module +============================================= + +.. automodule:: pyface.action.tests.test_action_item + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_action_manager.rst python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_action_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_action_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_action_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.tests.test\_action\_manager module +================================================ + +.. automodule:: pyface.action.tests.test_action_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_action.rst python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.tests.test\_action module +======================================= + +.. automodule:: pyface.action.tests.test_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_field_action.rst python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_field_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_field_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_field_action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.tests.test\_field\_action module +============================================== + +.. automodule:: pyface.action.tests.test_field_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_group.rst python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_group.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_group.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_group.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.tests.test\_group module +====================================== + +.. automodule:: pyface.action.tests.test_group + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_gui_application_action.rst python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_gui_application_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_gui_application_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_gui_application_action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.tests.test\_gui\_application\_action module +========================================================= + +.. automodule:: pyface.action.tests.test_gui_application_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_listening_action.rst python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_listening_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_listening_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_listening_action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.tests.test\_listening\_action module +================================================== + +.. automodule:: pyface.action.tests.test_listening_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_traitsui_widget_action.rst python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_traitsui_widget_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.tests.test_traitsui_widget_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.tests.test_traitsui_widget_action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.tests.test\_traitsui\_widget\_action module +========================================================= + +.. automodule:: pyface.action.tests.test_traitsui_widget_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.tool_bar_manager.rst python-pyface-6.1.2/docs/source/api/pyface.action.tool_bar_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.tool_bar_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.tool_bar_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.tool\_bar\_manager module +======================================= + +.. automodule:: pyface.action.tool_bar_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.tool_palette_manager.rst python-pyface-6.1.2/docs/source/api/pyface.action.tool_palette_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.tool_palette_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.tool_palette_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.tool\_palette\_manager module +=========================================== + +.. automodule:: pyface.action.tool_palette_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.traitsui_widget_action.rst python-pyface-6.1.2/docs/source/api/pyface.action.traitsui_widget_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.traitsui_widget_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.traitsui_widget_action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.traitsui\_widget\_action module +============================================= + +.. automodule:: pyface.action.traitsui_widget_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.action.window_action.rst python-pyface-6.1.2/docs/source/api/pyface.action.window_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.action.window_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.action.window_action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.action.window\_action module +=================================== + +.. automodule:: pyface.action.window_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.api.rst python-pyface-6.1.2/docs/source/api/pyface.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.api.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.api module +================= + +.. automodule:: pyface.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.application.rst python-pyface-6.1.2/docs/source/api/pyface.application.rst --- python-pyface-4.5.2/docs/source/api/pyface.application.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.application.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.application module +========================= + +.. automodule:: pyface.application + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.application_window.rst python-pyface-6.1.2/docs/source/api/pyface.application_window.rst --- python-pyface-4.5.2/docs/source/api/pyface.application_window.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.application_window.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.application\_window module +================================= + +.. automodule:: pyface.application_window + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.base_toolkit.rst python-pyface-6.1.2/docs/source/api/pyface.base_toolkit.rst --- python-pyface-4.5.2/docs/source/api/pyface.base_toolkit.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.base_toolkit.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.base\_toolkit module +=========================== + +.. automodule:: pyface.base_toolkit + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.beep.rst python-pyface-6.1.2/docs/source/api/pyface.beep.rst --- python-pyface-4.5.2/docs/source/api/pyface.beep.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.beep.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.beep module +================== + +.. automodule:: pyface.beep + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.clipboard.rst python-pyface-6.1.2/docs/source/api/pyface.clipboard.rst --- python-pyface-4.5.2/docs/source/api/pyface.clipboard.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.clipboard.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.clipboard module +======================= + +.. automodule:: pyface.clipboard + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.confirmation_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.confirmation_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.confirmation_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.confirmation_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.confirmation\_dialog module +================================== + +.. automodule:: pyface.confirmation_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.constant.rst python-pyface-6.1.2/docs/source/api/pyface.constant.rst --- python-pyface-4.5.2/docs/source/api/pyface.constant.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.constant.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.constant module +====================== + +.. automodule:: pyface.constant + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.dialog.rst python-pyface-6.1.2/docs/source/api/pyface.dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.dialog module +==================== + +.. automodule:: pyface.dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.directory_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.directory_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.directory_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.directory_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.directory\_dialog module +=============================== + +.. automodule:: pyface.directory_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.dock.rst python-pyface-6.1.2/docs/source/api/pyface.dock.rst --- python-pyface-4.5.2/docs/source/api/pyface.dock.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.dock.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -dock Package -============ - -:mod:`dock` Package -------------------- - -.. automodule:: pyface.dock - :members: - :undoc-members: - :show-inheritance: - -:mod:`api` Module ------------------ - -.. automodule:: pyface.dock.api - :members: - :undoc-members: - :show-inheritance: - -:mod:`dock_sizer` Module ------------------------- - -.. automodule:: pyface.dock.dock_sizer - :members: - :undoc-members: - :show-inheritance: - -:mod:`dock_window` Module -------------------------- - -.. automodule:: pyface.dock.dock_window - :members: - :undoc-members: - :show-inheritance: - -:mod:`dock_window_feature` Module ---------------------------------- - -.. automodule:: pyface.dock.dock_window_feature - :members: - :undoc-members: - :show-inheritance: - -:mod:`dock_window_shell` Module -------------------------------- - -.. automodule:: pyface.dock.dock_window_shell - :members: - :undoc-members: - :show-inheritance: - -:mod:`feature_bar` Module -------------------------- - -.. automodule:: pyface.dock.feature_bar - :members: - :undoc-members: - :show-inheritance: - -:mod:`feature_tool` Module --------------------------- - -.. automodule:: pyface.dock.feature_tool - :members: - :undoc-members: - :show-inheritance: - -:mod:`idock_ui_provider` Module -------------------------------- - -.. automodule:: pyface.dock.idock_ui_provider - :members: - :undoc-members: - :show-inheritance: - -:mod:`idockable` Module ------------------------ - -.. automodule:: pyface.dock.idockable - :members: - :undoc-members: - :show-inheritance: - -:mod:`ifeature_tool` Module ---------------------------- - -.. automodule:: pyface.dock.ifeature_tool - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.drop_handler.rst python-pyface-6.1.2/docs/source/api/pyface.drop_handler.rst --- python-pyface-4.5.2/docs/source/api/pyface.drop_handler.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.drop_handler.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.drop\_handler module +=========================== + +.. automodule:: pyface.drop_handler + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.expandable_header.rst python-pyface-6.1.2/docs/source/api/pyface.expandable_header.rst --- python-pyface-4.5.2/docs/source/api/pyface.expandable_header.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.expandable_header.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.expandable\_header module +================================ + +.. automodule:: pyface.expandable_header + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.expandable_panel.rst python-pyface-6.1.2/docs/source/api/pyface.expandable_panel.rst --- python-pyface-4.5.2/docs/source/api/pyface.expandable_panel.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.expandable_panel.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.expandable\_panel module +=============================== + +.. automodule:: pyface.expandable_panel + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.fields.api.rst python-pyface-6.1.2/docs/source/api/pyface.fields.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.fields.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.fields.api.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.fields.api module +======================== + +.. automodule:: pyface.fields.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.fields.combo_field.rst python-pyface-6.1.2/docs/source/api/pyface.fields.combo_field.rst --- python-pyface-4.5.2/docs/source/api/pyface.fields.combo_field.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.fields.combo_field.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.fields.combo\_field module +================================= + +.. automodule:: pyface.fields.combo_field + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.fields.i_combo_field.rst python-pyface-6.1.2/docs/source/api/pyface.fields.i_combo_field.rst --- python-pyface-4.5.2/docs/source/api/pyface.fields.i_combo_field.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.fields.i_combo_field.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.fields.i\_combo\_field module +==================================== + +.. automodule:: pyface.fields.i_combo_field + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.fields.i_field.rst python-pyface-6.1.2/docs/source/api/pyface.fields.i_field.rst --- python-pyface-4.5.2/docs/source/api/pyface.fields.i_field.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.fields.i_field.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.fields.i\_field module +============================= + +.. automodule:: pyface.fields.i_field + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.fields.i_spin_field.rst python-pyface-6.1.2/docs/source/api/pyface.fields.i_spin_field.rst --- python-pyface-4.5.2/docs/source/api/pyface.fields.i_spin_field.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.fields.i_spin_field.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.fields.i\_spin\_field module +=================================== + +.. automodule:: pyface.fields.i_spin_field + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.fields.i_text_field.rst python-pyface-6.1.2/docs/source/api/pyface.fields.i_text_field.rst --- python-pyface-4.5.2/docs/source/api/pyface.fields.i_text_field.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.fields.i_text_field.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.fields.i\_text\_field module +=================================== + +.. automodule:: pyface.fields.i_text_field + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.fields.rst python-pyface-6.1.2/docs/source/api/pyface.fields.rst --- python-pyface-4.5.2/docs/source/api/pyface.fields.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.fields.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,29 @@ +pyface.fields package +===================== + +.. automodule:: pyface.fields + :members: + :undoc-members: + :show-inheritance: + +Subpackages +----------- + +.. toctree:: + + pyface.fields.tests + +Submodules +---------- + +.. toctree:: + + pyface.fields.api + pyface.fields.combo_field + pyface.fields.i_combo_field + pyface.fields.i_field + pyface.fields.i_spin_field + pyface.fields.i_text_field + pyface.fields.spin_field + pyface.fields.text_field + diff -Nru python-pyface-4.5.2/docs/source/api/pyface.fields.spin_field.rst python-pyface-6.1.2/docs/source/api/pyface.fields.spin_field.rst --- python-pyface-4.5.2/docs/source/api/pyface.fields.spin_field.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.fields.spin_field.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.fields.spin\_field module +================================ + +.. automodule:: pyface.fields.spin_field + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.fields.tests.field_mixin.rst python-pyface-6.1.2/docs/source/api/pyface.fields.tests.field_mixin.rst --- python-pyface-4.5.2/docs/source/api/pyface.fields.tests.field_mixin.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.fields.tests.field_mixin.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.fields.tests.field\_mixin module +======================================= + +.. automodule:: pyface.fields.tests.field_mixin + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.fields.tests.rst python-pyface-6.1.2/docs/source/api/pyface.fields.tests.rst --- python-pyface-4.5.2/docs/source/api/pyface.fields.tests.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.fields.tests.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,18 @@ +pyface.fields.tests package +=========================== + +.. automodule:: pyface.fields.tests + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + + pyface.fields.tests.field_mixin + pyface.fields.tests.test_combo_field + pyface.fields.tests.test_spin_field + pyface.fields.tests.test_text_field + diff -Nru python-pyface-4.5.2/docs/source/api/pyface.fields.tests.test_combo_field.rst python-pyface-6.1.2/docs/source/api/pyface.fields.tests.test_combo_field.rst --- python-pyface-4.5.2/docs/source/api/pyface.fields.tests.test_combo_field.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.fields.tests.test_combo_field.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.fields.tests.test\_combo\_field module +============================================= + +.. automodule:: pyface.fields.tests.test_combo_field + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.fields.tests.test_spin_field.rst python-pyface-6.1.2/docs/source/api/pyface.fields.tests.test_spin_field.rst --- python-pyface-4.5.2/docs/source/api/pyface.fields.tests.test_spin_field.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.fields.tests.test_spin_field.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.fields.tests.test\_spin\_field module +============================================ + +.. automodule:: pyface.fields.tests.test_spin_field + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.fields.tests.test_text_field.rst python-pyface-6.1.2/docs/source/api/pyface.fields.tests.test_text_field.rst --- python-pyface-4.5.2/docs/source/api/pyface.fields.tests.test_text_field.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.fields.tests.test_text_field.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.fields.tests.test\_text\_field module +============================================ + +.. automodule:: pyface.fields.tests.test_text_field + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.fields.text_field.rst python-pyface-6.1.2/docs/source/api/pyface.fields.text_field.rst --- python-pyface-4.5.2/docs/source/api/pyface.fields.text_field.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.fields.text_field.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.fields.text\_field module +================================ + +.. automodule:: pyface.fields.text_field + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.file_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.file_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.file_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.file_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.file\_dialog module +========================== + +.. automodule:: pyface.file_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.filter.rst python-pyface-6.1.2/docs/source/api/pyface.filter.rst --- python-pyface-4.5.2/docs/source/api/pyface.filter.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.filter.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.filter module +==================== + +.. automodule:: pyface.filter + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.grid.rst python-pyface-6.1.2/docs/source/api/pyface.grid.rst --- python-pyface-4.5.2/docs/source/api/pyface.grid.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.grid.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,131 +0,0 @@ -grid Package -============ - -:mod:`api` Module ------------------ - -.. automodule:: pyface.grid.api - :members: - :undoc-members: - :show-inheritance: - -:mod:`checkbox_image_renderer` Module -------------------------------------- - -.. automodule:: pyface.grid.checkbox_image_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`checkbox_renderer` Module -------------------------------- - -.. automodule:: pyface.grid.checkbox_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`combobox_focus_handler` Module ------------------------------------- - -.. automodule:: pyface.grid.combobox_focus_handler - :members: - :undoc-members: - :show-inheritance: - -:mod:`composite_grid_model` Module ----------------------------------- - -.. automodule:: pyface.grid.composite_grid_model - :members: - :undoc-members: - :show-inheritance: - -:mod:`edit_image_renderer` Module ---------------------------------- - -.. automodule:: pyface.grid.edit_image_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`edit_renderer` Module ---------------------------- - -.. automodule:: pyface.grid.edit_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`grid` Module ------------------- - -.. automodule:: pyface.grid.grid - :members: - :undoc-members: - :show-inheritance: - -:mod:`grid_cell_image_renderer` Module --------------------------------------- - -.. automodule:: pyface.grid.grid_cell_image_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`grid_cell_renderer` Module --------------------------------- - -.. automodule:: pyface.grid.grid_cell_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`grid_model` Module ------------------------- - -.. automodule:: pyface.grid.grid_model - :members: - :undoc-members: - :show-inheritance: - -:mod:`inverted_grid_model` Module ---------------------------------- - -.. automodule:: pyface.grid.inverted_grid_model - :members: - :undoc-members: - :show-inheritance: - -:mod:`mapped_grid_cell_image_renderer` Module ---------------------------------------------- - -.. automodule:: pyface.grid.mapped_grid_cell_image_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`simple_grid_model` Module -------------------------------- - -.. automodule:: pyface.grid.simple_grid_model - :members: - :undoc-members: - :show-inheritance: - -:mod:`trait_grid_cell_adapter` Module -------------------------------------- - -.. automodule:: pyface.grid.trait_grid_cell_adapter - :members: - :undoc-members: - :show-inheritance: - -:mod:`trait_grid_model` Module ------------------------------- - -.. automodule:: pyface.grid.trait_grid_model - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.gui_application.rst python-pyface-6.1.2/docs/source/api/pyface.gui_application.rst --- python-pyface-4.5.2/docs/source/api/pyface.gui_application.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.gui_application.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.gui\_application module +============================== + +.. automodule:: pyface.gui_application + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.gui.rst python-pyface-6.1.2/docs/source/api/pyface.gui.rst --- python-pyface-4.5.2/docs/source/api/pyface.gui.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.gui.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.gui module +================= + +.. automodule:: pyface.gui + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.heading_text.rst python-pyface-6.1.2/docs/source/api/pyface.heading_text.rst --- python-pyface-4.5.2/docs/source/api/pyface.heading_text.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.heading_text.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.heading\_text module +=========================== + +.. automodule:: pyface.heading_text + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_about_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.i_about_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_about_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_about_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_about\_dialog module +============================== + +.. automodule:: pyface.i_about_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_application_window.rst python-pyface-6.1.2/docs/source/api/pyface.i_application_window.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_application_window.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_application_window.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_application\_window module +==================================== + +.. automodule:: pyface.i_application_window + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_clipboard.rst python-pyface-6.1.2/docs/source/api/pyface.i_clipboard.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_clipboard.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_clipboard.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_clipboard module +========================== + +.. automodule:: pyface.i_clipboard + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_confirmation_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.i_confirmation_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_confirmation_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_confirmation_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_confirmation\_dialog module +===================================== + +.. automodule:: pyface.i_confirmation_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.i_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_dialog module +======================= + +.. automodule:: pyface.i_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_directory_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.i_directory_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_directory_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_directory_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_directory\_dialog module +================================== + +.. automodule:: pyface.i_directory_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_drop_handler.rst python-pyface-6.1.2/docs/source/api/pyface.i_drop_handler.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_drop_handler.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_drop_handler.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_drop\_handler module +============================== + +.. automodule:: pyface.i_drop_handler + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_file_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.i_file_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_file_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_file_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_file\_dialog module +============================= + +.. automodule:: pyface.i_file_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_gui.rst python-pyface-6.1.2/docs/source/api/pyface.i_gui.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_gui.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_gui.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_gui module +==================== + +.. automodule:: pyface.i_gui + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_heading_text.rst python-pyface-6.1.2/docs/source/api/pyface.i_heading_text.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_heading_text.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_heading_text.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_heading\_text module +============================== + +.. automodule:: pyface.i_heading_text + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_image_cache.rst python-pyface-6.1.2/docs/source/api/pyface.i_image_cache.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_image_cache.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_image_cache.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_image\_cache module +============================= + +.. automodule:: pyface.i_image_cache + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_image_resource.rst python-pyface-6.1.2/docs/source/api/pyface.i_image_resource.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_image_resource.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_image_resource.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_image\_resource module +================================ + +.. automodule:: pyface.i_image_resource + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.image_button.rst python-pyface-6.1.2/docs/source/api/pyface.image_button.rst --- python-pyface-4.5.2/docs/source/api/pyface.image_button.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.image_button.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.image\_button module +=========================== + +.. automodule:: pyface.image_button + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.image_cache.rst python-pyface-6.1.2/docs/source/api/pyface.image_cache.rst --- python-pyface-4.5.2/docs/source/api/pyface.image_cache.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.image_cache.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.image\_cache module +========================== + +.. automodule:: pyface.image_cache + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.image.image.rst python-pyface-6.1.2/docs/source/api/pyface.image.image.rst --- python-pyface-4.5.2/docs/source/api/pyface.image.image.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.image.image.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.image.image module +========================= + +.. automodule:: pyface.image.image + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.image_list.rst python-pyface-6.1.2/docs/source/api/pyface.image_list.rst --- python-pyface-4.5.2/docs/source/api/pyface.image_list.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.image_list.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.image\_list module +========================= + +.. automodule:: pyface.image_list + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.image_resource.rst python-pyface-6.1.2/docs/source/api/pyface.image_resource.rst --- python-pyface-4.5.2/docs/source/api/pyface.image_resource.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.image_resource.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.image\_resource module +============================= + +.. automodule:: pyface.image_resource + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.image.rst python-pyface-6.1.2/docs/source/api/pyface.image.rst --- python-pyface-4.5.2/docs/source/api/pyface.image.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.image.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,15 @@ +pyface.image package +==================== + +.. automodule:: pyface.image + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + + pyface.image.image + diff -Nru python-pyface-4.5.2/docs/source/api/pyface.image_widget.rst python-pyface-6.1.2/docs/source/api/pyface.image_widget.rst --- python-pyface-4.5.2/docs/source/api/pyface.image_widget.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.image_widget.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.image\_widget module +=========================== + +.. automodule:: pyface.image_widget + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_message_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.i_message_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_message_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_message_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_message\_dialog module +================================ + +.. automodule:: pyface.i_message_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_progress_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.i_progress_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_progress_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_progress_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_progress\_dialog module +================================= + +.. automodule:: pyface.i_progress_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_python_editor.rst python-pyface-6.1.2/docs/source/api/pyface.i_python_editor.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_python_editor.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_python_editor.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_python\_editor module +=============================== + +.. automodule:: pyface.i_python_editor + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_python_shell.rst python-pyface-6.1.2/docs/source/api/pyface.i_python_shell.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_python_shell.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_python_shell.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_python\_shell module +============================== + +.. automodule:: pyface.i_python_shell + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ipython_widget.rst python-pyface-6.1.2/docs/source/api/pyface.ipython_widget.rst --- python-pyface-4.5.2/docs/source/api/pyface.ipython_widget.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ipython_widget.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.ipython\_widget module +============================= + +.. automodule:: pyface.ipython_widget + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_single_choice_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.i_single_choice_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_single_choice_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_single_choice_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_single\_choice\_dialog module +======================================= + +.. automodule:: pyface.i_single_choice_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_splash_screen.rst python-pyface-6.1.2/docs/source/api/pyface.i_splash_screen.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_splash_screen.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_splash_screen.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_splash\_screen module +=============================== + +.. automodule:: pyface.i_splash_screen + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_split_widget.rst python-pyface-6.1.2/docs/source/api/pyface.i_split_widget.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_split_widget.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_split_widget.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_split\_widget module +============================== + +.. automodule:: pyface.i_split_widget + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_system_metrics.rst python-pyface-6.1.2/docs/source/api/pyface.i_system_metrics.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_system_metrics.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_system_metrics.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_system\_metrics module +================================ + +.. automodule:: pyface.i_system_metrics + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_widget.rst python-pyface-6.1.2/docs/source/api/pyface.i_widget.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_widget.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_widget.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_widget module +======================= + +.. automodule:: pyface.i_widget + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.i_window.rst python-pyface-6.1.2/docs/source/api/pyface.i_window.rst --- python-pyface-4.5.2/docs/source/api/pyface.i_window.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.i_window.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.i\_window module +======================= + +.. automodule:: pyface.i_window + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.key_pressed_event.rst python-pyface-6.1.2/docs/source/api/pyface.key_pressed_event.rst --- python-pyface-4.5.2/docs/source/api/pyface.key_pressed_event.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.key_pressed_event.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.key\_pressed\_event module +================================= + +.. automodule:: pyface.key_pressed_event + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.layered_panel.rst python-pyface-6.1.2/docs/source/api/pyface.layered_panel.rst --- python-pyface-4.5.2/docs/source/api/pyface.layered_panel.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.layered_panel.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.layered\_panel module +============================ + +.. automodule:: pyface.layered_panel + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.list_box_model.rst python-pyface-6.1.2/docs/source/api/pyface.list_box_model.rst --- python-pyface-4.5.2/docs/source/api/pyface.list_box_model.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.list_box_model.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.list\_box\_model module +============================== + +.. automodule:: pyface.list_box_model + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.list_box.rst python-pyface-6.1.2/docs/source/api/pyface.list_box.rst --- python-pyface-4.5.2/docs/source/api/pyface.list_box.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.list_box.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.list\_box module +======================= + +.. automodule:: pyface.list_box + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.mdi_application_window.rst python-pyface-6.1.2/docs/source/api/pyface.mdi_application_window.rst --- python-pyface-4.5.2/docs/source/api/pyface.mdi_application_window.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.mdi_application_window.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.mdi\_application\_window module +====================================== + +.. automodule:: pyface.mdi_application_window + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.mdi_window_menu.rst python-pyface-6.1.2/docs/source/api/pyface.mdi_window_menu.rst --- python-pyface-4.5.2/docs/source/api/pyface.mdi_window_menu.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.mdi_window_menu.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.mdi\_window\_menu module +=============================== + +.. automodule:: pyface.mdi_window_menu + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.message_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.message_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.message_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.message_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.message\_dialog module +============================= + +.. automodule:: pyface.message_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.mimedata.rst python-pyface-6.1.2/docs/source/api/pyface.mimedata.rst --- python-pyface-4.5.2/docs/source/api/pyface.mimedata.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.mimedata.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.mimedata module +====================== + +.. automodule:: pyface.mimedata + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.multi_toolbar_window.rst python-pyface-6.1.2/docs/source/api/pyface.multi_toolbar_window.rst --- python-pyface-4.5.2/docs/source/api/pyface.multi_toolbar_window.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.multi_toolbar_window.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.multi\_toolbar\_window module +==================================== + +.. automodule:: pyface.multi_toolbar_window + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.preference.api.rst python-pyface-6.1.2/docs/source/api/pyface.preference.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.preference.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.preference.api.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.preference.api module +============================ + +.. automodule:: pyface.preference.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.preference.preference_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.preference.preference_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.preference.preference_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.preference.preference_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.preference.preference\_dialog module +=========================================== + +.. automodule:: pyface.preference.preference_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.preference.preference_node.rst python-pyface-6.1.2/docs/source/api/pyface.preference.preference_node.rst --- python-pyface-4.5.2/docs/source/api/pyface.preference.preference_node.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.preference.preference_node.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.preference.preference\_node module +========================================= + +.. automodule:: pyface.preference.preference_node + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.preference.preference_page.rst python-pyface-6.1.2/docs/source/api/pyface.preference.preference_page.rst --- python-pyface-4.5.2/docs/source/api/pyface.preference.preference_page.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.preference.preference_page.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.preference.preference\_page module +========================================= + +.. automodule:: pyface.preference.preference_page + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.preference.rst python-pyface-6.1.2/docs/source/api/pyface.preference.rst --- python-pyface-4.5.2/docs/source/api/pyface.preference.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.preference.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,43 +1,18 @@ -preference Package -================== - -:mod:`preference` Package -------------------------- +pyface.preference package +========================= .. automodule:: pyface.preference :members: :undoc-members: :show-inheritance: -:mod:`api` Module ------------------ - -.. automodule:: pyface.preference.api - :members: - :undoc-members: - :show-inheritance: - -:mod:`preference_dialog` Module -------------------------------- - -.. automodule:: pyface.preference.preference_dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`preference_node` Module ------------------------------ +Submodules +---------- -.. automodule:: pyface.preference.preference_node - :members: - :undoc-members: - :show-inheritance: +.. toctree:: -:mod:`preference_page` Module ------------------------------ - -.. automodule:: pyface.preference.preference_page - :members: - :undoc-members: - :show-inheritance: + pyface.preference.api + pyface.preference.preference_dialog + pyface.preference.preference_node + pyface.preference.preference_page diff -Nru python-pyface-4.5.2/docs/source/api/pyface.progress_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.progress_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.progress_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.progress_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.progress\_dialog module +============================== + +.. automodule:: pyface.progress_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.python_editor.rst python-pyface-6.1.2/docs/source/api/pyface.python_editor.rst --- python-pyface-4.5.2/docs/source/api/pyface.python_editor.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.python_editor.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.python\_editor module +============================ + +.. automodule:: pyface.python_editor + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.python_shell.rst python-pyface-6.1.2/docs/source/api/pyface.python_shell.rst --- python-pyface-4.5.2/docs/source/api/pyface.python_shell.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.python_shell.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.python\_shell module +=========================== + +.. automodule:: pyface.python_shell + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.qt.rst python-pyface-6.1.2/docs/source/api/pyface.qt.rst --- python-pyface-4.5.2/docs/source/api/pyface.qt.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.qt.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -qt Package -========== - -:mod:`qt` Package ------------------ - -.. automodule:: pyface.qt - :members: - :undoc-members: - :show-inheritance: - -:mod:`QtCore` Module --------------------- - -.. automodule:: pyface.qt.QtCore - :members: - :undoc-members: - :show-inheritance: - -:mod:`QtGui` Module -------------------- - -.. automodule:: pyface.qt.QtGui - :members: - :undoc-members: - :show-inheritance: - -:mod:`QtNetwork` Module ------------------------ - -.. automodule:: pyface.qt.QtNetwork - :members: - :undoc-members: - :show-inheritance: - -:mod:`QtOpenGL` Module ----------------------- - -.. automodule:: pyface.qt.QtOpenGL - :members: - :undoc-members: - :show-inheritance: - -:mod:`QtScript` Module ----------------------- - -.. automodule:: pyface.qt.QtScript - :members: - :undoc-members: - :show-inheritance: - -:mod:`QtSvg` Module -------------------- - -.. automodule:: pyface.qt.QtSvg - :members: - :undoc-members: - :show-inheritance: - -:mod:`QtTest` Module --------------------- - -.. automodule:: pyface.qt.QtTest - :members: - :undoc-members: - :show-inheritance: - -:mod:`QtWebKit` Module ----------------------- - -.. automodule:: pyface.qt.QtWebKit - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.resource.api.rst python-pyface-6.1.2/docs/source/api/pyface.resource.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.resource.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.resource.api.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.resource.api module +========================== + +.. automodule:: pyface.resource.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.resource_manager.rst python-pyface-6.1.2/docs/source/api/pyface.resource_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.resource_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.resource_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.resource\_manager module +=============================== + +.. automodule:: pyface.resource_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.resource.resource_factory.rst python-pyface-6.1.2/docs/source/api/pyface.resource.resource_factory.rst --- python-pyface-4.5.2/docs/source/api/pyface.resource.resource_factory.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.resource.resource_factory.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.resource.resource\_factory module +======================================== + +.. automodule:: pyface.resource.resource_factory + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.resource.resource_manager.rst python-pyface-6.1.2/docs/source/api/pyface.resource.resource_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.resource.resource_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.resource.resource_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.resource.resource\_manager module +======================================== + +.. automodule:: pyface.resource.resource_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.resource.resource_path.rst python-pyface-6.1.2/docs/source/api/pyface.resource.resource_path.rst --- python-pyface-4.5.2/docs/source/api/pyface.resource.resource_path.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.resource.resource_path.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.resource.resource\_path module +===================================== + +.. automodule:: pyface.resource.resource_path + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.resource.resource_reference.rst python-pyface-6.1.2/docs/source/api/pyface.resource.resource_reference.rst --- python-pyface-4.5.2/docs/source/api/pyface.resource.resource_reference.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.resource.resource_reference.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.resource.resource\_reference module +========================================== + +.. automodule:: pyface.resource.resource_reference + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.resource.rst python-pyface-6.1.2/docs/source/api/pyface.resource.rst --- python-pyface-4.5.2/docs/source/api/pyface.resource.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.resource.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,51 +1,19 @@ -resource Package -================ - -:mod:`resource` Package ------------------------ +pyface.resource package +======================= .. automodule:: pyface.resource :members: :undoc-members: :show-inheritance: -:mod:`api` Module ------------------ - -.. automodule:: pyface.resource.api - :members: - :undoc-members: - :show-inheritance: - -:mod:`resource_factory` Module ------------------------------- +Submodules +---------- -.. automodule:: pyface.resource.resource_factory - :members: - :undoc-members: - :show-inheritance: +.. toctree:: -:mod:`resource_manager` Module ------------------------------- - -.. automodule:: pyface.resource.resource_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`resource_path` Module ---------------------------- - -.. automodule:: pyface.resource.resource_path - :members: - :undoc-members: - :show-inheritance: - -:mod:`resource_reference` Module --------------------------------- - -.. automodule:: pyface.resource.resource_reference - :members: - :undoc-members: - :show-inheritance: + pyface.resource.api + pyface.resource.resource_factory + pyface.resource.resource_manager + pyface.resource.resource_path + pyface.resource.resource_reference diff -Nru python-pyface-4.5.2/docs/source/api/pyface.rst python-pyface-6.1.2/docs/source/api/pyface.rst --- python-pyface-4.5.2/docs/source/api/pyface.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,24 +1,108 @@ -pyface Package +pyface package ============== +.. automodule:: pyface + :members: + :undoc-members: + :show-inheritance: + +Subpackages +----------- + .. toctree:: - :maxdepth: 1 pyface.action - pyface.dock - pyface.grid + pyface.fields + pyface.image pyface.preference - pyface.qt pyface.resource pyface.sizers pyface.tasks pyface.tests pyface.timer pyface.tree - pyface.ui pyface.util pyface.viewer pyface.wizard pyface.workbench - pyface.wx + +Submodules +---------- + +.. toctree:: + + pyface.about_dialog + pyface.api + pyface.application + pyface.application_window + pyface.base_toolkit + pyface.beep + pyface.clipboard + pyface.confirmation_dialog + pyface.constant + pyface.dialog + pyface.directory_dialog + pyface.drop_handler + pyface.expandable_header + pyface.expandable_panel + pyface.file_dialog + pyface.filter + pyface.gui + pyface.gui_application + pyface.heading_text + pyface.i_about_dialog + pyface.i_application_window + pyface.i_clipboard + pyface.i_confirmation_dialog + pyface.i_dialog + pyface.i_directory_dialog + pyface.i_drop_handler + pyface.i_file_dialog + pyface.i_gui + pyface.i_heading_text + pyface.i_image_cache + pyface.i_image_resource + pyface.i_message_dialog + pyface.i_progress_dialog + pyface.i_python_editor + pyface.i_python_shell + pyface.i_single_choice_dialog + pyface.i_splash_screen + pyface.i_split_widget + pyface.i_system_metrics + pyface.i_widget + pyface.i_window + pyface.image_button + pyface.image_cache + pyface.image_list + pyface.image_resource + pyface.image_widget + pyface.ipython_widget + pyface.key_pressed_event + pyface.layered_panel + pyface.list_box + pyface.list_box_model + pyface.mdi_application_window + pyface.mdi_window_menu + pyface.message_dialog + pyface.mimedata + pyface.multi_toolbar_window + pyface.progress_dialog + pyface.python_editor + pyface.python_shell + pyface.resource_manager + pyface.single_choice_dialog + pyface.sorter + pyface.splash_screen + pyface.splash_screen_log_handler + pyface.split_application_window + pyface.split_dialog + pyface.split_panel + pyface.split_widget + pyface.system_metrics + pyface.toolkit + pyface.ui_traits + pyface.widget + pyface.window + pyface.xrc_dialog diff -Nru python-pyface-4.5.2/docs/source/api/pyface.single_choice_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.single_choice_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.single_choice_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.single_choice_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.single\_choice\_dialog module +==================================== + +.. automodule:: pyface.single_choice_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.sizers.flow.rst python-pyface-6.1.2/docs/source/api/pyface.sizers.flow.rst --- python-pyface-4.5.2/docs/source/api/pyface.sizers.flow.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.sizers.flow.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.sizers.flow module +========================= + +.. automodule:: pyface.sizers.flow + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.sizers.rst python-pyface-6.1.2/docs/source/api/pyface.sizers.rst --- python-pyface-4.5.2/docs/source/api/pyface.sizers.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.sizers.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,11 +1,15 @@ -sizers Package -============== +pyface.sizers package +===================== -:mod:`flow` Module ------------------- - -.. automodule:: pyface.sizers.flow +.. automodule:: pyface.sizers :members: :undoc-members: :show-inheritance: +Submodules +---------- + +.. toctree:: + + pyface.sizers.flow + diff -Nru python-pyface-4.5.2/docs/source/api/pyface.sorter.rst python-pyface-6.1.2/docs/source/api/pyface.sorter.rst --- python-pyface-4.5.2/docs/source/api/pyface.sorter.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.sorter.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.sorter module +==================== + +.. automodule:: pyface.sorter + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.splash_screen_log_handler.rst python-pyface-6.1.2/docs/source/api/pyface.splash_screen_log_handler.rst --- python-pyface-4.5.2/docs/source/api/pyface.splash_screen_log_handler.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.splash_screen_log_handler.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.splash\_screen\_log\_handler module +========================================== + +.. automodule:: pyface.splash_screen_log_handler + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.splash_screen.rst python-pyface-6.1.2/docs/source/api/pyface.splash_screen.rst --- python-pyface-4.5.2/docs/source/api/pyface.splash_screen.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.splash_screen.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.splash\_screen module +============================ + +.. automodule:: pyface.splash_screen + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.split_application_window.rst python-pyface-6.1.2/docs/source/api/pyface.split_application_window.rst --- python-pyface-4.5.2/docs/source/api/pyface.split_application_window.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.split_application_window.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.split\_application\_window module +======================================== + +.. automodule:: pyface.split_application_window + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.split_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.split_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.split_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.split_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.split\_dialog module +=========================== + +.. automodule:: pyface.split_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.split_panel.rst python-pyface-6.1.2/docs/source/api/pyface.split_panel.rst --- python-pyface-4.5.2/docs/source/api/pyface.split_panel.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.split_panel.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.split\_panel module +========================== + +.. automodule:: pyface.split_panel + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.split_widget.rst python-pyface-6.1.2/docs/source/api/pyface.split_widget.rst --- python-pyface-4.5.2/docs/source/api/pyface.split_widget.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.split_widget.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.split\_widget module +=========================== + +.. automodule:: pyface.split_widget + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.system_metrics.rst python-pyface-6.1.2/docs/source/api/pyface.system_metrics.rst --- python-pyface-4.5.2/docs/source/api/pyface.system_metrics.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.system_metrics.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.system\_metrics module +============================= + +.. automodule:: pyface.system_metrics + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.action.api.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.action.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.action.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.action.api.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.action.api module +============================== + +.. automodule:: pyface.tasks.action.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.action.dock_pane_toggle_group.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.action.dock_pane_toggle_group.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.action.dock_pane_toggle_group.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.action.dock_pane_toggle_group.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.action.dock\_pane\_toggle\_group module +==================================================== + +.. automodule:: pyface.tasks.action.dock_pane_toggle_group + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.action.listening_action.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.action.listening_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.action.listening_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.action.listening_action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.action.listening\_action module +============================================ + +.. automodule:: pyface.tasks.action.listening_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.action.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.action.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.action.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,75 +1,25 @@ -action Package -============== +pyface.tasks.action package +=========================== -:mod:`api` Module ------------------ - -.. automodule:: pyface.tasks.action.api - :members: - :undoc-members: - :show-inheritance: - -:mod:`dock_pane_toggle_group` Module ------------------------------------- - -.. automodule:: pyface.tasks.action.dock_pane_toggle_group - :members: - :undoc-members: - :show-inheritance: - -:mod:`listening_action` Module ------------------------------- - -.. automodule:: pyface.tasks.action.listening_action - :members: - :undoc-members: - :show-inheritance: - -:mod:`schema` Module --------------------- - -.. automodule:: pyface.tasks.action.schema - :members: - :undoc-members: - :show-inheritance: - -:mod:`schema_addition` Module ------------------------------ - -.. automodule:: pyface.tasks.action.schema_addition - :members: - :undoc-members: - :show-inheritance: - -:mod:`task_action` Module -------------------------- - -.. automodule:: pyface.tasks.action.task_action +.. automodule:: pyface.tasks.action :members: :undoc-members: :show-inheritance: -:mod:`task_action_controller` Module ------------------------------------- +Submodules +---------- -.. automodule:: pyface.tasks.action.task_action_controller - :members: - :undoc-members: - :show-inheritance: +.. toctree:: -:mod:`task_action_manager_builder` Module ------------------------------------------ - -.. automodule:: pyface.tasks.action.task_action_manager_builder - :members: - :undoc-members: - :show-inheritance: - -:mod:`task_toggle_group` Module -------------------------------- - -.. automodule:: pyface.tasks.action.task_toggle_group - :members: - :undoc-members: - :show-inheritance: + pyface.tasks.action.api + pyface.tasks.action.dock_pane_toggle_group + pyface.tasks.action.listening_action + pyface.tasks.action.schema + pyface.tasks.action.schema_addition + pyface.tasks.action.task_action + pyface.tasks.action.task_action_controller + pyface.tasks.action.task_action_manager_builder + pyface.tasks.action.task_toggle_group + pyface.tasks.action.task_window_toggle_group + pyface.tasks.action.tasks_application_action diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.action.schema_addition.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.action.schema_addition.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.action.schema_addition.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.action.schema_addition.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.action.schema\_addition module +=========================================== + +.. automodule:: pyface.tasks.action.schema_addition + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.action.schema.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.action.schema.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.action.schema.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.action.schema.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.action.schema module +================================= + +.. automodule:: pyface.tasks.action.schema + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.action.task_action_controller.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.action.task_action_controller.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.action.task_action_controller.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.action.task_action_controller.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.action.task\_action\_controller module +=================================================== + +.. automodule:: pyface.tasks.action.task_action_controller + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.action.task_action_manager_builder.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.action.task_action_manager_builder.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.action.task_action_manager_builder.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.action.task_action_manager_builder.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.action.task\_action\_manager\_builder module +========================================================= + +.. automodule:: pyface.tasks.action.task_action_manager_builder + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.action.task_action.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.action.task_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.action.task_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.action.task_action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.action.task\_action module +======================================= + +.. automodule:: pyface.tasks.action.task_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.action.tasks_application_action.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.action.tasks_application_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.action.tasks_application_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.action.tasks_application_action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.action.tasks\_application\_action module +===================================================== + +.. automodule:: pyface.tasks.action.tasks_application_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.action.task_toggle_group.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.action.task_toggle_group.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.action.task_toggle_group.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.action.task_toggle_group.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.action.task\_toggle\_group module +============================================== + +.. automodule:: pyface.tasks.action.task_toggle_group + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.action.task_window_toggle_group.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.action.task_window_toggle_group.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.action.task_window_toggle_group.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.action.task_window_toggle_group.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.action.task\_window\_toggle\_group module +====================================================== + +.. automodule:: pyface.tasks.action.task_window_toggle_group + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.advanced_editor_area_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.advanced_editor_area_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.advanced_editor_area_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.advanced_editor_area_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.advanced\_editor\_area\_pane module +================================================ + +.. automodule:: pyface.tasks.advanced_editor_area_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.api.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.api.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.api module +======================= + +.. automodule:: pyface.tasks.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.contrib.python_shell.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.contrib.python_shell.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.contrib.python_shell.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.contrib.python_shell.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.contrib.python\_shell module +========================================= + +.. automodule:: pyface.tasks.contrib.python_shell + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.contrib.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.contrib.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.contrib.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.contrib.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,11 +1,15 @@ -contrib Package -=============== +pyface.tasks.contrib package +============================ -:mod:`python_shell` Module --------------------------- - -.. automodule:: pyface.tasks.contrib.python_shell +.. automodule:: pyface.tasks.contrib :members: :undoc-members: :show-inheritance: +Submodules +---------- + +.. toctree:: + + pyface.tasks.contrib.python_shell + diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.dock_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.dock_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.dock_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.dock_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.dock\_pane module +============================== + +.. automodule:: pyface.tasks.dock_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.editor_area_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.editor_area_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.editor_area_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.editor_area_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.editor\_area\_pane module +====================================== + +.. automodule:: pyface.tasks.editor_area_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.editor.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.editor.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.editor.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.editor.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.editor module +========================== + +.. automodule:: pyface.tasks.editor + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.enaml_dock_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.enaml_dock_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.enaml_dock_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.enaml_dock_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.enaml\_dock\_pane module +===================================== + +.. automodule:: pyface.tasks.enaml_dock_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.enaml_editor.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.enaml_editor.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.enaml_editor.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.enaml_editor.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.enaml\_editor module +================================= + +.. automodule:: pyface.tasks.enaml_editor + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.enaml_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.enaml_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.enaml_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.enaml_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.enaml\_pane module +=============================== + +.. automodule:: pyface.tasks.enaml_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.enaml_task_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.enaml_task_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.enaml_task_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.enaml_task_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.enaml\_task\_pane module +===================================== + +.. automodule:: pyface.tasks.enaml_task_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.i_advanced_editor_area_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.i_advanced_editor_area_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.i_advanced_editor_area_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.i_advanced_editor_area_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.i\_advanced\_editor\_area\_pane module +=================================================== + +.. automodule:: pyface.tasks.i_advanced_editor_area_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.i_dock_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.i_dock_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.i_dock_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.i_dock_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.i\_dock\_pane module +================================= + +.. automodule:: pyface.tasks.i_dock_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.i_editor_area_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.i_editor_area_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.i_editor_area_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.i_editor_area_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.i\_editor\_area\_pane module +========================================= + +.. automodule:: pyface.tasks.i_editor_area_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.i_editor.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.i_editor.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.i_editor.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.i_editor.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.i\_editor module +============================= + +.. automodule:: pyface.tasks.i_editor + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.i_task_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.i_task_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.i_task_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.i_task_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.i\_task\_pane module +================================= + +.. automodule:: pyface.tasks.i_task_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.i_task_window_backend.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.i_task_window_backend.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.i_task_window_backend.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.i_task_window_backend.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.i\_task\_window\_backend module +============================================ + +.. automodule:: pyface.tasks.i_task_window_backend + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,210 +1,7 @@ -tasks Package -============= +pyface.tasks package +==================== -:mod:`advanced_editor_area_pane` Module ---------------------------------------- - -.. automodule:: pyface.tasks.advanced_editor_area_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`api` Module ------------------ - -.. automodule:: pyface.tasks.api - :members: - :undoc-members: - :show-inheritance: - -:mod:`dock_pane` Module ------------------------ - -.. automodule:: pyface.tasks.dock_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`editor` Module --------------------- - -.. automodule:: pyface.tasks.editor - :members: - :undoc-members: - :show-inheritance: - -:mod:`editor_area_pane` Module ------------------------------- - -.. automodule:: pyface.tasks.editor_area_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`enaml_dock_pane` Module ------------------------------ - -.. automodule:: pyface.tasks.enaml_dock_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`enaml_editor` Module --------------------------- - -.. automodule:: pyface.tasks.enaml_editor - :members: - :undoc-members: - :show-inheritance: - -:mod:`enaml_pane` Module ------------------------- - -.. automodule:: pyface.tasks.enaml_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`enaml_task_pane` Module ------------------------------ - -.. automodule:: pyface.tasks.enaml_task_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_advanced_editor_area_pane` Module ------------------------------------------ - -.. automodule:: pyface.tasks.i_advanced_editor_area_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_dock_pane` Module -------------------------- - -.. automodule:: pyface.tasks.i_dock_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_editor` Module ----------------------- - -.. automodule:: pyface.tasks.i_editor - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_editor_area_pane` Module --------------------------------- - -.. automodule:: pyface.tasks.i_editor_area_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_task_pane` Module -------------------------- - -.. automodule:: pyface.tasks.i_task_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_task_window_backend` Module ------------------------------------ - -.. automodule:: pyface.tasks.i_task_window_backend - :members: - :undoc-members: - :show-inheritance: - -:mod:`split_editor_area_pane` Module ------------------------------------- - -.. automodule:: pyface.tasks.split_editor_area_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`task` Module ------------------- - -.. automodule:: pyface.tasks.task - :members: - :undoc-members: - :show-inheritance: - -:mod:`task_layout` Module -------------------------- - -.. automodule:: pyface.tasks.task_layout - :members: - :undoc-members: - :show-inheritance: - -:mod:`task_pane` Module ------------------------ - -.. automodule:: pyface.tasks.task_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`task_window` Module -------------------------- - -.. automodule:: pyface.tasks.task_window - :members: - :undoc-members: - :show-inheritance: - -:mod:`task_window_backend` Module ---------------------------------- - -.. automodule:: pyface.tasks.task_window_backend - :members: - :undoc-members: - :show-inheritance: - -:mod:`task_window_layout` Module --------------------------------- - -.. automodule:: pyface.tasks.task_window_layout - :members: - :undoc-members: - :show-inheritance: - -:mod:`topological_sort` Module ------------------------------- - -.. automodule:: pyface.tasks.topological_sort - :members: - :undoc-members: - :show-inheritance: - -:mod:`traits_dock_pane` Module ------------------------------- - -.. automodule:: pyface.tasks.traits_dock_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`traits_editor` Module ---------------------------- - -.. automodule:: pyface.tasks.traits_editor - :members: - :undoc-members: - :show-inheritance: - -:mod:`traits_task_pane` Module ------------------------------- - -.. automodule:: pyface.tasks.traits_task_pane +.. automodule:: pyface.tasks :members: :undoc-members: :show-inheritance: @@ -216,4 +13,38 @@ pyface.tasks.action pyface.tasks.contrib + pyface.tasks.tests + +Submodules +---------- + +.. toctree:: + + pyface.tasks.advanced_editor_area_pane + pyface.tasks.api + pyface.tasks.dock_pane + pyface.tasks.editor + pyface.tasks.editor_area_pane + pyface.tasks.enaml_dock_pane + pyface.tasks.enaml_editor + pyface.tasks.enaml_pane + pyface.tasks.enaml_task_pane + pyface.tasks.i_advanced_editor_area_pane + pyface.tasks.i_dock_pane + pyface.tasks.i_editor + pyface.tasks.i_editor_area_pane + pyface.tasks.i_task_pane + pyface.tasks.i_task_window_backend + pyface.tasks.split_editor_area_pane + pyface.tasks.task + pyface.tasks.task_layout + pyface.tasks.task_pane + pyface.tasks.task_window + pyface.tasks.task_window_backend + pyface.tasks.task_window_layout + pyface.tasks.tasks_application + pyface.tasks.topological_sort + pyface.tasks.traits_dock_pane + pyface.tasks.traits_editor + pyface.tasks.traits_task_pane diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.split_editor_area_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.split_editor_area_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.split_editor_area_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.split_editor_area_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.split\_editor\_area\_pane module +============================================= + +.. automodule:: pyface.tasks.split_editor_area_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.task_layout.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.task_layout.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.task_layout.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.task_layout.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.task\_layout module +================================ + +.. automodule:: pyface.tasks.task_layout + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.task_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.task_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.task_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.task_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.task\_pane module +============================== + +.. automodule:: pyface.tasks.task_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.task.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.task.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.task.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.task.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.task module +======================== + +.. automodule:: pyface.tasks.task + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.tasks_application.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.tasks_application.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.tasks_application.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.tasks_application.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.tasks\_application module +====================================== + +.. automodule:: pyface.tasks.tasks_application + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.task_window_backend.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.task_window_backend.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.task_window_backend.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.task_window_backend.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.task\_window\_backend module +========================================= + +.. automodule:: pyface.tasks.task_window_backend + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.task_window_layout.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.task_window_layout.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.task_window_layout.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.task_window_layout.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.task\_window\_layout module +======================================== + +.. automodule:: pyface.tasks.task_window_layout + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.task_window.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.task_window.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.task_window.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.task_window.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.task\_window module +================================ + +.. automodule:: pyface.tasks.task_window + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,24 @@ +pyface.tasks.tests package +========================== + +.. automodule:: pyface.tasks.tests + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + + pyface.tasks.tests.test_action_manager_builder + pyface.tasks.tests.test_dock_pane_toggle_group + pyface.tasks.tests.test_editor_area_pane + pyface.tasks.tests.test_enaml_dock_pane + pyface.tasks.tests.test_enaml_editor + pyface.tasks.tests.test_enaml_task_pane + pyface.tasks.tests.test_task_layout + pyface.tasks.tests.test_task_window + pyface.tasks.tests.test_tasks_application + pyface.tasks.tests.test_topological_sort + diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_action_manager_builder.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_action_manager_builder.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_action_manager_builder.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_action_manager_builder.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.tests.test\_action\_manager\_builder module +======================================================== + +.. automodule:: pyface.tasks.tests.test_action_manager_builder + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_dock_pane_toggle_group.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_dock_pane_toggle_group.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_dock_pane_toggle_group.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_dock_pane_toggle_group.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.tests.test\_dock\_pane\_toggle\_group module +========================================================= + +.. automodule:: pyface.tasks.tests.test_dock_pane_toggle_group + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_editor_area_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_editor_area_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_editor_area_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_editor_area_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.tests.test\_editor\_area\_pane module +================================================== + +.. automodule:: pyface.tasks.tests.test_editor_area_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_enaml_dock_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_enaml_dock_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_enaml_dock_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_enaml_dock_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.tests.test\_enaml\_dock\_pane module +================================================= + +.. automodule:: pyface.tasks.tests.test_enaml_dock_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_enaml_editor.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_enaml_editor.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_enaml_editor.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_enaml_editor.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.tests.test\_enaml\_editor module +============================================= + +.. automodule:: pyface.tasks.tests.test_enaml_editor + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_enaml_task_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_enaml_task_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_enaml_task_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_enaml_task_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.tests.test\_enaml\_task\_pane module +================================================= + +.. automodule:: pyface.tasks.tests.test_enaml_task_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_task_layout.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_task_layout.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_task_layout.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_task_layout.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.tests.test\_task\_layout module +============================================ + +.. automodule:: pyface.tasks.tests.test_task_layout + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_tasks_application.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_tasks_application.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_tasks_application.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_tasks_application.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.tests.test\_tasks\_application module +================================================== + +.. automodule:: pyface.tasks.tests.test_tasks_application + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_task_window.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_task_window.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_task_window.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_task_window.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.tests.test\_task\_window module +============================================ + +.. automodule:: pyface.tasks.tests.test_task_window + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_topological_sort.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_topological_sort.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.tests.test_topological_sort.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.tests.test_topological_sort.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.tests.test\_topological\_sort module +================================================= + +.. automodule:: pyface.tasks.tests.test_topological_sort + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.topological_sort.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.topological_sort.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.topological_sort.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.topological_sort.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.topological\_sort module +===================================== + +.. automodule:: pyface.tasks.topological_sort + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.traits_dock_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.traits_dock_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.traits_dock_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.traits_dock_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.traits\_dock\_pane module +====================================== + +.. automodule:: pyface.tasks.traits_dock_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.traits_editor.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.traits_editor.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.traits_editor.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.traits_editor.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.traits\_editor module +================================== + +.. automodule:: pyface.tasks.traits_editor + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tasks.traits_task_pane.rst python-pyface-6.1.2/docs/source/api/pyface.tasks.traits_task_pane.rst --- python-pyface-4.5.2/docs/source/api/pyface.tasks.traits_task_pane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tasks.traits_task_pane.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tasks.traits\_task\_pane module +====================================== + +.. automodule:: pyface.tasks.traits_task_pane + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.python_shell_script.rst python-pyface-6.1.2/docs/source/api/pyface.tests.python_shell_script.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.python_shell_script.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.python_shell_script.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.python\_shell\_script module +========================================= + +.. automodule:: pyface.tests.python_shell_script + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.rst python-pyface-6.1.2/docs/source/api/pyface.tests.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,11 +1,52 @@ -tests Package -============= +pyface.tests package +==================== -:mod:`test_splash_screen_log_handler` Module --------------------------------------------- - -.. automodule:: pyface.tests.test_splash_screen_log_handler +.. automodule:: pyface.tests :members: :undoc-members: :show-inheritance: +Subpackages +----------- + +.. toctree:: + + pyface.tests.test_new_toolkit + +Submodules +---------- + +.. toctree:: + + pyface.tests.python_shell_script + pyface.tests.test_about_dialog + pyface.tests.test_application + pyface.tests.test_application_window + pyface.tests.test_base_toolkit + pyface.tests.test_beep + pyface.tests.test_clipboard + pyface.tests.test_confirmation_dialog + pyface.tests.test_dialog + pyface.tests.test_directory_dialog + pyface.tests.test_file_dialog + pyface.tests.test_gui_application + pyface.tests.test_heading_text + pyface.tests.test_image_cache + pyface.tests.test_image_resource + pyface.tests.test_message_dialog + pyface.tests.test_progress_dialog + pyface.tests.test_python_editor + pyface.tests.test_python_shell + pyface.tests.test_resource_manager + pyface.tests.test_single_choice_dialog + pyface.tests.test_splash_screen + pyface.tests.test_splash_screen_log_handler + pyface.tests.test_split_application_window + pyface.tests.test_split_dialog + pyface.tests.test_split_panel + pyface.tests.test_system_metrics + pyface.tests.test_toolkit + pyface.tests.test_ui_traits + pyface.tests.test_widget + pyface.tests.test_window + diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_about_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_about_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_about_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_about_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_about\_dialog module +======================================= + +.. automodule:: pyface.tests.test_about_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_application.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_application.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_application.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_application.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_application module +===================================== + +.. automodule:: pyface.tests.test_application + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_application_window.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_application_window.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_application_window.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_application_window.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_application\_window module +============================================= + +.. automodule:: pyface.tests.test_application_window + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_base_toolkit.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_base_toolkit.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_base_toolkit.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_base_toolkit.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_base\_toolkit module +======================================= + +.. automodule:: pyface.tests.test_base_toolkit + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_beep.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_beep.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_beep.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_beep.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_beep module +============================== + +.. automodule:: pyface.tests.test_beep + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_clipboard.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_clipboard.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_clipboard.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_clipboard.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_clipboard module +=================================== + +.. automodule:: pyface.tests.test_clipboard + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_confirmation_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_confirmation_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_confirmation_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_confirmation_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_confirmation\_dialog module +============================================== + +.. automodule:: pyface.tests.test_confirmation_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_dialog module +================================ + +.. automodule:: pyface.tests.test_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_directory_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_directory_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_directory_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_directory_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_directory\_dialog module +=========================================== + +.. automodule:: pyface.tests.test_directory_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_file_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_file_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_file_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_file_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_file\_dialog module +====================================== + +.. automodule:: pyface.tests.test_file_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_gui_application.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_gui_application.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_gui_application.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_gui_application.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_gui\_application module +========================================== + +.. automodule:: pyface.tests.test_gui_application + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_heading_text.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_heading_text.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_heading_text.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_heading_text.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_heading\_text module +======================================= + +.. automodule:: pyface.tests.test_heading_text + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_image_cache.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_image_cache.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_image_cache.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_image_cache.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_image\_cache module +====================================== + +.. automodule:: pyface.tests.test_image_cache + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_image_resource.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_image_resource.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_image_resource.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_image_resource.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_image\_resource module +========================================= + +.. automodule:: pyface.tests.test_image_resource + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_message_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_message_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_message_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_message_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_message\_dialog module +========================================= + +.. automodule:: pyface.tests.test_message_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_new_toolkit.init.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_new_toolkit.init.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_new_toolkit.init.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_new_toolkit.init.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_new\_toolkit.init module +=========================================== + +.. automodule:: pyface.tests.test_new_toolkit.init + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_new_toolkit.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_new_toolkit.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_new_toolkit.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_new_toolkit.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,16 @@ +pyface.tests.test\_new\_toolkit package +======================================= + +.. automodule:: pyface.tests.test_new_toolkit + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + + pyface.tests.test_new_toolkit.init + pyface.tests.test_new_toolkit.widget + diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_new_toolkit.widget.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_new_toolkit.widget.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_new_toolkit.widget.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_new_toolkit.widget.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_new\_toolkit.widget module +============================================= + +.. automodule:: pyface.tests.test_new_toolkit.widget + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_progress_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_progress_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_progress_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_progress_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_progress\_dialog module +========================================== + +.. automodule:: pyface.tests.test_progress_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_python_editor.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_python_editor.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_python_editor.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_python_editor.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_python\_editor module +======================================== + +.. automodule:: pyface.tests.test_python_editor + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_python_shell.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_python_shell.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_python_shell.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_python_shell.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_python\_shell module +======================================= + +.. automodule:: pyface.tests.test_python_shell + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_resource_manager.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_resource_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_resource_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_resource_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_resource\_manager module +=========================================== + +.. automodule:: pyface.tests.test_resource_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_single_choice_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_single_choice_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_single_choice_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_single_choice_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_single\_choice\_dialog module +================================================ + +.. automodule:: pyface.tests.test_single_choice_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_splash_screen_log_handler.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_splash_screen_log_handler.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_splash_screen_log_handler.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_splash_screen_log_handler.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_splash\_screen\_log\_handler module +====================================================== + +.. automodule:: pyface.tests.test_splash_screen_log_handler + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_splash_screen.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_splash_screen.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_splash_screen.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_splash_screen.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_splash\_screen module +======================================== + +.. automodule:: pyface.tests.test_splash_screen + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_split_application_window.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_split_application_window.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_split_application_window.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_split_application_window.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_split\_application\_window module +==================================================== + +.. automodule:: pyface.tests.test_split_application_window + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_split_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_split_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_split_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_split_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_split\_dialog module +======================================= + +.. automodule:: pyface.tests.test_split_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_split_panel.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_split_panel.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_split_panel.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_split_panel.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_split\_panel module +====================================== + +.. automodule:: pyface.tests.test_split_panel + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_system_metrics.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_system_metrics.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_system_metrics.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_system_metrics.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_system\_metrics module +========================================= + +.. automodule:: pyface.tests.test_system_metrics + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_toolkit.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_toolkit.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_toolkit.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_toolkit.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_toolkit module +================================= + +.. automodule:: pyface.tests.test_toolkit + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_ui_traits.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_ui_traits.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_ui_traits.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_ui_traits.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_ui\_traits module +==================================== + +.. automodule:: pyface.tests.test_ui_traits + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_widget.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_widget.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_widget.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_widget.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_widget module +================================ + +.. automodule:: pyface.tests.test_widget + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tests.test_window.rst python-pyface-6.1.2/docs/source/api/pyface.tests.test_window.rst --- python-pyface-4.5.2/docs/source/api/pyface.tests.test_window.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tests.test_window.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tests.test\_window module +================================ + +.. automodule:: pyface.tests.test_window + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.timer.api.rst python-pyface-6.1.2/docs/source/api/pyface.timer.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.timer.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.timer.api.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.timer.api module +======================= + +.. automodule:: pyface.timer.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.timer.do_later.rst python-pyface-6.1.2/docs/source/api/pyface.timer.do_later.rst --- python-pyface-4.5.2/docs/source/api/pyface.timer.do_later.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.timer.do_later.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.timer.do\_later module +============================= + +.. automodule:: pyface.timer.do_later + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.timer.i_timer.rst python-pyface-6.1.2/docs/source/api/pyface.timer.i_timer.rst --- python-pyface-4.5.2/docs/source/api/pyface.timer.i_timer.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.timer.i_timer.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.timer.i\_timer module +============================ + +.. automodule:: pyface.timer.i_timer + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.timer.rst python-pyface-6.1.2/docs/source/api/pyface.timer.rst --- python-pyface-4.5.2/docs/source/api/pyface.timer.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.timer.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,27 +1,25 @@ -timer Package -============= +pyface.timer package +==================== -:mod:`api` Module ------------------ - -.. automodule:: pyface.timer.api +.. automodule:: pyface.timer :members: :undoc-members: :show-inheritance: -:mod:`do_later` Module ----------------------- +Subpackages +----------- -.. automodule:: pyface.timer.do_later - :members: - :undoc-members: - :show-inheritance: +.. toctree:: -:mod:`timer` Module -------------------- + pyface.timer.tests -.. automodule:: pyface.timer.timer - :members: - :undoc-members: - :show-inheritance: +Submodules +---------- + +.. toctree:: + + pyface.timer.api + pyface.timer.do_later + pyface.timer.i_timer + pyface.timer.timer diff -Nru python-pyface-4.5.2/docs/source/api/pyface.timer.tests.rst python-pyface-6.1.2/docs/source/api/pyface.timer.tests.rst --- python-pyface-4.5.2/docs/source/api/pyface.timer.tests.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.timer.tests.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,15 @@ +pyface.timer.tests package +========================== + +.. automodule:: pyface.timer.tests + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + + pyface.timer.tests.test_timer + diff -Nru python-pyface-4.5.2/docs/source/api/pyface.timer.tests.test_timer.rst python-pyface-6.1.2/docs/source/api/pyface.timer.tests.test_timer.rst --- python-pyface-4.5.2/docs/source/api/pyface.timer.tests.test_timer.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.timer.tests.test_timer.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.timer.tests.test\_timer module +===================================== + +.. automodule:: pyface.timer.tests.test_timer + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.timer.timer.rst python-pyface-6.1.2/docs/source/api/pyface.timer.timer.rst --- python-pyface-4.5.2/docs/source/api/pyface.timer.timer.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.timer.timer.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.timer.timer module +========================= + +.. automodule:: pyface.timer.timer + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.toolkit.rst python-pyface-6.1.2/docs/source/api/pyface.toolkit.rst --- python-pyface-4.5.2/docs/source/api/pyface.toolkit.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.toolkit.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.toolkit module +===================== + +.. automodule:: pyface.toolkit + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tree.api.rst python-pyface-6.1.2/docs/source/api/pyface.tree.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.tree.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tree.api.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tree.api module +====================== + +.. automodule:: pyface.tree.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tree.node_event.rst python-pyface-6.1.2/docs/source/api/pyface.tree.node_event.rst --- python-pyface-4.5.2/docs/source/api/pyface.tree.node_event.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tree.node_event.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tree.node\_event module +============================== + +.. automodule:: pyface.tree.node_event + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tree.node_manager.rst python-pyface-6.1.2/docs/source/api/pyface.tree.node_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.tree.node_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tree.node_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tree.node\_manager module +================================ + +.. automodule:: pyface.tree.node_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tree.node_monitor.rst python-pyface-6.1.2/docs/source/api/pyface.tree.node_monitor.rst --- python-pyface-4.5.2/docs/source/api/pyface.tree.node_monitor.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tree.node_monitor.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tree.node\_monitor module +================================ + +.. automodule:: pyface.tree.node_monitor + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tree.node_tree_model.rst python-pyface-6.1.2/docs/source/api/pyface.tree.node_tree_model.rst --- python-pyface-4.5.2/docs/source/api/pyface.tree.node_tree_model.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tree.node_tree_model.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tree.node\_tree\_model module +==================================== + +.. automodule:: pyface.tree.node_tree_model + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tree.node_tree.rst python-pyface-6.1.2/docs/source/api/pyface.tree.node_tree.rst --- python-pyface-4.5.2/docs/source/api/pyface.tree.node_tree.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tree.node_tree.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tree.node\_tree module +============================= + +.. automodule:: pyface.tree.node_tree + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tree.node_type.rst python-pyface-6.1.2/docs/source/api/pyface.tree.node_type.rst --- python-pyface-4.5.2/docs/source/api/pyface.tree.node_type.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tree.node_type.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tree.node\_type module +============================= + +.. automodule:: pyface.tree.node_type + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tree.rst python-pyface-6.1.2/docs/source/api/pyface.tree.rst --- python-pyface-4.5.2/docs/source/api/pyface.tree.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tree.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,91 +1,25 @@ -tree Package -============ +pyface.tree package +=================== -:mod:`api` Module ------------------ - -.. automodule:: pyface.tree.api - :members: - :undoc-members: - :show-inheritance: - -:mod:`node_event` Module ------------------------- - -.. automodule:: pyface.tree.node_event - :members: - :undoc-members: - :show-inheritance: - -:mod:`node_manager` Module --------------------------- - -.. automodule:: pyface.tree.node_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`node_monitor` Module --------------------------- - -.. automodule:: pyface.tree.node_monitor - :members: - :undoc-members: - :show-inheritance: - -:mod:`node_tree` Module ------------------------ - -.. automodule:: pyface.tree.node_tree - :members: - :undoc-members: - :show-inheritance: - -:mod:`node_tree_model` Module ------------------------------ - -.. automodule:: pyface.tree.node_tree_model - :members: - :undoc-members: - :show-inheritance: - -:mod:`node_type` Module ------------------------ - -.. automodule:: pyface.tree.node_type - :members: - :undoc-members: - :show-inheritance: - -:mod:`trait_dict_node_type` Module ----------------------------------- - -.. automodule:: pyface.tree.trait_dict_node_type +.. automodule:: pyface.tree :members: :undoc-members: :show-inheritance: -:mod:`trait_list_node_type` Module ----------------------------------- +Submodules +---------- -.. automodule:: pyface.tree.trait_list_node_type - :members: - :undoc-members: - :show-inheritance: - -:mod:`tree` Module ------------------- - -.. automodule:: pyface.tree.tree - :members: - :undoc-members: - :show-inheritance: - -:mod:`tree_model` Module ------------------------- +.. toctree:: -.. automodule:: pyface.tree.tree_model - :members: - :undoc-members: - :show-inheritance: + pyface.tree.api + pyface.tree.node_event + pyface.tree.node_manager + pyface.tree.node_monitor + pyface.tree.node_tree + pyface.tree.node_tree_model + pyface.tree.node_type + pyface.tree.trait_dict_node_type + pyface.tree.trait_list_node_type + pyface.tree.tree + pyface.tree.tree_model diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tree.trait_dict_node_type.rst python-pyface-6.1.2/docs/source/api/pyface.tree.trait_dict_node_type.rst --- python-pyface-4.5.2/docs/source/api/pyface.tree.trait_dict_node_type.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tree.trait_dict_node_type.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tree.trait\_dict\_node\_type module +========================================== + +.. automodule:: pyface.tree.trait_dict_node_type + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tree.trait_list_node_type.rst python-pyface-6.1.2/docs/source/api/pyface.tree.trait_list_node_type.rst --- python-pyface-4.5.2/docs/source/api/pyface.tree.trait_list_node_type.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tree.trait_list_node_type.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tree.trait\_list\_node\_type module +========================================== + +.. automodule:: pyface.tree.trait_list_node_type + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tree.tree_model.rst python-pyface-6.1.2/docs/source/api/pyface.tree.tree_model.rst --- python-pyface-4.5.2/docs/source/api/pyface.tree.tree_model.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tree.tree_model.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tree.tree\_model module +============================== + +.. automodule:: pyface.tree.tree_model + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.tree.tree.rst python-pyface-6.1.2/docs/source/api/pyface.tree.tree.rst --- python-pyface-4.5.2/docs/source/api/pyface.tree.tree.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.tree.tree.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.tree.tree module +======================= + +.. automodule:: pyface.tree.tree + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.null.action.rst python-pyface-6.1.2/docs/source/api/pyface.ui.null.action.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.null.action.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.null.action.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -action Package -============== - -:mod:`action` Package ---------------------- - -.. automodule:: pyface.ui.null.action - :members: - :undoc-members: - :show-inheritance: - -:mod:`action_item` Module -------------------------- - -.. automodule:: pyface.ui.null.action.action_item - :members: - :undoc-members: - :show-inheritance: - -:mod:`menu_bar_manager` Module ------------------------------- - -.. automodule:: pyface.ui.null.action.menu_bar_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`menu_manager` Module --------------------------- - -.. automodule:: pyface.ui.null.action.menu_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`status_bar_manager` Module --------------------------------- - -.. automodule:: pyface.ui.null.action.status_bar_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`tool_bar_manager` Module ------------------------------- - -.. automodule:: pyface.ui.null.action.tool_bar_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`tool_palette` Module --------------------------- - -.. automodule:: pyface.ui.null.action.tool_palette - :members: - :undoc-members: - :show-inheritance: - -:mod:`tool_palette_manager` Module ----------------------------------- - -.. automodule:: pyface.ui.null.action.tool_palette_manager - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.null.rst python-pyface-6.1.2/docs/source/api/pyface.ui.null.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.null.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.null.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -null Package -============ - -:mod:`clipboard` Module ------------------------ - -.. automodule:: pyface.ui.null.clipboard - :members: - :undoc-members: - :show-inheritance: - -:mod:`image_resource` Module ----------------------------- - -.. automodule:: pyface.ui.null.image_resource - :members: - :undoc-members: - :show-inheritance: - -:mod:`init` Module ------------------- - -.. automodule:: pyface.ui.null.init - :members: - :undoc-members: - :show-inheritance: - -:mod:`resource_manager` Module ------------------------------- - -.. automodule:: pyface.ui.null.resource_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`widget` Module --------------------- - -.. automodule:: pyface.ui.null.widget - :members: - :undoc-members: - :show-inheritance: - -:mod:`window` Module --------------------- - -.. automodule:: pyface.ui.null.window - :members: - :undoc-members: - :show-inheritance: - -Subpackages ------------ - -.. toctree:: - - pyface.ui.null.action - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.action.rst python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.action.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.action.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.action.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -action Package -============== - -:mod:`action` Package ---------------------- - -.. automodule:: pyface.ui.qt4.action - :members: - :undoc-members: - :show-inheritance: - -:mod:`action_item` Module -------------------------- - -.. automodule:: pyface.ui.qt4.action.action_item - :members: - :undoc-members: - :show-inheritance: - -:mod:`menu_bar_manager` Module ------------------------------- - -.. automodule:: pyface.ui.qt4.action.menu_bar_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`menu_manager` Module --------------------------- - -.. automodule:: pyface.ui.qt4.action.menu_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`status_bar_manager` Module --------------------------------- - -.. automodule:: pyface.ui.qt4.action.status_bar_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`tool_bar_manager` Module ------------------------------- - -.. automodule:: pyface.ui.qt4.action.tool_bar_manager - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.code_editor.rst python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.code_editor.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.code_editor.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.code_editor.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -code_editor Package -=================== - -:mod:`code_editor` Package --------------------------- - -.. automodule:: pyface.ui.qt4.code_editor - :members: - :undoc-members: - :show-inheritance: - -:mod:`code_widget` Module -------------------------- - -.. automodule:: pyface.ui.qt4.code_editor.code_widget - :members: - :undoc-members: - :show-inheritance: - -:mod:`find_widget` Module -------------------------- - -.. automodule:: pyface.ui.qt4.code_editor.find_widget - :members: - :undoc-members: - :show-inheritance: - -:mod:`gutters` Module ---------------------- - -.. automodule:: pyface.ui.qt4.code_editor.gutters - :members: - :undoc-members: - :show-inheritance: - -:mod:`pygments_highlighter` Module ----------------------------------- - -.. automodule:: pyface.ui.qt4.code_editor.pygments_highlighter - :members: - :undoc-members: - :show-inheritance: - -:mod:`replace_widget` Module ----------------------------- - -.. automodule:: pyface.ui.qt4.code_editor.replace_widget - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.console.rst python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.console.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.console.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.console.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -console Package -=============== - -:mod:`api` Module ------------------ - -.. automodule:: pyface.ui.qt4.console.api - :members: - :undoc-members: - :show-inheritance: - -:mod:`bracket_matcher` Module ------------------------------ - -.. automodule:: pyface.ui.qt4.console.bracket_matcher - :members: - :undoc-members: - :show-inheritance: - -:mod:`call_tip_widget` Module ------------------------------ - -.. automodule:: pyface.ui.qt4.console.call_tip_widget - :members: - :undoc-members: - :show-inheritance: - -:mod:`completion_lexer` Module ------------------------------- - -.. automodule:: pyface.ui.qt4.console.completion_lexer - :members: - :undoc-members: - :show-inheritance: - -:mod:`console_widget` Module ----------------------------- - -.. automodule:: pyface.ui.qt4.console.console_widget - :members: - :undoc-members: - :show-inheritance: - -:mod:`history_console_widget` Module ------------------------------------- - -.. automodule:: pyface.ui.qt4.console.history_console_widget - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.rst python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,209 +0,0 @@ -qt4 Package -=========== - -:mod:`qt4` Package ------------------- - -.. automodule:: pyface.ui.qt4 - :members: - :undoc-members: - :show-inheritance: - -:mod:`about_dialog` Module --------------------------- - -.. automodule:: pyface.ui.qt4.about_dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`application_window` Module --------------------------------- - -.. automodule:: pyface.ui.qt4.application_window - :members: - :undoc-members: - :show-inheritance: - -:mod:`beep` Module ------------------- - -.. automodule:: pyface.ui.qt4.beep - :members: - :undoc-members: - :show-inheritance: - -:mod:`clipboard` Module ------------------------ - -.. automodule:: pyface.ui.qt4.clipboard - :members: - :undoc-members: - :show-inheritance: - -:mod:`confirmation_dialog` Module ---------------------------------- - -.. automodule:: pyface.ui.qt4.confirmation_dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`dialog` Module --------------------- - -.. automodule:: pyface.ui.qt4.dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`directory_dialog` Module ------------------------------- - -.. automodule:: pyface.ui.qt4.directory_dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`file_dialog` Module -------------------------- - -.. automodule:: pyface.ui.qt4.file_dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`gui` Module ------------------ - -.. automodule:: pyface.ui.qt4.gui - :members: - :undoc-members: - :show-inheritance: - -:mod:`heading_text` Module --------------------------- - -.. automodule:: pyface.ui.qt4.heading_text - :members: - :undoc-members: - :show-inheritance: - -:mod:`image_cache` Module -------------------------- - -.. automodule:: pyface.ui.qt4.image_cache - :members: - :undoc-members: - :show-inheritance: - -:mod:`image_resource` Module ----------------------------- - -.. automodule:: pyface.ui.qt4.image_resource - :members: - :undoc-members: - :show-inheritance: - -:mod:`init` Module ------------------- - -.. automodule:: pyface.ui.qt4.init - :members: - :undoc-members: - :show-inheritance: - -:mod:`message_dialog` Module ----------------------------- - -.. automodule:: pyface.ui.qt4.message_dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`progress_dialog` Module ------------------------------ - -.. automodule:: pyface.ui.qt4.progress_dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`python_editor` Module ---------------------------- - -.. automodule:: pyface.ui.qt4.python_editor - :members: - :undoc-members: - :show-inheritance: - -:mod:`python_shell` Module --------------------------- - -.. automodule:: pyface.ui.qt4.python_shell - :members: - :undoc-members: - :show-inheritance: - -:mod:`resource_manager` Module ------------------------------- - -.. automodule:: pyface.ui.qt4.resource_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`splash_screen` Module ---------------------------- - -.. automodule:: pyface.ui.qt4.splash_screen - :members: - :undoc-members: - :show-inheritance: - -:mod:`split_widget` Module --------------------------- - -.. automodule:: pyface.ui.qt4.split_widget - :members: - :undoc-members: - :show-inheritance: - -:mod:`system_metrics` Module ----------------------------- - -.. automodule:: pyface.ui.qt4.system_metrics - :members: - :undoc-members: - :show-inheritance: - -:mod:`widget` Module --------------------- - -.. automodule:: pyface.ui.qt4.widget - :members: - :undoc-members: - :show-inheritance: - -:mod:`window` Module --------------------- - -.. automodule:: pyface.ui.qt4.window - :members: - :undoc-members: - :show-inheritance: - -Subpackages ------------ - -.. toctree:: - - pyface.ui.qt4.action - pyface.ui.qt4.code_editor - pyface.ui.qt4.console - pyface.ui.qt4.tasks - pyface.ui.qt4.timer - pyface.ui.qt4.util - pyface.ui.qt4.wizard - pyface.ui.qt4.workbench - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.tasks.rst python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.tasks.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.tasks.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.tasks.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -tasks Package -============= - -:mod:`advanced_editor_area_pane` Module ---------------------------------------- - -.. automodule:: pyface.ui.qt4.tasks.advanced_editor_area_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`dock_pane` Module ------------------------ - -.. automodule:: pyface.ui.qt4.tasks.dock_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`editor` Module --------------------- - -.. automodule:: pyface.ui.qt4.tasks.editor - :members: - :undoc-members: - :show-inheritance: - -:mod:`editor_area_pane` Module ------------------------------- - -.. automodule:: pyface.ui.qt4.tasks.editor_area_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`main_window_layout` Module --------------------------------- - -.. automodule:: pyface.ui.qt4.tasks.main_window_layout - :members: - :undoc-members: - :show-inheritance: - -:mod:`split_editor_area_pane` Module ------------------------------------- - -.. automodule:: pyface.ui.qt4.tasks.split_editor_area_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`task_pane` Module ------------------------ - -.. automodule:: pyface.ui.qt4.tasks.task_pane - :members: - :undoc-members: - :show-inheritance: - -:mod:`task_window_backend` Module ---------------------------------- - -.. automodule:: pyface.ui.qt4.tasks.task_window_backend - :members: - :undoc-members: - :show-inheritance: - -:mod:`util` Module ------------------- - -.. automodule:: pyface.ui.qt4.tasks.util - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.timer.rst python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.timer.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.timer.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.timer.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -timer Package -============= - -:mod:`timer` Package --------------------- - -.. automodule:: pyface.ui.qt4.timer - :members: - :undoc-members: - :show-inheritance: - -:mod:`do_later` Module ----------------------- - -.. automodule:: pyface.ui.qt4.timer.do_later - :members: - :undoc-members: - :show-inheritance: - -:mod:`timer` Module -------------------- - -.. automodule:: pyface.ui.qt4.timer.timer - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.util.rst python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.util.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.util.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.util.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -util Package -============ - -:mod:`testing` Module ---------------------- - -.. automodule:: pyface.ui.qt4.util.testing - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.wizard.rst python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.wizard.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.wizard.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.wizard.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -wizard Package -============== - -:mod:`wizard` Package ---------------------- - -.. automodule:: pyface.ui.qt4.wizard - :members: - :undoc-members: - :show-inheritance: - -:mod:`wizard` Module --------------------- - -.. automodule:: pyface.ui.qt4.wizard.wizard - :members: - :undoc-members: - :show-inheritance: - -:mod:`wizard_page` Module -------------------------- - -.. automodule:: pyface.ui.qt4.wizard.wizard_page - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.workbench.rst python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.workbench.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.qt4.workbench.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.qt4.workbench.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -workbench Package -================= - -:mod:`workbench` Package ------------------------- - -.. automodule:: pyface.ui.qt4.workbench - :members: - :undoc-members: - :show-inheritance: - -:mod:`editor` Module --------------------- - -.. automodule:: pyface.ui.qt4.workbench.editor - :members: - :undoc-members: - :show-inheritance: - -:mod:`split_tab_widget` Module ------------------------------- - -.. automodule:: pyface.ui.qt4.workbench.split_tab_widget - :members: - :undoc-members: - :show-inheritance: - -:mod:`view` Module ------------------- - -.. automodule:: pyface.ui.qt4.workbench.view - :members: - :undoc-members: - :show-inheritance: - -:mod:`workbench_window_layout` Module -------------------------------------- - -.. automodule:: pyface.ui.qt4.workbench.workbench_window_layout - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.rst python-pyface-6.1.2/docs/source/api/pyface.ui.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -ui Package -========== - -Subpackages ------------ - -.. toctree:: - - pyface.ui.null - pyface.ui.qt4 - pyface.ui.wx - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui_traits.rst python-pyface-6.1.2/docs/source/api/pyface.ui_traits.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui_traits.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui_traits.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.ui\_traits module +======================== + +.. automodule:: pyface.ui_traits + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.wx.action.rst python-pyface-6.1.2/docs/source/api/pyface.ui.wx.action.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.wx.action.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.wx.action.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -action Package -============== - -:mod:`action` Package ---------------------- - -.. automodule:: pyface.ui.wx.action - :members: - :undoc-members: - :show-inheritance: - -:mod:`action_item` Module -------------------------- - -.. automodule:: pyface.ui.wx.action.action_item - :members: - :undoc-members: - :show-inheritance: - -:mod:`menu_bar_manager` Module ------------------------------- - -.. automodule:: pyface.ui.wx.action.menu_bar_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`menu_manager` Module --------------------------- - -.. automodule:: pyface.ui.wx.action.menu_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`status_bar_manager` Module --------------------------------- - -.. automodule:: pyface.ui.wx.action.status_bar_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`tool_bar_manager` Module ------------------------------- - -.. automodule:: pyface.ui.wx.action.tool_bar_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`tool_palette` Module --------------------------- - -.. automodule:: pyface.ui.wx.action.tool_palette - :members: - :undoc-members: - :show-inheritance: - -:mod:`tool_palette_manager` Module ----------------------------------- - -.. automodule:: pyface.ui.wx.action.tool_palette_manager - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.wx.grid.rst python-pyface-6.1.2/docs/source/api/pyface.ui.wx.grid.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.wx.grid.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.wx.grid.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,139 +0,0 @@ -grid Package -============ - -:mod:`grid` Package -------------------- - -.. automodule:: pyface.ui.wx.grid - :members: - :undoc-members: - :show-inheritance: - -:mod:`api` Module ------------------ - -.. automodule:: pyface.ui.wx.grid.api - :members: - :undoc-members: - :show-inheritance: - -:mod:`checkbox_image_renderer` Module -------------------------------------- - -.. automodule:: pyface.ui.wx.grid.checkbox_image_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`checkbox_renderer` Module -------------------------------- - -.. automodule:: pyface.ui.wx.grid.checkbox_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`combobox_focus_handler` Module ------------------------------------- - -.. automodule:: pyface.ui.wx.grid.combobox_focus_handler - :members: - :undoc-members: - :show-inheritance: - -:mod:`composite_grid_model` Module ----------------------------------- - -.. automodule:: pyface.ui.wx.grid.composite_grid_model - :members: - :undoc-members: - :show-inheritance: - -:mod:`edit_image_renderer` Module ---------------------------------- - -.. automodule:: pyface.ui.wx.grid.edit_image_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`edit_renderer` Module ---------------------------- - -.. automodule:: pyface.ui.wx.grid.edit_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`grid` Module ------------------- - -.. automodule:: pyface.ui.wx.grid.grid - :members: - :undoc-members: - :show-inheritance: - -:mod:`grid_cell_image_renderer` Module --------------------------------------- - -.. automodule:: pyface.ui.wx.grid.grid_cell_image_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`grid_cell_renderer` Module --------------------------------- - -.. automodule:: pyface.ui.wx.grid.grid_cell_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`grid_model` Module ------------------------- - -.. automodule:: pyface.ui.wx.grid.grid_model - :members: - :undoc-members: - :show-inheritance: - -:mod:`inverted_grid_model` Module ---------------------------------- - -.. automodule:: pyface.ui.wx.grid.inverted_grid_model - :members: - :undoc-members: - :show-inheritance: - -:mod:`mapped_grid_cell_image_renderer` Module ---------------------------------------------- - -.. automodule:: pyface.ui.wx.grid.mapped_grid_cell_image_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`simple_grid_model` Module -------------------------------- - -.. automodule:: pyface.ui.wx.grid.simple_grid_model - :members: - :undoc-members: - :show-inheritance: - -:mod:`trait_grid_cell_adapter` Module -------------------------------------- - -.. automodule:: pyface.ui.wx.grid.trait_grid_cell_adapter - :members: - :undoc-members: - :show-inheritance: - -:mod:`trait_grid_model` Module ------------------------------- - -.. automodule:: pyface.ui.wx.grid.trait_grid_model - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.wx.rst python-pyface-6.1.2/docs/source/api/pyface.ui.wx.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.wx.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.wx.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,214 +0,0 @@ -wx Package -========== - -:mod:`wx` Package ------------------ - -.. automodule:: pyface.ui.wx - :members: - :undoc-members: - :show-inheritance: - -:mod:`about_dialog` Module --------------------------- - -.. automodule:: pyface.ui.wx.about_dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`application_window` Module --------------------------------- - -.. automodule:: pyface.ui.wx.application_window - :members: - :undoc-members: - :show-inheritance: - -:mod:`beep` Module ------------------- - -.. automodule:: pyface.ui.wx.beep - :members: - :undoc-members: - :show-inheritance: - -:mod:`clipboard` Module ------------------------ - -.. automodule:: pyface.ui.wx.clipboard - :members: - :undoc-members: - :show-inheritance: - -:mod:`confirmation_dialog` Module ---------------------------------- - -.. automodule:: pyface.ui.wx.confirmation_dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`dialog` Module --------------------- - -.. automodule:: pyface.ui.wx.dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`directory_dialog` Module ------------------------------- - -.. automodule:: pyface.ui.wx.directory_dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`file_dialog` Module -------------------------- - -.. automodule:: pyface.ui.wx.file_dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`gui` Module ------------------ - -.. automodule:: pyface.ui.wx.gui - :members: - :undoc-members: - :show-inheritance: - -:mod:`heading_text` Module --------------------------- - -.. automodule:: pyface.ui.wx.heading_text - :members: - :undoc-members: - :show-inheritance: - -:mod:`image_cache` Module -------------------------- - -.. automodule:: pyface.ui.wx.image_cache - :members: - :undoc-members: - :show-inheritance: - -:mod:`image_resource` Module ----------------------------- - -.. automodule:: pyface.ui.wx.image_resource - :members: - :undoc-members: - :show-inheritance: - -:mod:`init` Module ------------------- - -.. automodule:: pyface.ui.wx.init - :members: - :undoc-members: - :show-inheritance: - -:mod:`ipython_widget` Module ----------------------------- - -.. automodule:: pyface.ui.wx.ipython_widget - :members: - :undoc-members: - :show-inheritance: - -:mod:`message_dialog` Module ----------------------------- - -.. automodule:: pyface.ui.wx.message_dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`progress_dialog` Module ------------------------------ - -.. automodule:: pyface.ui.wx.progress_dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`python_editor` Module ---------------------------- - -.. automodule:: pyface.ui.wx.python_editor - :members: - :undoc-members: - :show-inheritance: - -:mod:`python_shell` Module --------------------------- - -.. automodule:: pyface.ui.wx.python_shell - :members: - :undoc-members: - :show-inheritance: - -:mod:`resource_manager` Module ------------------------------- - -.. automodule:: pyface.ui.wx.resource_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`splash_screen` Module ---------------------------- - -.. automodule:: pyface.ui.wx.splash_screen - :members: - :undoc-members: - :show-inheritance: - -:mod:`split_widget` Module --------------------------- - -.. automodule:: pyface.ui.wx.split_widget - :members: - :undoc-members: - :show-inheritance: - -:mod:`system_metrics` Module ----------------------------- - -.. automodule:: pyface.ui.wx.system_metrics - :members: - :undoc-members: - :show-inheritance: - -:mod:`widget` Module --------------------- - -.. automodule:: pyface.ui.wx.widget - :members: - :undoc-members: - :show-inheritance: - -:mod:`window` Module --------------------- - -.. automodule:: pyface.ui.wx.window - :members: - :undoc-members: - :show-inheritance: - -Subpackages ------------ - -.. toctree:: - - pyface.ui.wx.action - pyface.ui.wx.grid - pyface.ui.wx.timer - pyface.ui.wx.wizard - pyface.ui.wx.workbench - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.wx.timer.rst python-pyface-6.1.2/docs/source/api/pyface.ui.wx.timer.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.wx.timer.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.wx.timer.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -timer Package -============= - -:mod:`timer` Package --------------------- - -.. automodule:: pyface.ui.wx.timer - :members: - :undoc-members: - :show-inheritance: - -:mod:`do_later` Module ----------------------- - -.. automodule:: pyface.ui.wx.timer.do_later - :members: - :undoc-members: - :show-inheritance: - -:mod:`timer` Module -------------------- - -.. automodule:: pyface.ui.wx.timer.timer - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.wx.wizard.rst python-pyface-6.1.2/docs/source/api/pyface.ui.wx.wizard.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.wx.wizard.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.wx.wizard.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -wizard Package -============== - -:mod:`wizard` Package ---------------------- - -.. automodule:: pyface.ui.wx.wizard - :members: - :undoc-members: - :show-inheritance: - -:mod:`wizard` Module --------------------- - -.. automodule:: pyface.ui.wx.wizard.wizard - :members: - :undoc-members: - :show-inheritance: - -:mod:`wizard_page` Module -------------------------- - -.. automodule:: pyface.ui.wx.wizard.wizard_page - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.ui.wx.workbench.rst python-pyface-6.1.2/docs/source/api/pyface.ui.wx.workbench.rst --- python-pyface-4.5.2/docs/source/api/pyface.ui.wx.workbench.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.ui.wx.workbench.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -workbench Package -================= - -:mod:`workbench` Package ------------------------- - -.. automodule:: pyface.ui.wx.workbench - :members: - :undoc-members: - :show-inheritance: - -:mod:`editor` Module --------------------- - -.. automodule:: pyface.ui.wx.workbench.editor - :members: - :undoc-members: - :show-inheritance: - -:mod:`editor_set_structure_handler` Module ------------------------------------------- - -.. automodule:: pyface.ui.wx.workbench.editor_set_structure_handler - :members: - :undoc-members: - :show-inheritance: - -:mod:`view` Module ------------------- - -.. automodule:: pyface.ui.wx.workbench.view - :members: - :undoc-members: - :show-inheritance: - -:mod:`view_set_structure_handler` Module ----------------------------------------- - -.. automodule:: pyface.ui.wx.workbench.view_set_structure_handler - :members: - :undoc-members: - :show-inheritance: - -:mod:`workbench_dock_window` Module ------------------------------------ - -.. automodule:: pyface.ui.wx.workbench.workbench_dock_window - :members: - :undoc-members: - :show-inheritance: - -:mod:`workbench_window_layout` Module -------------------------------------- - -.. automodule:: pyface.ui.wx.workbench.workbench_window_layout - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.util.font_helper.rst python-pyface-6.1.2/docs/source/api/pyface.util.font_helper.rst --- python-pyface-4.5.2/docs/source/api/pyface.util.font_helper.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.util.font_helper.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.util.font\_helper module +=============================== + +.. automodule:: pyface.util.font_helper + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.util.grid.api.rst python-pyface-6.1.2/docs/source/api/pyface.util.grid.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.util.grid.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.util.grid.api.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.util.grid.api module +=========================== + +.. automodule:: pyface.util.grid.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.util.grid.grid_column.rst python-pyface-6.1.2/docs/source/api/pyface.util.grid.grid_column.rst --- python-pyface-4.5.2/docs/source/api/pyface.util.grid.grid_column.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.util.grid.grid_column.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.util.grid.grid\_column module +==================================== + +.. automodule:: pyface.util.grid.grid_column + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.util.grid.grid_model.rst python-pyface-6.1.2/docs/source/api/pyface.util.grid.grid_model.rst --- python-pyface-4.5.2/docs/source/api/pyface.util.grid.grid_model.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.util.grid.grid_model.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.util.grid.grid\_model module +=================================== + +.. automodule:: pyface.util.grid.grid_model + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.util.grid.grid_row.rst python-pyface-6.1.2/docs/source/api/pyface.util.grid.grid_row.rst --- python-pyface-4.5.2/docs/source/api/pyface.util.grid.grid_row.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.util.grid.grid_row.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.util.grid.grid\_row module +================================= + +.. automodule:: pyface.util.grid.grid_row + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.util.grid.grid.rst python-pyface-6.1.2/docs/source/api/pyface.util.grid.grid.rst --- python-pyface-4.5.2/docs/source/api/pyface.util.grid.grid.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.util.grid.grid.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.util.grid.grid module +============================ + +.. automodule:: pyface.util.grid.grid + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.util.grid.rst python-pyface-6.1.2/docs/source/api/pyface.util.grid.rst --- python-pyface-4.5.2/docs/source/api/pyface.util.grid.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.util.grid.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,51 +1,19 @@ -grid Package -============ - -:mod:`grid` Package -------------------- +pyface.util.grid package +======================== .. automodule:: pyface.util.grid :members: :undoc-members: :show-inheritance: -:mod:`api` Module ------------------ - -.. automodule:: pyface.util.grid.api - :members: - :undoc-members: - :show-inheritance: - -:mod:`grid` Module ------------------- +Submodules +---------- -.. automodule:: pyface.util.grid.grid - :members: - :undoc-members: - :show-inheritance: +.. toctree:: -:mod:`grid_column` Module -------------------------- - -.. automodule:: pyface.util.grid.grid_column - :members: - :undoc-members: - :show-inheritance: - -:mod:`grid_model` Module ------------------------- - -.. automodule:: pyface.util.grid.grid_model - :members: - :undoc-members: - :show-inheritance: - -:mod:`grid_row` Module ----------------------- - -.. automodule:: pyface.util.grid.grid_row - :members: - :undoc-members: - :show-inheritance: + pyface.util.grid.api + pyface.util.grid.grid + pyface.util.grid.grid_column + pyface.util.grid.grid_model + pyface.util.grid.grid_row diff -Nru python-pyface-4.5.2/docs/source/api/pyface.util.guisupport.rst python-pyface-6.1.2/docs/source/api/pyface.util.guisupport.rst --- python-pyface-4.5.2/docs/source/api/pyface.util.guisupport.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.util.guisupport.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.util.guisupport module +============================= + +.. automodule:: pyface.util.guisupport + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.util.id_helper.rst python-pyface-6.1.2/docs/source/api/pyface.util.id_helper.rst --- python-pyface-4.5.2/docs/source/api/pyface.util.id_helper.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.util.id_helper.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.util.id\_helper module +============================= + +.. automodule:: pyface.util.id_helper + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.util.python_stc.rst python-pyface-6.1.2/docs/source/api/pyface.util.python_stc.rst --- python-pyface-4.5.2/docs/source/api/pyface.util.python_stc.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.util.python_stc.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.util.python\_stc module +============================== + +.. automodule:: pyface.util.python_stc + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.util.rst python-pyface-6.1.2/docs/source/api/pyface.util.rst --- python-pyface-4.5.2/docs/source/api/pyface.util.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.util.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,54 +1,11 @@ -util Package -============ - -:mod:`util` Package -------------------- +pyface.util package +=================== .. automodule:: pyface.util :members: :undoc-members: :show-inheritance: -:mod:`fix_introspect_bug` Module --------------------------------- - -.. automodule:: pyface.util.fix_introspect_bug - :members: - :undoc-members: - :show-inheritance: - -:mod:`font_helper` Module -------------------------- - -.. automodule:: pyface.util.font_helper - :members: - :undoc-members: - :show-inheritance: - -:mod:`guisupport` Module ------------------------- - -.. automodule:: pyface.util.guisupport - :members: - :undoc-members: - :show-inheritance: - -:mod:`id_helper` Module ------------------------ - -.. automodule:: pyface.util.id_helper - :members: - :undoc-members: - :show-inheritance: - -:mod:`python_stc` Module ------------------------- - -.. automodule:: pyface.util.python_stc - :members: - :undoc-members: - :show-inheritance: - Subpackages ----------- @@ -57,3 +14,14 @@ pyface.util.grid pyface.util.tests +Submodules +---------- + +.. toctree:: + + pyface.util.font_helper + pyface.util.guisupport + pyface.util.id_helper + pyface.util.python_stc + pyface.util.testing + diff -Nru python-pyface-4.5.2/docs/source/api/pyface.util.testing.rst python-pyface-6.1.2/docs/source/api/pyface.util.testing.rst --- python-pyface-4.5.2/docs/source/api/pyface.util.testing.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.util.testing.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.util.testing module +========================== + +.. automodule:: pyface.util.testing + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.util.tests.rst python-pyface-6.1.2/docs/source/api/pyface.util.tests.rst --- python-pyface-4.5.2/docs/source/api/pyface.util.tests.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.util.tests.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,11 +1,15 @@ -tests Package -============= +pyface.util.tests package +========================= -:mod:`test_id_helper` Module ----------------------------- - -.. automodule:: pyface.util.tests.test_id_helper +.. automodule:: pyface.util.tests :members: :undoc-members: :show-inheritance: +Submodules +---------- + +.. toctree:: + + pyface.util.tests.test_id_helper + diff -Nru python-pyface-4.5.2/docs/source/api/pyface.util.tests.test_id_helper.rst python-pyface-6.1.2/docs/source/api/pyface.util.tests.test_id_helper.rst --- python-pyface-4.5.2/docs/source/api/pyface.util.tests.test_id_helper.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.util.tests.test_id_helper.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.util.tests.test\_id\_helper module +========================================= + +.. automodule:: pyface.util.tests.test_id_helper + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.api.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.api.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.api module +======================== + +.. automodule:: pyface.viewer.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.column_provider.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.column_provider.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.column_provider.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.column_provider.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.column\_provider module +===================================== + +.. automodule:: pyface.viewer.column_provider + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.content_provider.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.content_provider.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.content_provider.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.content_provider.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.content\_provider module +====================================== + +.. automodule:: pyface.viewer.content_provider + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.content_viewer.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.content_viewer.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.content_viewer.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.content_viewer.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.content\_viewer module +==================================== + +.. automodule:: pyface.viewer.content_viewer + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.default_tree_content_provider.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.default_tree_content_provider.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.default_tree_content_provider.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.default_tree_content_provider.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.default\_tree\_content\_provider module +===================================================== + +.. automodule:: pyface.viewer.default_tree_content_provider + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.label_provider.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.label_provider.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.label_provider.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.label_provider.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.label\_provider module +==================================== + +.. automodule:: pyface.viewer.label_provider + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,147 +1,31 @@ -viewer Package -============== - -:mod:`viewer` Package ---------------------- +pyface.viewer package +===================== .. automodule:: pyface.viewer :members: :undoc-members: :show-inheritance: -:mod:`api` Module ------------------ - -.. automodule:: pyface.viewer.api - :members: - :undoc-members: - :show-inheritance: - -:mod:`column_provider` Module ------------------------------ - -.. automodule:: pyface.viewer.column_provider - :members: - :undoc-members: - :show-inheritance: - -:mod:`content_provider` Module ------------------------------- - -.. automodule:: pyface.viewer.content_provider - :members: - :undoc-members: - :show-inheritance: - -:mod:`content_viewer` Module ----------------------------- - -.. automodule:: pyface.viewer.content_viewer - :members: - :undoc-members: - :show-inheritance: - -:mod:`default_tree_content_provider` Module -------------------------------------------- +Submodules +---------- -.. automodule:: pyface.viewer.default_tree_content_provider - :members: - :undoc-members: - :show-inheritance: +.. toctree:: -:mod:`label_provider` Module ----------------------------- - -.. automodule:: pyface.viewer.label_provider - :members: - :undoc-members: - :show-inheritance: - -:mod:`table_column_provider` Module ------------------------------------ - -.. automodule:: pyface.viewer.table_column_provider - :members: - :undoc-members: - :show-inheritance: - -:mod:`table_content_provider` Module ------------------------------------- - -.. automodule:: pyface.viewer.table_content_provider - :members: - :undoc-members: - :show-inheritance: - -:mod:`table_label_provider` Module ----------------------------------- - -.. automodule:: pyface.viewer.table_label_provider - :members: - :undoc-members: - :show-inheritance: - -:mod:`table_viewer` Module --------------------------- - -.. automodule:: pyface.viewer.table_viewer - :members: - :undoc-members: - :show-inheritance: - -:mod:`tree_content_provider` Module ------------------------------------ - -.. automodule:: pyface.viewer.tree_content_provider - :members: - :undoc-members: - :show-inheritance: - -:mod:`tree_item` Module ------------------------ - -.. automodule:: pyface.viewer.tree_item - :members: - :undoc-members: - :show-inheritance: - -:mod:`tree_label_provider` Module ---------------------------------- - -.. automodule:: pyface.viewer.tree_label_provider - :members: - :undoc-members: - :show-inheritance: - -:mod:`tree_viewer` Module -------------------------- - -.. automodule:: pyface.viewer.tree_viewer - :members: - :undoc-members: - :show-inheritance: - -:mod:`viewer` Module --------------------- - -.. automodule:: pyface.viewer.viewer - :members: - :undoc-members: - :show-inheritance: - -:mod:`viewer_filter` Module ---------------------------- - -.. automodule:: pyface.viewer.viewer_filter - :members: - :undoc-members: - :show-inheritance: - -:mod:`viewer_sorter` Module ---------------------------- - -.. automodule:: pyface.viewer.viewer_sorter - :members: - :undoc-members: - :show-inheritance: + pyface.viewer.api + pyface.viewer.column_provider + pyface.viewer.content_provider + pyface.viewer.content_viewer + pyface.viewer.default_tree_content_provider + pyface.viewer.label_provider + pyface.viewer.table_column_provider + pyface.viewer.table_content_provider + pyface.viewer.table_label_provider + pyface.viewer.table_viewer + pyface.viewer.tree_content_provider + pyface.viewer.tree_item + pyface.viewer.tree_label_provider + pyface.viewer.tree_viewer + pyface.viewer.viewer + pyface.viewer.viewer_filter + pyface.viewer.viewer_sorter diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.table_column_provider.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.table_column_provider.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.table_column_provider.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.table_column_provider.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.table\_column\_provider module +============================================ + +.. automodule:: pyface.viewer.table_column_provider + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.table_content_provider.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.table_content_provider.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.table_content_provider.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.table_content_provider.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.table\_content\_provider module +============================================= + +.. automodule:: pyface.viewer.table_content_provider + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.table_label_provider.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.table_label_provider.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.table_label_provider.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.table_label_provider.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.table\_label\_provider module +=========================================== + +.. automodule:: pyface.viewer.table_label_provider + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.table_viewer.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.table_viewer.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.table_viewer.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.table_viewer.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.table\_viewer module +================================== + +.. automodule:: pyface.viewer.table_viewer + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.tree_content_provider.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.tree_content_provider.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.tree_content_provider.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.tree_content_provider.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.tree\_content\_provider module +============================================ + +.. automodule:: pyface.viewer.tree_content_provider + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.tree_item.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.tree_item.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.tree_item.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.tree_item.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.tree\_item module +=============================== + +.. automodule:: pyface.viewer.tree_item + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.tree_label_provider.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.tree_label_provider.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.tree_label_provider.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.tree_label_provider.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.tree\_label\_provider module +========================================== + +.. automodule:: pyface.viewer.tree_label_provider + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.tree_viewer.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.tree_viewer.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.tree_viewer.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.tree_viewer.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.tree\_viewer module +================================= + +.. automodule:: pyface.viewer.tree_viewer + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.viewer_filter.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.viewer_filter.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.viewer_filter.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.viewer_filter.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.viewer\_filter module +=================================== + +.. automodule:: pyface.viewer.viewer_filter + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.viewer.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.viewer.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.viewer.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.viewer.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.viewer module +=========================== + +.. automodule:: pyface.viewer.viewer + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.viewer.viewer_sorter.rst python-pyface-6.1.2/docs/source/api/pyface.viewer.viewer_sorter.rst --- python-pyface-4.5.2/docs/source/api/pyface.viewer.viewer_sorter.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.viewer.viewer_sorter.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.viewer.viewer\_sorter module +=================================== + +.. automodule:: pyface.viewer.viewer_sorter + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.widget.rst python-pyface-6.1.2/docs/source/api/pyface.widget.rst --- python-pyface-4.5.2/docs/source/api/pyface.widget.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.widget.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.widget module +==================== + +.. automodule:: pyface.widget + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.window.rst python-pyface-6.1.2/docs/source/api/pyface.window.rst --- python-pyface-4.5.2/docs/source/api/pyface.window.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.window.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.window module +==================== + +.. automodule:: pyface.window + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.wizard.api.rst python-pyface-6.1.2/docs/source/api/pyface.wizard.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.wizard.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.wizard.api.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.wizard.api module +======================== + +.. automodule:: pyface.wizard.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.wizard.chained_wizard_controller.rst python-pyface-6.1.2/docs/source/api/pyface.wizard.chained_wizard_controller.rst --- python-pyface-4.5.2/docs/source/api/pyface.wizard.chained_wizard_controller.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.wizard.chained_wizard_controller.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.wizard.chained\_wizard\_controller module +================================================ + +.. automodule:: pyface.wizard.chained_wizard_controller + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.wizard.chained_wizard.rst python-pyface-6.1.2/docs/source/api/pyface.wizard.chained_wizard.rst --- python-pyface-4.5.2/docs/source/api/pyface.wizard.chained_wizard.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.wizard.chained_wizard.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.wizard.chained\_wizard module +==================================== + +.. automodule:: pyface.wizard.chained_wizard + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.wizard.i_wizard_controller.rst python-pyface-6.1.2/docs/source/api/pyface.wizard.i_wizard_controller.rst --- python-pyface-4.5.2/docs/source/api/pyface.wizard.i_wizard_controller.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.wizard.i_wizard_controller.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.wizard.i\_wizard\_controller module +========================================== + +.. automodule:: pyface.wizard.i_wizard_controller + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.wizard.i_wizard_page.rst python-pyface-6.1.2/docs/source/api/pyface.wizard.i_wizard_page.rst --- python-pyface-4.5.2/docs/source/api/pyface.wizard.i_wizard_page.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.wizard.i_wizard_page.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.wizard.i\_wizard\_page module +==================================== + +.. automodule:: pyface.wizard.i_wizard_page + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.wizard.i_wizard.rst python-pyface-6.1.2/docs/source/api/pyface.wizard.i_wizard.rst --- python-pyface-4.5.2/docs/source/api/pyface.wizard.i_wizard.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.wizard.i_wizard.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.wizard.i\_wizard module +============================== + +.. automodule:: pyface.wizard.i_wizard + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.wizard.rst python-pyface-6.1.2/docs/source/api/pyface.wizard.rst --- python-pyface-4.5.2/docs/source/api/pyface.wizard.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.wizard.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,99 +1,25 @@ -wizard Package -============== - -:mod:`wizard` Package ---------------------- +pyface.wizard package +===================== .. automodule:: pyface.wizard :members: :undoc-members: :show-inheritance: -:mod:`api` Module ------------------ - -.. automodule:: pyface.wizard.api - :members: - :undoc-members: - :show-inheritance: - -:mod:`chained_wizard` Module ----------------------------- - -.. automodule:: pyface.wizard.chained_wizard - :members: - :undoc-members: - :show-inheritance: - -:mod:`chained_wizard_controller` Module ---------------------------------------- +Submodules +---------- -.. automodule:: pyface.wizard.chained_wizard_controller - :members: - :undoc-members: - :show-inheritance: +.. toctree:: -:mod:`i_wizard` Module ----------------------- - -.. automodule:: pyface.wizard.i_wizard - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_wizard_controller` Module ---------------------------------- - -.. automodule:: pyface.wizard.i_wizard_controller - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_wizard_page` Module ---------------------------- - -.. automodule:: pyface.wizard.i_wizard_page - :members: - :undoc-members: - :show-inheritance: - -:mod:`simple_wizard` Module ---------------------------- - -.. automodule:: pyface.wizard.simple_wizard - :members: - :undoc-members: - :show-inheritance: - -:mod:`simple_wizard_controller` Module --------------------------------------- - -.. automodule:: pyface.wizard.simple_wizard_controller - :members: - :undoc-members: - :show-inheritance: - -:mod:`wizard` Module --------------------- - -.. automodule:: pyface.wizard.wizard - :members: - :undoc-members: - :show-inheritance: - -:mod:`wizard_controller` Module -------------------------------- - -.. automodule:: pyface.wizard.wizard_controller - :members: - :undoc-members: - :show-inheritance: - -:mod:`wizard_page` Module -------------------------- - -.. automodule:: pyface.wizard.wizard_page - :members: - :undoc-members: - :show-inheritance: + pyface.wizard.api + pyface.wizard.chained_wizard + pyface.wizard.chained_wizard_controller + pyface.wizard.i_wizard + pyface.wizard.i_wizard_controller + pyface.wizard.i_wizard_page + pyface.wizard.simple_wizard + pyface.wizard.simple_wizard_controller + pyface.wizard.wizard + pyface.wizard.wizard_controller + pyface.wizard.wizard_page diff -Nru python-pyface-4.5.2/docs/source/api/pyface.wizard.simple_wizard_controller.rst python-pyface-6.1.2/docs/source/api/pyface.wizard.simple_wizard_controller.rst --- python-pyface-4.5.2/docs/source/api/pyface.wizard.simple_wizard_controller.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.wizard.simple_wizard_controller.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.wizard.simple\_wizard\_controller module +=============================================== + +.. automodule:: pyface.wizard.simple_wizard_controller + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.wizard.simple_wizard.rst python-pyface-6.1.2/docs/source/api/pyface.wizard.simple_wizard.rst --- python-pyface-4.5.2/docs/source/api/pyface.wizard.simple_wizard.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.wizard.simple_wizard.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.wizard.simple\_wizard module +=================================== + +.. automodule:: pyface.wizard.simple_wizard + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.wizard.wizard_controller.rst python-pyface-6.1.2/docs/source/api/pyface.wizard.wizard_controller.rst --- python-pyface-4.5.2/docs/source/api/pyface.wizard.wizard_controller.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.wizard.wizard_controller.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.wizard.wizard\_controller module +======================================= + +.. automodule:: pyface.wizard.wizard_controller + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.wizard.wizard_page.rst python-pyface-6.1.2/docs/source/api/pyface.wizard.wizard_page.rst --- python-pyface-4.5.2/docs/source/api/pyface.wizard.wizard_page.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.wizard.wizard_page.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.wizard.wizard\_page module +================================= + +.. automodule:: pyface.wizard.wizard_page + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.wizard.wizard.rst python-pyface-6.1.2/docs/source/api/pyface.wizard.wizard.rst --- python-pyface-4.5.2/docs/source/api/pyface.wizard.wizard.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.wizard.wizard.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.wizard.wizard module +=========================== + +.. automodule:: pyface.wizard.wizard + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.action_controller.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.action_controller.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.action_controller.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.action_controller.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.action\_controller module +================================================= + +.. automodule:: pyface.workbench.action.action_controller + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.api.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.api.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.api module +================================== + +.. automodule:: pyface.workbench.action.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.delete_user_perspective_action.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.delete_user_perspective_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.delete_user_perspective_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.delete_user_perspective_action.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.delete\_user\_perspective\_action module +================================================================ + +.. automodule:: pyface.workbench.action.delete_user_perspective_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.menu_bar_manager.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.menu_bar_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.menu_bar_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.menu_bar_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.menu\_bar\_manager module +================================================= + +.. automodule:: pyface.workbench.action.menu_bar_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.new_user_perspective_action.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.new_user_perspective_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.new_user_perspective_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.new_user_perspective_action.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.new\_user\_perspective\_action module +============================================================= + +.. automodule:: pyface.workbench.action.new_user_perspective_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.perspective_menu_manager.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.perspective_menu_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.perspective_menu_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.perspective_menu_manager.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.perspective\_menu\_manager module +========================================================= + +.. automodule:: pyface.workbench.action.perspective_menu_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.rename_user_perspective_action.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.rename_user_perspective_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.rename_user_perspective_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.rename_user_perspective_action.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.rename\_user\_perspective\_action module +================================================================ + +.. automodule:: pyface.workbench.action.rename_user_perspective_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.reset_active_perspective_action.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.reset_active_perspective_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.reset_active_perspective_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.reset_active_perspective_action.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.reset\_active\_perspective\_action module +================================================================= + +.. automodule:: pyface.workbench.action.reset_active_perspective_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.reset_all_perspectives_action.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.reset_all_perspectives_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.reset_all_perspectives_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.reset_all_perspectives_action.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.reset\_all\_perspectives\_action module +=============================================================== + +.. automodule:: pyface.workbench.action.reset_all_perspectives_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.rst 2019-05-08 14:16:25.000000000 +0000 @@ -1,163 +1,34 @@ -action Package -============== +pyface.workbench.action package +=============================== -:mod:`action_controller` Module -------------------------------- - -.. automodule:: pyface.workbench.action.action_controller - :members: - :undoc-members: - :show-inheritance: - -:mod:`api` Module ------------------ - -.. automodule:: pyface.workbench.action.api - :members: - :undoc-members: - :show-inheritance: - -:mod:`delete_user_perspective_action` Module --------------------------------------------- - -.. automodule:: pyface.workbench.action.delete_user_perspective_action - :members: - :undoc-members: - :show-inheritance: - -:mod:`menu_bar_manager` Module ------------------------------- - -.. automodule:: pyface.workbench.action.menu_bar_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`new_user_perspective_action` Module ------------------------------------------ - -.. automodule:: pyface.workbench.action.new_user_perspective_action - :members: - :undoc-members: - :show-inheritance: - -:mod:`perspective_menu_manager` Module --------------------------------------- - -.. automodule:: pyface.workbench.action.perspective_menu_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`rename_user_perspective_action` Module --------------------------------------------- - -.. automodule:: pyface.workbench.action.rename_user_perspective_action - :members: - :undoc-members: - :show-inheritance: - -:mod:`reset_active_perspective_action` Module ---------------------------------------------- - -.. automodule:: pyface.workbench.action.reset_active_perspective_action +.. automodule:: pyface.workbench.action :members: :undoc-members: :show-inheritance: -:mod:`reset_all_perspectives_action` Module -------------------------------------------- - -.. automodule:: pyface.workbench.action.reset_all_perspectives_action - :members: - :undoc-members: - :show-inheritance: - -:mod:`save_as_user_perspective_action` Module ---------------------------------------------- - -.. automodule:: pyface.workbench.action.save_as_user_perspective_action - :members: - :undoc-members: - :show-inheritance: - -:mod:`set_active_perspective_action` Module -------------------------------------------- - -.. automodule:: pyface.workbench.action.set_active_perspective_action - :members: - :undoc-members: - :show-inheritance: - -:mod:`setattr_action` Module ----------------------------- - -.. automodule:: pyface.workbench.action.setattr_action - :members: - :undoc-members: - :show-inheritance: - -:mod:`show_view_action` Module ------------------------------- - -.. automodule:: pyface.workbench.action.show_view_action - :members: - :undoc-members: - :show-inheritance: - -:mod:`toggle_view_visibility_action` Module -------------------------------------------- - -.. automodule:: pyface.workbench.action.toggle_view_visibility_action - :members: - :undoc-members: - :show-inheritance: - -:mod:`tool_bar_manager` Module ------------------------------- - -.. automodule:: pyface.workbench.action.tool_bar_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`user_perspective_action` Module -------------------------------------- - -.. automodule:: pyface.workbench.action.user_perspective_action - :members: - :undoc-members: - :show-inheritance: - -:mod:`user_perspective_name` Module ------------------------------------ - -.. automodule:: pyface.workbench.action.user_perspective_name - :members: - :undoc-members: - :show-inheritance: - -:mod:`view_chooser` Module --------------------------- - -.. automodule:: pyface.workbench.action.view_chooser - :members: - :undoc-members: - :show-inheritance: - -:mod:`view_menu_manager` Module -------------------------------- - -.. automodule:: pyface.workbench.action.view_menu_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`workbench_action` Module ------------------------------- - -.. automodule:: pyface.workbench.action.workbench_action - :members: - :undoc-members: - :show-inheritance: +Submodules +---------- + +.. toctree:: + + pyface.workbench.action.action_controller + pyface.workbench.action.api + pyface.workbench.action.delete_user_perspective_action + pyface.workbench.action.menu_bar_manager + pyface.workbench.action.new_user_perspective_action + pyface.workbench.action.perspective_menu_manager + pyface.workbench.action.rename_user_perspective_action + pyface.workbench.action.reset_active_perspective_action + pyface.workbench.action.reset_all_perspectives_action + pyface.workbench.action.save_as_user_perspective_action + pyface.workbench.action.set_active_perspective_action + pyface.workbench.action.setattr_action + pyface.workbench.action.show_view_action + pyface.workbench.action.toggle_view_visibility_action + pyface.workbench.action.tool_bar_manager + pyface.workbench.action.user_perspective_action + pyface.workbench.action.user_perspective_name + pyface.workbench.action.view_chooser + pyface.workbench.action.view_menu_manager + pyface.workbench.action.workbench_action diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.save_as_user_perspective_action.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.save_as_user_perspective_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.save_as_user_perspective_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.save_as_user_perspective_action.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.save\_as\_user\_perspective\_action module +================================================================== + +.. automodule:: pyface.workbench.action.save_as_user_perspective_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.set_active_perspective_action.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.set_active_perspective_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.set_active_perspective_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.set_active_perspective_action.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.set\_active\_perspective\_action module +=============================================================== + +.. automodule:: pyface.workbench.action.set_active_perspective_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.setattr_action.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.setattr_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.setattr_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.setattr_action.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.setattr\_action module +============================================== + +.. automodule:: pyface.workbench.action.setattr_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.show_view_action.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.show_view_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.show_view_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.show_view_action.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.show\_view\_action module +================================================= + +.. automodule:: pyface.workbench.action.show_view_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.toggle_view_visibility_action.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.toggle_view_visibility_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.toggle_view_visibility_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.toggle_view_visibility_action.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.toggle\_view\_visibility\_action module +=============================================================== + +.. automodule:: pyface.workbench.action.toggle_view_visibility_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.tool_bar_manager.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.tool_bar_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.tool_bar_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.tool_bar_manager.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.tool\_bar\_manager module +================================================= + +.. automodule:: pyface.workbench.action.tool_bar_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.user_perspective_action.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.user_perspective_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.user_perspective_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.user_perspective_action.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.user\_perspective\_action module +======================================================== + +.. automodule:: pyface.workbench.action.user_perspective_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.user_perspective_name.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.user_perspective_name.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.user_perspective_name.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.user_perspective_name.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.user\_perspective\_name module +====================================================== + +.. automodule:: pyface.workbench.action.user_perspective_name + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.view_chooser.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.view_chooser.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.view_chooser.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.view_chooser.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.view\_chooser module +============================================ + +.. automodule:: pyface.workbench.action.view_chooser + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.view_menu_manager.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.view_menu_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.view_menu_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.view_menu_manager.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.view\_menu\_manager module +================================================== + +.. automodule:: pyface.workbench.action.view_menu_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.action.workbench_action.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.action.workbench_action.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.action.workbench_action.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.action.workbench_action.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.action.workbench\_action module +================================================ + +.. automodule:: pyface.workbench.action.workbench_action + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.api.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.api.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.api module +=========================== + +.. automodule:: pyface.workbench.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.debug.api.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.debug.api.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.debug.api.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.debug.api.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.debug.api module +================================= + +.. automodule:: pyface.workbench.debug.api + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.debug.debug_view.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.debug.debug_view.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.debug.debug_view.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.debug.debug_view.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.debug.debug\_view module +========================================= + +.. automodule:: pyface.workbench.debug.debug_view + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.debug.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.debug.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.debug.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.debug.rst 2019-05-08 14:16:25.000000000 +0000 @@ -1,19 +1,16 @@ -debug Package -============= +pyface.workbench.debug package +============================== -:mod:`api` Module ------------------ - -.. automodule:: pyface.workbench.debug.api +.. automodule:: pyface.workbench.debug :members: :undoc-members: :show-inheritance: -:mod:`debug_view` Module ------------------------- +Submodules +---------- -.. automodule:: pyface.workbench.debug.debug_view - :members: - :undoc-members: - :show-inheritance: +.. toctree:: + + pyface.workbench.debug.api + pyface.workbench.debug.debug_view diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.editor_manager.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.editor_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.editor_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.editor_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.editor\_manager module +======================================= + +.. automodule:: pyface.workbench.editor_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.editor.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.editor.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.editor.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.editor.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.editor module +============================== + +.. automodule:: pyface.workbench.editor + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.i_editor_manager.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.i_editor_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.i_editor_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.i_editor_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.i\_editor\_manager module +========================================== + +.. automodule:: pyface.workbench.i_editor_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.i_editor.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.i_editor.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.i_editor.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.i_editor.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.i\_editor module +================================= + +.. automodule:: pyface.workbench.i_editor + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.i_perspective_item.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.i_perspective_item.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.i_perspective_item.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.i_perspective_item.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.i\_perspective\_item module +============================================ + +.. automodule:: pyface.workbench.i_perspective_item + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.i_perspective.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.i_perspective.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.i_perspective.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.i_perspective.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.i\_perspective module +====================================== + +.. automodule:: pyface.workbench.i_perspective + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.i_view.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.i_view.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.i_view.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.i_view.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.i\_view module +=============================== + +.. automodule:: pyface.workbench.i_view + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.i_workbench_part.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.i_workbench_part.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.i_workbench_part.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.i_workbench_part.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.i\_workbench\_part module +========================================== + +.. automodule:: pyface.workbench.i_workbench_part + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.i_workbench.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.i_workbench.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.i_workbench.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.i_workbench.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.i\_workbench module +==================================== + +.. automodule:: pyface.workbench.i_workbench + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.i_workbench_window_layout.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.i_workbench_window_layout.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.i_workbench_window_layout.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.i_workbench_window_layout.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.i\_workbench\_window\_layout module +==================================================== + +.. automodule:: pyface.workbench.i_workbench_window_layout + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.perspective_item.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.perspective_item.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.perspective_item.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.perspective_item.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.perspective\_item module +========================================= + +.. automodule:: pyface.workbench.perspective_item + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.perspective.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.perspective.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.perspective.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.perspective.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.perspective module +=================================== + +.. automodule:: pyface.workbench.perspective + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.rst 2019-05-08 14:16:24.000000000 +0000 @@ -1,178 +1,7 @@ -workbench Package -================= +pyface.workbench package +======================== -:mod:`api` Module ------------------ - -.. automodule:: pyface.workbench.api - :members: - :undoc-members: - :show-inheritance: - -:mod:`editor` Module --------------------- - -.. automodule:: pyface.workbench.editor - :members: - :undoc-members: - :show-inheritance: - -:mod:`editor_manager` Module ----------------------------- - -.. automodule:: pyface.workbench.editor_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_editor` Module ----------------------- - -.. automodule:: pyface.workbench.i_editor - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_editor_manager` Module ------------------------------- - -.. automodule:: pyface.workbench.i_editor_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_perspective` Module ---------------------------- - -.. automodule:: pyface.workbench.i_perspective - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_perspective_item` Module --------------------------------- - -.. automodule:: pyface.workbench.i_perspective_item - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_view` Module --------------------- - -.. automodule:: pyface.workbench.i_view - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_workbench` Module -------------------------- - -.. automodule:: pyface.workbench.i_workbench - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_workbench_part` Module ------------------------------- - -.. automodule:: pyface.workbench.i_workbench_part - :members: - :undoc-members: - :show-inheritance: - -:mod:`i_workbench_window_layout` Module ---------------------------------------- - -.. automodule:: pyface.workbench.i_workbench_window_layout - :members: - :undoc-members: - :show-inheritance: - -:mod:`perspective` Module -------------------------- - -.. automodule:: pyface.workbench.perspective - :members: - :undoc-members: - :show-inheritance: - -:mod:`perspective_item` Module ------------------------------- - -.. automodule:: pyface.workbench.perspective_item - :members: - :undoc-members: - :show-inheritance: - -:mod:`traits_ui_editor` Module ------------------------------- - -.. automodule:: pyface.workbench.traits_ui_editor - :members: - :undoc-members: - :show-inheritance: - -:mod:`traits_ui_view` Module ----------------------------- - -.. automodule:: pyface.workbench.traits_ui_view - :members: - :undoc-members: - :show-inheritance: - -:mod:`user_perspective_manager` Module --------------------------------------- - -.. automodule:: pyface.workbench.user_perspective_manager - :members: - :undoc-members: - :show-inheritance: - -:mod:`view` Module ------------------- - -.. automodule:: pyface.workbench.view - :members: - :undoc-members: - :show-inheritance: - -:mod:`window_event` Module --------------------------- - -.. automodule:: pyface.workbench.window_event - :members: - :undoc-members: - :show-inheritance: - -:mod:`workbench` Module ------------------------ - -.. automodule:: pyface.workbench.workbench - :members: - :undoc-members: - :show-inheritance: - -:mod:`workbench_window` Module ------------------------------- - -.. automodule:: pyface.workbench.workbench_window - :members: - :undoc-members: - :show-inheritance: - -:mod:`workbench_window_layout` Module -------------------------------------- - -.. automodule:: pyface.workbench.workbench_window_layout - :members: - :undoc-members: - :show-inheritance: - -:mod:`workbench_window_memento` Module --------------------------------------- - -.. automodule:: pyface.workbench.workbench_window_memento +.. automodule:: pyface.workbench :members: :undoc-members: :show-inheritance: @@ -184,4 +13,33 @@ pyface.workbench.action pyface.workbench.debug + pyface.workbench.tests + +Submodules +---------- + +.. toctree:: + + pyface.workbench.api + pyface.workbench.editor + pyface.workbench.editor_manager + pyface.workbench.i_editor + pyface.workbench.i_editor_manager + pyface.workbench.i_perspective + pyface.workbench.i_perspective_item + pyface.workbench.i_view + pyface.workbench.i_workbench + pyface.workbench.i_workbench_part + pyface.workbench.i_workbench_window_layout + pyface.workbench.perspective + pyface.workbench.perspective_item + pyface.workbench.traits_ui_editor + pyface.workbench.traits_ui_view + pyface.workbench.user_perspective_manager + pyface.workbench.view + pyface.workbench.window_event + pyface.workbench.workbench + pyface.workbench.workbench_window + pyface.workbench.workbench_window_layout + pyface.workbench.workbench_window_memento diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.tests.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.tests.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.tests.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.tests.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,15 @@ +pyface.workbench.tests package +============================== + +.. automodule:: pyface.workbench.tests + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + + pyface.workbench.tests.test_workbench_window + diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.tests.test_workbench_window.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.tests.test_workbench_window.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.tests.test_workbench_window.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.tests.test_workbench_window.rst 2019-05-08 14:16:25.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.tests.test\_workbench\_window module +===================================================== + +.. automodule:: pyface.workbench.tests.test_workbench_window + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.traits_ui_editor.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.traits_ui_editor.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.traits_ui_editor.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.traits_ui_editor.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.traits\_ui\_editor module +========================================== + +.. automodule:: pyface.workbench.traits_ui_editor + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.traits_ui_view.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.traits_ui_view.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.traits_ui_view.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.traits_ui_view.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.traits\_ui\_view module +======================================== + +.. automodule:: pyface.workbench.traits_ui_view + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.user_perspective_manager.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.user_perspective_manager.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.user_perspective_manager.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.user_perspective_manager.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.user\_perspective\_manager module +================================================== + +.. automodule:: pyface.workbench.user_perspective_manager + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.view.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.view.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.view.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.view.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.view module +============================ + +.. automodule:: pyface.workbench.view + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.window_event.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.window_event.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.window_event.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.window_event.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.window\_event module +===================================== + +.. automodule:: pyface.workbench.window_event + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.workbench.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.workbench.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.workbench.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.workbench.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.workbench module +================================= + +.. automodule:: pyface.workbench.workbench + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.workbench_window_layout.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.workbench_window_layout.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.workbench_window_layout.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.workbench_window_layout.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.workbench\_window\_layout module +================================================= + +.. automodule:: pyface.workbench.workbench_window_layout + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.workbench_window_memento.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.workbench_window_memento.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.workbench_window_memento.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.workbench_window_memento.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.workbench\_window\_memento module +================================================== + +.. automodule:: pyface.workbench.workbench_window_memento + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.workbench.workbench_window.rst python-pyface-6.1.2/docs/source/api/pyface.workbench.workbench_window.rst --- python-pyface-4.5.2/docs/source/api/pyface.workbench.workbench_window.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.workbench.workbench_window.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.workbench.workbench\_window module +========================================= + +.. automodule:: pyface.workbench.workbench_window + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/api/pyface.wx.rst python-pyface-6.1.2/docs/source/api/pyface.wx.rst --- python-pyface-4.5.2/docs/source/api/pyface.wx.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.wx.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,154 +0,0 @@ -wx Package -========== - -:mod:`wx` Package ------------------ - -.. automodule:: pyface.wx - :members: - :undoc-members: - :show-inheritance: - -:mod:`clipboard` Module ------------------------ - -.. automodule:: pyface.wx.clipboard - :members: - :undoc-members: - :show-inheritance: - -:mod:`color` Module -------------------- - -.. automodule:: pyface.wx.color - :members: - :undoc-members: - :show-inheritance: - -:mod:`dialog` Module --------------------- - -.. automodule:: pyface.wx.dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`divider` Module ---------------------- - -.. automodule:: pyface.wx.divider - :members: - :undoc-members: - :show-inheritance: - -:mod:`drag_and_drop` Module ---------------------------- - -.. automodule:: pyface.wx.drag_and_drop - :members: - :undoc-members: - :show-inheritance: - -:mod:`font` Module ------------------- - -.. automodule:: pyface.wx.font - :members: - :undoc-members: - :show-inheritance: - -:mod:`image` Module -------------------- - -.. automodule:: pyface.wx.image - :members: - :undoc-members: - :show-inheritance: - -:mod:`image_cache` Module -------------------------- - -.. automodule:: pyface.wx.image_cache - :members: - :undoc-members: - :show-inheritance: - -:mod:`image_list` Module ------------------------- - -.. automodule:: pyface.wx.image_list - :members: - :undoc-members: - :show-inheritance: - -:mod:`lazy_switcher` Module ---------------------------- - -.. automodule:: pyface.wx.lazy_switcher - :members: - :undoc-members: - :show-inheritance: - -:mod:`pager` Module -------------------- - -.. automodule:: pyface.wx.pager - :members: - :undoc-members: - :show-inheritance: - -:mod:`progress_meter` Module ----------------------------- - -.. automodule:: pyface.wx.progress_meter - :members: - :undoc-members: - :show-inheritance: - -:mod:`scrolled_message_dialog` Module -------------------------------------- - -.. automodule:: pyface.wx.scrolled_message_dialog - :members: - :undoc-members: - :show-inheritance: - -:mod:`shell` Module -------------------- - -.. automodule:: pyface.wx.shell - :members: - :undoc-members: - :show-inheritance: - -:mod:`sized_panel` Module -------------------------- - -.. automodule:: pyface.wx.sized_panel - :members: - :undoc-members: - :show-inheritance: - -:mod:`spacer` Module --------------------- - -.. automodule:: pyface.wx.spacer - :members: - :undoc-members: - :show-inheritance: - -:mod:`switcher` Module ----------------------- - -.. automodule:: pyface.wx.switcher - :members: - :undoc-members: - :show-inheritance: - -Subpackages ------------ - -.. toctree:: - - pyface.wx.spreadsheet - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.wx.spreadsheet.rst python-pyface-6.1.2/docs/source/api/pyface.wx.spreadsheet.rst --- python-pyface-4.5.2/docs/source/api/pyface.wx.spreadsheet.rst 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.wx.spreadsheet.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -spreadsheet Package -=================== - -:mod:`spreadsheet` Package --------------------------- - -.. automodule:: pyface.wx.spreadsheet - :members: - :undoc-members: - :show-inheritance: - -:mod:`abstract_grid_view` Module --------------------------------- - -.. automodule:: pyface.wx.spreadsheet.abstract_grid_view - :members: - :undoc-members: - :show-inheritance: - -:mod:`default_renderer` Module ------------------------------- - -.. automodule:: pyface.wx.spreadsheet.default_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`font_renderer` Module ---------------------------- - -.. automodule:: pyface.wx.spreadsheet.font_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`unit_renderer` Module ---------------------------- - -.. automodule:: pyface.wx.spreadsheet.unit_renderer - :members: - :undoc-members: - :show-inheritance: - -:mod:`virtual_model` Module ---------------------------- - -.. automodule:: pyface.wx.spreadsheet.virtual_model - :members: - :undoc-members: - :show-inheritance: - diff -Nru python-pyface-4.5.2/docs/source/api/pyface.xrc_dialog.rst python-pyface-6.1.2/docs/source/api/pyface.xrc_dialog.rst --- python-pyface-4.5.2/docs/source/api/pyface.xrc_dialog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/api/pyface.xrc_dialog.rst 2019-05-08 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +pyface.xrc\_dialog module +========================= + +.. automodule:: pyface.xrc_dialog + :members: + :undoc-members: + :show-inheritance: diff -Nru python-pyface-4.5.2/docs/source/applications.rst python-pyface-6.1.2/docs/source/applications.rst --- python-pyface-4.5.2/docs/source/applications.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/applications.rst 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,265 @@ +=================== +Pyface Applications +=================== + +.. py:currentmodule:: pyface.application + +Pyface provides a collection of classes suitable for representing an +application. Although the classes are principally designed to work with +GUI-based applications, the base class :py:class:`Application` class does not +and so can be used as the basis for command-line or server applications with +a shared codebase with a GUI application. + +Additionally, the application classes are designed to be forward-compatible +with Envisage application classes so applications developed using this +framework can easily be refactored to take advantage of the Envisage's plug-in +extensibility if that should be required. + +Application Interface +===================== + +The core of the :py:class:`Application` class' API are three methods: +:py:meth:`Application.run`, :py:meth:`Application.start`, and +:py:meth:`Application.stop`. The :py:meth:`Application.run` method is the +entry-point of the application, and performs the following steps: + +1. calls the :py:meth:`Application.start` method to initialize the + application's state. + +2. if the start is successful, calls an internal :py:meth:`Application._run` + method which does the actual work (such as running the GUI event loop). + +3. when the :py:meth:`Application._run` method returns, calls + :py:meth:`Application.stop` to release any resources used by the application + and de-initialize as needed. + +Subclasses of the base :py:class:`Application` class will likely override all +three of these methods, but :py:class:`pyface.gui_application.GUIApplication` +subclasses may be able to avoid having to touch them, depending on what +addition resources they need to access. + +In addition to these three methods, there is an :py:meth:`Application.exit` +method that can be called by code that wants to halt the application at that +point. For the base class this simply raises an :py:class:``ApplicationExit`` +exception, but for event loop based classes it may instead call appropriate +toolkit code to close open windows and stop the application event loop. + +During this life-cycle, the application will emit various Traits events +indicating the state that it is currently in. The sequence of events is +normally :py:attr:`Application.starting`, :py:attr:`Application.started` +:py:attr:`Application.application_initialized`, +:py:attr:`Application.stopping`, and :py:attr:`Application.stopped` + +In addition to the core methods and events, the :py:class:`Application` class +has some traits for metadata about the application, primarily the +human-readable application name, a description of the application, and a +globally unique application id. The application also has traits holding +platform-dependent "home" and "user" directory paths, which by default are +provided by :py:mod:`traits.etsconfig` which give reasonable platform-dependent +results. + +Application Example +------------------- + +A simple command-line application might look something like this:: + + import argparse + from pyface.application import Application + from traits.api import Str + + class HelloApplication(Application): + """ Simple application subclass that greets a location. """ + + #: The location being greeted. + location = Str("world") + + def _run(self): + super(HelloApplication, self)._run() + print("Hello "+self.location) + + def main(): + app = HelloApplication() + + parser = argparse.ArgumentParser(description=app.description) + parser.add_argument('location', nargs='?', default=app.location, + help="the location to greet") + parser.parse_args(namespace=app) + + app.run() + + if __name__ == '__main__': + main() + + +GUIApplication Interface +======================== + +.. py:currentmodule:: pyface.gui_application + +The :py:class:`GUIApplication` subclass is the base class to use for +Pyface-based GUI applications. This class invokes the Pyface toolkit's event +loop in the :py:meth:`GUIApplication._run` method, and stops it in the +:py:meth:`GUIApplication._exit` method. + +The class has code that tracks application windows through their lifecycle. +The application has a list :py:attr:`GUIApplication.windows` of all known +windows. Windows can be added to the list with the +:py:meth:`GUIApplication.add_window` method which also handles opening the +window. Windows are automatically removed from the list when they are closed. +In addition the class has a :py:meth:`GUIApplication.create_window` method +which by default calls the :py:attr:`GUIApplication.window_factory` attribute +and handles setting titles, icons and sizing of the created windows. Windows +created by :py:meth:`GUIApplication.create_window` still need to be added to +the application's list of windows via :py:meth:`GUIApplication.add_window`. + +The :py:meth:`GUIApplication.start` method of the class must ensure that there +is at least one open window by the point that the event loop starts, +particularly with the WxPython backend. The default +:py:meth:`GUIApplication.start` method calls +:py:meth:`GUIApplication._create_windows` to perform the initial set-up of open +windows. The default behaviour is to call the +:py:meth:`GUIApplication.create_windows` method and then add that window. + +In most cases to use the base :py:class:`GUIApplication` class, you will want +to: + +* create a subclass of :py:class:`~pyface.application_window.ApplicationWindow` + that at least overrides the + :py:meth:`~pyface.application_window.ApplicationWindow._create_contents` + method to create the desired user interface. Ideally this window should be + able to work without needing an application, as this helps with reusability. +* create a window factory function that taskes the application and arbitrary + other keyword arguments and creates an instance of the + :py:class:`~pyface.application_window.ApplicationWindow` subclass along with + any additional application-dependent state that is required. This can + include application-dependent menus, toolbars, etc. as well as other state + injected by from application. + +While the :py:class:`GUIApplication` class can be used without subclassing, for +complex applications it is likely that the a subclass will need to be used, +and will likely override the :py:meth:`~GUIApplication.start`, +:py:meth:`~GUIApplication.stop` and :py:meth:`~GUIApplication.create_window` +methods to perform additional application-specific customization. + +GUIApplication Example +---------------------- + +The following example shows how to build a simple but functional +:py:class:`GUIApplication` which provides an interactive Python shell. The +application has two parts: a +:py:class:`pyface.application_window.ApplicationWindow` subclass which is +responsible for creating the Python shell widget, and a window factory which +is responsible for creating the windows and populating the menu bar. + +The application window subclass looks like this:: + + from pyface.api import ApplicationWindow, PythonShell + from traits.api import Instance + + class PythonShellWindow(ApplicationWindow): + """ An application window that displays a simple Python shell. """ + + #: The title of the window. + title = "Python Shell" + + #: The Python shell widget to use. + shell = Instance('pyface.i_python_shell.IPythonShell') + + def _create_contents(self, parent): + """ Create the shell widget. """ + self.shell = PythonShell(parent) + return self.shell.control + +Note that we don't (and shouldn't) need the application to be available for +this class to work - it is a perfectly good stand-alone class that can +potentially be re-used in many different contexts. + +While the GUI application window subclass looks like this:: + + from pyface.api import GUIApplication + from pyface.action.api import ( + AboutAction, CloseWindowAction, CreateWindowAction, ExitAction, Group, + MenuBarManager, MenuManager + ) + from python_shell_window import PythonShellWindow + + def create_python_shell_window(application, **kwargs): + window = PythonShellWindow() + window.menu_bar_manager = MenuBarManager( + MenuManager( + Group(CreateWindowAction(application=application)), + Group( + CloseWindowAction(window=window), + ExitAction(application=application), + ), + name='&File', + ), + MenuManager( + AboutAction(application=application), + name='&Help', + ) + ) + return window + + def main(): + app = GUIApplication( + name="Python Shell", + description="An example application that provides a Python shell.", + icon='python_icon', + logo='python_logo', + window_factory=create_python_shell_window, + ) + app.run() + + if __name__ == '__main__': + main() + +A more complete version of this can be found in the Pyface examples. + +TasksApplication Interface +========================== + +.. py:currentmodule:: pyface.tasks.tasks_application + +The :py:class:`TasksApplication` class works in a similar way to the +:py:class:`~pyface.gui_application.GUIApplication` class, but instead of the +supplying a window factory, instead you provide one or more +:py:class:`TaskFactory` instances which provide information about the +different Tasks that are available for each window. + +In addition the :py:class:`TasksApplication` has traits that hold extra +application-specific :py:class:`~pyface.actions.action.Action`s via the +:py:class:`~pyface.tasks.actions.schema_addition.SchemaAddition` mechanism, +and :py:class:`~pyface.tasks.dock_pane.DockPane` via factories for creating +the dock panes. + +A complete :py:class:`TasksApplication` can be as simple as:: + + from pyface.tasks.api import TaskFactory, TasksApplication + from python_editor_task import PythonEditorTask + + def main(): + app = TasksApplication( + id="example_python_editor_application", + name="Python Editor", + description=( + "An example Tasks application that provides a Python editor." + ), + icon='python_icon', + logo='python_logo', + task_factories=[ + TaskFactory( + id='example.python_editor_task', + name="Python Editor", + factory=PythonEditorTask + ) + ], + ) + + # invoke the mainloop + app.run() + + if __name__ == '__main__': + main() + +A more complete version of this can be found in the Pyface examples. diff -Nru python-pyface-4.5.2/docs/source/changelog.rst python-pyface-6.1.2/docs/source/changelog.rst --- python-pyface-4.5.2/docs/source/changelog.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/changelog.rst 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,2 @@ + +.. include:: ../../CHANGES.txt diff -Nru python-pyface-4.5.2/docs/source/conf.py python-pyface-6.1.2/docs/source/conf.py --- python-pyface-4.5.2/docs/source/conf.py 2015-03-16 14:33:12.000000000 +0000 +++ python-pyface-6.1.2/docs/source/conf.py 2019-05-03 13:53:35.000000000 +0000 @@ -26,8 +26,9 @@ # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'sphinx.ext.autodoc', - 'refactordoc', - ] + 'sphinx.ext.napoleon', + 'traits.util.trait_documenter' +] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -40,13 +41,14 @@ # General substitutions. project = 'pyface' -copyright = '2008-2015, Enthought' +copyright = '2008-2016, Enthought' # The default replacements for |version| and |release|, also used in various # other places throughout the built documents. d = {} -execfile(os.path.join('..', '..', 'pyface', '__init__.py'), d) -version = release = d['__version__'] +with open(os.path.join('..', '..', 'pyface', '_version.py')) as fp: + exec (fp.read(), d) +version = release = d['full_version'] # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: @@ -78,14 +80,13 @@ # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' - # Options for HTML output # ----------------------- # The style sheet to use for HTML and HTML Help pages. A file of that name # must exist either in Sphinx' static/ path, or in one of the custom paths # given in html_static_path. -html_style = 'default.css' +#html_style = 'default.css' # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". @@ -96,12 +97,12 @@ # The name of an image file (within the static path) to place at the top of # the sidebar. -html_logo = "_static/e-logo-rev.png" +#html_logo = "_static/e-logo-rev.png" # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -html_favicon = "et.ico" +#html_favicon = "favicon.ico" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -144,8 +145,31 @@ #html_file_suffix = '' # Output file base name for HTML help builder. -htmlhelp_basename = 'ETSdoc' +htmlhelp_basename = 'Pyfacedoc' +# html theme information +try: + import enthought_sphinx_theme + + html_theme_path = [enthought_sphinx_theme.theme_path] + html_theme = 'enthought' +except ImportError as exc: + import warnings + msg = "Can't find Enthought Sphinx Theme, using default.\nException was:\n{}" + warnings.warn(RuntimeWarning(msg.format(exc))) + + # old defaults + html_logo = "e-logo-rev.jpg" + html_favicon = "et.png" + html_style = 'default.css' + +# Useful aliases to avoid repeating long URLs. +extlinks = { + 'github-examples': ( + 'https://github.com/enthought/pyface/tree/master/examples/%s', + 'github-examples' + ) +} # Options for LaTeX output # ------------------------ @@ -159,7 +183,10 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual]). latex_documents = [ - ('index', 'TraitsGUI.tex', 'TraitsGUI Documentation', 'Enthought', 'manual'), + ( + 'index', 'TraitsGUI.tex', 'TraitsGUI Documentation', 'Enthought', + 'manual' + ), ] # The name of an image file (relative to this directory) to place at the top of @@ -178,3 +205,27 @@ # If false, no module index is generated. #latex_use_modindex = True + +# Options for autodoc +# ------------------- + +autodoc_member_order = 'bysource' + +autodoc_mock_imports = [ + 'wx', + 'wx.grid', + 'wx.html', + 'wx.lib', + 'wx.lib.scrolledpanel', + 'wx.lib.layoutf', + 'wx.lib.mixins', + 'wx.lib.mixins.grid', + 'wx.lib.wxpTag', + 'wx.lib.gridmovers', + 'wx.stc', + 'wx.py', + 'IPython', + 'IPython.frontend', + 'IPython.frontend.wx', + 'IPython.frontend.wx.wx_frontend', +] diff -Nru python-pyface-4.5.2/docs/source/fields.rst python-pyface-6.1.2/docs/source/fields.rst --- python-pyface-4.5.2/docs/source/fields.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/fields.rst 2019-05-03 11:52:40.000000000 +0000 @@ -0,0 +1,63 @@ +====== +Fields +====== + +Pyface provides a small collection of simple field widgets that are pre-bound +to a Traits interface, so that you can use them in a cross-toolkit manner. + +Where possible, these classes share a common API for the same functionality. +In particular, all classes have a +:py:attr:`~pyface.fields.i_field.IField.value` trait which holds the (usually +user-editable) value displayed in the field. Code using the field can listen +to changes in this trait to react to the user entering a new value for the +field without needing to know anything about the underlying toolkit event +signalling mechanisms. + +All fields also provide traits for setting the +:py:attr:`~pyface.fields.i_field.IField.tooltip` and +:py:attr:`~pyface.fields.i_field.IField.context_menu` of the field. Tooltips +expect unicode text values, and context menus should be +:py:class:`~pyface.action.menu_manager.MenuManager` instances. + +TextField +========= + +The :py:class:`~pyface.fields.i_text_field.ITextField` interface provides +additional traits that specify whether the value should be updated on +every keystroke (by setting +:py:attr:`~pyface.fields.i_text_field.ITextField.update_text` to ``"auto"``) +or when the user has finished editing the field by moving focus away from +the text field (by setting +:py:attr:`~pyface.fields.i_text_field.ITextField.update_text` to +``"editing_finshed"``). + +The text field can be set to show a placeholder text to hint about the desired +value that is shown when the box is empty via the +:py:attr:`~pyface.fields.i_text_field.ITextField.placeholder` trait. It can +also be set to conceal typed text by setting +:py:attr:`~pyface.fields.i_text_field.ITextField.echo` to ``"password"`` (and +the Qt backend has a number of other options as well). The text field can be +set to read-only mode via the +:py:attr:`~pyface.fields.i_text_field.ITextField.read_only` trait. + +SpinField +========= + +The :py:class:`~pyface.fields.i_spin_field.ISpinField` interface has an integer +for the :py:attr:`~pyface.fields.i_spin_field.ISpinField.value`, and also +requires a range to be set, either via setting the min/max values as a tuple to +the :py:attr:`~pyface.fields.i_spin_field.ISpinField.range` trait, or by setting +values individually to :py:attr:`~pyface.fields.i_spin_field.ISpinField.minimum` +and :py:attr:`~pyface.fields.i_spin_field.ISpinField.maximum`. + +ComboField +========== + +The :py:class:`~pyface.fields.i_combo_field.IComboField` interface has an arbitrary +:py:attr:`~pyface.fields.i_spin_field.IComboField.value` that must come from a list +of valid :py:attr:`~pyface.fields.i_spin_field.IComboField.values`. For non-text +values, a :py:attr:`~pyface.fields.i_spin_field.IComboField.formatter` function +should be provided - this defaults to either :py:func:`str` (Python 3+) or +:py:func:`unicode` (Python 2). + + diff -Nru python-pyface-4.5.2/docs/source/index.rst python-pyface-6.1.2/docs/source/index.rst --- python-pyface-4.5.2/docs/source/index.rst 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/docs/source/index.rst 2019-07-20 11:46:59.000000000 +0000 @@ -1,20 +1,14 @@ -Welcome to the Pyface documentation! -======================================= - -If you want to display Traits-based user interfaces, you need, in addition to -the Traits project: - - -The TraitsUI project - -A Python GUI toolkit, either wxPython or PyQt - -A "backend" connector, either TraitsBackendWX or TraitsBackendQt - -TraitsUI contains a toolkit-independent GUI abstraction layers, used to support -the "visualization" features of the Traits package. Thus, you can write code in -terms of the Traits API (view, items, editors, etc.), and let Pyface and your -selected toolkit and backend take care of the details of displaying them. +==================================== +Welcome to the Pyface Documentation! +==================================== + +Pyface contains a toolkit-independent GUI abstraction layers, used to support +the "visualization" features of the Traits package. Thus, you can write code +in the abstraction of the Pyface API and the selected toolkit and backend take +care of the details of displaying them. Pyface ------- +====== Pyface enables programmers to interact with generic GUI objects, such as an "MDI Application Window", rather than with raw GUI widgets. (Pyface is named by @@ -22,7 +16,7 @@ for displaying and editing Traits-based objects. Toolkit Backends ----------------- +================ Traits and Pyface define APIs that are independent of any GUI toolkit. However, in order to actually produce user interfaces with them, you must install a @@ -30,21 +24,62 @@ project. Conversely, if you wish to use Traits without a UI, a "null" backend is automatically used in the absence of a real backend. -Currently, the supported GUI toolkits are wxPython, PySide and PyQt. While all -toolkits funtion with Traits, integration with wxPython is currently more -complete. All future development, however, will focus on supporting Qt. +Currently, the supported GUI toolkits are -.. warning:: Currently the default toolkit if none is supplied is 'wx', but - this will change to `qt` in Pyface 5.0. +* wxPython (>= 2.8, including experimental support for WxPython 3.0) +* PySide +* PyQt (Qt4 only, but Qt5 support is in development) + +While all toolkits funtion with Pyface, integration with wxPython is currently +more complete. Future development, however, will be more focused on +supporting Qt. + +The default toolkit if none is supplied is ``qt4``. This changed from ``wx`` in +Pyface 5.0. NOTE: Although the code in this library is BSD licensed, when the PyQt backend is used the more restrictive terms of PyQt's GPL or proprietary licensing will likely apply to your code. +Toolkit Backend Selection +------------------------- + +Selecting the backend to use is possible via the singleton object **ETSConfig** +(importable from `traits.etsconfig.api`), which has a string attribute, toolkit, +that signifies the GUI toolkit. + +The supported values of **ETSConfig.toolkit** are: + +* 'qt4': `PyQt `_, which provides Python + bindings for the `Qt `_ framework version 4. +* 'wx': `wxPython `_, which provides Python bindings + for the `wxWidgets `_ toolkit. +* 'null': A do-nothing toolkit, for situations where neither of the other + toolkits is installed, but Traits is needed for non-UI purposes. + +The default behavior of Pyface is to search for available toolkit-specific +packages in the order listed, and uses the first one it finds. The programmer or +the user can override this behavior in any of several ways, in the following +order of precedence: + +#. The program can explicitly set **ETSConfig.toolkit**. It must do this before + importing from any other Enthought Tool Suite component, including + traits. For example, at the beginning of a program:: + + from traits.etsconfig.api import ETSConfig + ETSConfig.toolkit = 'wx' + +#. The user can define a value for the ETS_TOOLKIT environment variable. + Contents --------- +======== .. toctree:: :maxdepth: 2 + Overview + Toolkits + Submodules + Pyface Applications API Documentation + Change Log diff -Nru python-pyface-4.5.2/docs/source/overview.rst python-pyface-6.1.2/docs/source/overview.rst --- python-pyface-4.5.2/docs/source/overview.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/overview.rst 2019-06-14 10:36:00.000000000 +0000 @@ -0,0 +1,351 @@ +======== +Overview +======== + +Pyface Concepts +=============== + +.. py:currentmodule:: pyface + +The basic purpose of Pyface is to provide an abstraction layer between the +interface exposed to the users of the library and the actual implementation +in terms of the underlying GUI library. To achieve this, Pyface provides +three types of object: + +Interfaces + Interface classes express the public interface for Pyface widgets. They + use `Trait's Interfaces `_ + to express this. Interface objects are not meant to be instantiated, but + should be used to express the types of objects that you expect in a + toolkit-independent manner. + +Mixins + Mixin classes provide concrete implementations of certain functionality + for a widget that are not toolkit-dependent, or can be provided purely + using other parts of the abstract interface. Concrete implementations + can choose to inherit from the mixin class to use that common + functionality. + +Toolkit Implementations + Each toolkit can provide classes that are full implementations of the + abstract Interfaces using the widgets and other facilities provided by the + toolkit. + +In addition there is a class heirarchy othogonal to this specifying the +relationship between different types of widgets. A "dialog" for example, is a +subclass of "window", which is in turn a subclass of "widget". This heirarchy +roughly mirrors the typical widget class system of a GUI library, and so +presents a general framework that can be abstracted between different backends. + +For example, a file dialog is specified using the :py:class:`.IFileDialog` +interface, which in turn inherits from :py:class:`.IDialog`, +:py:class:`.IWindow`, and :py:class:`.IWidget`, and the full usable interface +is the combination of these. The :py:class:`.MFileDialog` class provides some +mix-in capabilities around the expression of filters for file types. And then +there are two concrete implementations, :py:class:`pyface.ui.wx.file_dialog.FileDialog` +for wxPython and :py:class:`pyface.ui.qt4.file_dialog.FileDialog` for the Qt +backends. These toolkit classes in turn inherit from the appropriate toolkit's +:py:class:`Dialog`, :py:class:`Window`, and :py:class:`Widget` classes, as well +as the :py:class:`.MFileDialog` mixin. + +Finally, the toolkit selected for use determines which backend class is +actually used when a program is run, allowing a developer to write code like +the following to generate a platform-independent file dialog:: + + from pyface.api import FileDialog, OK + + def open_python_file(): + """ Ask the user for a Python file to open """ + dialog = FileDialog(action='open', wildcard=FileDialog.WILDCARD_PY) + result = dialog.open() + if result == OK: + return dialog.path + else: + return None + +There is a lot more to the library than just this, of course, but with this +framework in mind you can understand how Pyface is intended to be used. + + +Building A Pyface Application +============================= + +For a minimal Pyface application, you need to do two things: create a subclass +of :py:class:`.ApplicationWindow` containing your UI, +and use the :py:class:`pyface.gui.GUI` instance to start your application's +mainloop. + +This example shows how to create an application window containing a simple text +label:: + + from pyface.api import ApplicationWindow, HeadingText + + class MainWindow(ApplicationWindow): + """ The main application window. """ + + # The window title. + title = 'Hello World' + + def _create_contents(self, parent): + """ Create the editor. """ + + self._label = HeadingText(parent, text="Hello World") + + return self._label.control + +The :py:class:`.IApplicationWindow` interface also allows you to provide +methods for creating menus, toolbars, and so forth. In this example we have +used a generic cross-toolkit label widget for our content, but if we are +willing to forgo cross-platform compatibility we could create toolkit-specific +widgets instead. + +Having defined your main window class, you then need to create an instance of +it, open it, and start the event loop. We do this in a ``main()`` function +for our application:: + + from pyface.api import GUI + + def main(): + # Create the GUI. + gui = GUI() + + # Create and open the main window. + window = MainWindow() + window.open() + + # Start the GUI event loop! + gui.start_event_loop() + + + # Application entry point. + if __name__ == '__main__': + main() + +Actions +======= + +.. py:currentmodule:: pyface.action + +An immediate desire when building a traditional GUI application is to add +menus and toolbars to allow basic user interaction via the mouse or keyboard +shortcuts. Pyface provides these via :py:class:`~.action.Action` objects. + +Actions provide the information needed to display a menu or toolbar item and +such as the title text, accelerator keys, icon and whether the action has +"radio" or "toggle" behaviour. In addition the action needs to supply a +function to perform when the user activates it. This is usually done by +either supplying a callable for the :py:attr:`~.action.Action.on_perform` trait of the +:py:class:`~.action.Action` or by subclassing and overriding the :py:meth:`~.action.Action.perform` +method. + +The :py:attr:`~.action.Action.on_perform` is a callable that should expect no parameters to +be passed to it, so it should have all the context it needs to do what it +needs. At its simplest, the action might look something like this:: + + from pyface.action.api import Action + + def hello_world(): + print 'Hello world!' + + hello_action = Action( + name="Hello", + tooltip="Say hello", + accelerator="Ctrl+Shift+H", + on_perform=hello_world, + ) + +The equivalent written as a subclass of :py:class:`~.action.Action` would look like +this:: + + from pyface.action.api import Action + + class HelloAction(Action): + + #: The action's name (displayed on menus/tool bar tools etc). + name = "Hello" + + #: Keyboard accelerator. + accelerator = "Ctrl+Shift+H" + + #: A short description of the action used for tooltip text etc. + tooltip = "Say hello" + + def perform(self, event=None): + print 'Hello world!' + +Because actions usually require some context, the most common use will be to +supply a class method as the :py:attr:`~.action.Action.on_perform` callable. And for toolbar +actions, you usually want to supply an :py:attr:`~.action.Action.image` trait as well. + +Actions can be organized hierarchically into groups within menus and toolbars, +and a menubar can contain multiple menus. The following example shows how to +define a very simple Python editor application with menus:: + + class MainWindow(ApplicationWindow): + """ The main application window. """ + + def __init__(self, **traits): + """ Creates a new application window. """ + + # Base class constructor. + super(MainWindow, self).__init__(**traits) + + # Add a menu bar. + self.menu_bar_manager = MenuBarManager( + MenuManager( + Group( + Action( + name='&Open...', + accelerator='Ctrl+O', + on_perform=self.open_file + ), + Action( + name='&Save', + accelerator='Ctrl+S', + on_perform=self.save_file + ), + id='document_group', + ), + Action( + name='&Close', + accelerator='Ctrl+W', + on_perform=self.close + ), + name='&File') + ) + + def open_file(self): + """ Open a new file. """ + + if self.control: + dlg = FileDialog(parent=self.control, wildcard="*.py") + + if dlg.open() == OK: + self._editor.path = dlg.path + + def save_file(self): + """ Save the file. """ + + if self.control: + try: + self._editor.save() + except IOError, e: + # If you are trying to save to a file that doesn't exist, + # open up a FileDialog with a 'save as' action. + dlg = FileDialog( + parent=self.control, + action='save as', + wildcard="*.py") + if dlg.open() == OK: + self._editor.save(dlg.path) + + def _create_contents(self, parent): + """ Create the editor. """ + + self._editor = PythonEditor(parent) + + return self._editor.control + +Toolbars +-------- + +Toolbars work in a similar way to menus, each toolbar having a collection of +groups of actions. However in addition to the options available to a menu +item, a toolbar item can have an :py:class:`~.action.Action` that provides a widget +to embed in the toolbar. At its simplest this is done by specifying the +:py:attr:`~.action.Action.style` to be ``"widget"`` and then providing a +:py:attr:`~.action.Action.control_factory` callable that returns a toolkit object. + +There are two utility subclasses provided to handle common use cases. The +:py:class:`~.field_action.FieldAction` class takes a +:py:class:`~pyface.fields.i_field.IField` class and a dictionary of parameters +that specify the behaviour, and use this as the factory to create the +embedded widget. :py:class:`~.field_action.FieldAction` also overrides the +:py:attr:`~.field_action.FieldAction.perform` method to pass the new value of the field +to the :py:class:`~.field_action.FieldAction.on_perform` method. + +The second is the :py:class:`~.traitsui_widget_action.TraitsUIWidgetAction` +class which embeds an arbitrary TraitsUI in the toolbar. + + +Application Frameworks +====================== + +Pyface provides two application frameworks that help in building complex, +composable interfaces for applications. The first is Workbench, which is an +older framework; the second is Tasks, which is newer and more flexible than +Workbench. The Tasks framework is under active support, while Workbench is a +legacy codebase. + +For new projects, it's recommended that developers should use Tasks if they +need such an application framework. + +Both these frameworks are designed to be extensible using Envisage plugins, +and are currently documented as part of the Envisage project's documentation. + +* `Workbench `_ + +* `Tasks `_ + +Examples of building simple applications in each framework are provided in the +Pyface examples, and the APIs are auto-documented in these documents. + + +Pyface and TraitsUI +=================== + +Pyface is generally a lower-level GUI toolkit than TraitsUI, and many users +will find that TraitsUI provides all that they need. TraitsUI uses Pyface +for some of its functionality, and the Workbench and Tasks are designed to +easily incoprorate UIs built using TraitsUI. + +It is fairly straightforward to use or embed a TraitsUI view into a Pyface +widget: the basic approach is to call :py:meth:`edit_traits` with +``kind='panel'`` from inside the :py:meth:`_create_control` method (or +equivalent, like :py:meth:`_create_contents` when embedding in a window +or dialog) of the widget, extract the toolkit control from the resulting +:py:obj:`ui` object, and return or embed that control. + +For example, to embed a TraitsUI View in an :py:class:`ApplicationWindow`, +you might do something like this:: + + class Person(HasTraits): + """ Model class representing a person """ + + #: the name of the person + name = Str + + #: the age of the person + age = Int(18) + + #: the gender of the person + gender = Enum('female', 'male') + + # a default traits view + view = View( + Item('name', resizable=True), + Item('age', resizable=True), + Item('gender', resizable=True), + resizable=True, + ) + + + class MainWindow(ApplicationWindow): + """ The main application window. """ + + # The size of the window. + size = (320, 240) + + # The window title. + title = 'TraitsUI Person' + + # The traits object to display + person = Instance(Person, ()) + + def _create_contents(self, parent): + """ Create the editor. """ + self._ui = self.person.edit_traits(kind='panel', parent=parent) + return self._ui.control + +A similar approach can be used when working with Enaml, Matplotlib, or other +libraries which can produce a toolkit-specific control. diff -Nru python-pyface-4.5.2/docs/source/_static/default.css python-pyface-6.1.2/docs/source/_static/default.css --- python-pyface-4.5.2/docs/source/_static/default.css 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/docs/source/_static/default.css 2019-05-03 08:18:49.000000000 +0000 @@ -14,7 +14,7 @@ /* :::: LAYOUT :::: */ div.document { - background-color: #24326e; + background-color: #4289c9; } div.documentwrapper { @@ -44,7 +44,7 @@ p.logo { text-align: center; -} +} div.clearer { clear: both; Binary files /tmp/tmpeOISu5/RSokF2bCTe/python-pyface-4.5.2/docs/source/_static/e-logo-rev.jpg and /tmp/tmpeOISu5/LYlXeN4e5T/python-pyface-6.1.2/docs/source/_static/e-logo-rev.jpg differ Binary files /tmp/tmpeOISu5/RSokF2bCTe/python-pyface-4.5.2/docs/source/_static/e-logo-rev.png and /tmp/tmpeOISu5/LYlXeN4e5T/python-pyface-6.1.2/docs/source/_static/e-logo-rev.png differ Binary files /tmp/tmpeOISu5/RSokF2bCTe/python-pyface-4.5.2/docs/source/_static/et.ico and /tmp/tmpeOISu5/LYlXeN4e5T/python-pyface-6.1.2/docs/source/_static/et.ico differ Binary files /tmp/tmpeOISu5/RSokF2bCTe/python-pyface-4.5.2/docs/source/_static/et.png and /tmp/tmpeOISu5/LYlXeN4e5T/python-pyface-6.1.2/docs/source/_static/et.png differ diff -Nru python-pyface-4.5.2/docs/source/submodules.rst python-pyface-6.1.2/docs/source/submodules.rst --- python-pyface-4.5.2/docs/source/submodules.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/submodules.rst 2019-05-03 11:52:40.000000000 +0000 @@ -0,0 +1,9 @@ +========== +Submodules +========== + +.. toctree:: + :maxdepth: 2 + + Fields + Timers diff -Nru python-pyface-4.5.2/docs/source/timer.rst python-pyface-6.1.2/docs/source/timer.rst --- python-pyface-4.5.2/docs/source/timer.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/timer.rst 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,189 @@ +====== +Timers +====== + +Pyface provides a unified interface for toolkit timers. There are two levels +to this inferface: a simple functional interface for simple single-shot +deferred callbacks, and a more complex interface for application-level timers +such as heartbeats and periodic monitors. + +It is worth remembering that timers are only as accurate as the underlying +toolkit and operating system permit; in particular the toolkits usually +guarantee that they will be called no sooner than any specified delay, but +they may be called much later (eg. worst case, if an operating system sleep +occurs between a timer being set and being run, the delay can be arbitrarily +long). + +Functional Interface +==================== + +The basic functional interface is found in :py:mod:`pyface.timer.do_later`. +This provides two functions :py:func:`~pyface.timer.do_later.do_later` and +:py:func:`~pyface.timer.do_later.do_after`. These two functions behave in +essentially the same way, expecting a callback with arguments to be performed +once at some later time, the difference being that +:py:mod:`~pyface.timer.do_later.do_later` hard-codes the time to be 50 +milliseconds. + +.. code-block:: python + + import datetime + from pyface.timer.api import do_after, do_later + + DEFAULT_DELTA = datetime.timedelta(milliseconds=50) + + def report_time(time_started, expected_delay=DEFAULT_DELTA): + time_now = datetime.datetime.utcnow() + + print("Time started: {}".format(time_started)) + print("Time now: {}".format(time_now)) + print("Expected delay: {}".format(expected_delay)) + print("Actual delay: {}".format(time_now - time_started)) + + now = datetime.utcnow() + delay=datetime.timedelta(seconds=10) + do_after(10 * 1000, report_time, now, expected_delay=delay) + + now = datetime.utcnow() + do_later(report_time, now) + +.. note:: + For historical reasons, the :py:mod:`pyface.timer.do_later` API expects + times to be specified in milliseconds instead of seconds. + +An alternative functional interface with similar capabilties is available via +the :py:meth:`pyface.timer.timer.CallbackTimer.single_shot` class method. + + +Timer Classes +============= + +For more complex needs, the :py:mod:`pyface.timer.timer` module provides a +base timer class and several convenience subclasses for common use cases. + + +PyfaceTimer +----------- + +The :py:class:`pyface.timer.timer.PyfaceTimer` is a base class that can be +subclassed by providing a :py:meth:`~pyface.timer.timer.PyfaceTimer._perform` +method. + +.. code-block:: python + + import datetime + from pyface.timer.api import PyfaceTimer + + class CustomTimer(PyfaceTimer): + + def _perform(self): + print("The time is {}".format(datetime.datetime.now())) + +:py:class:`~pyface.timer.timer.PyfaceTimer` and its subclasses provide a +number of traits and methods to control the frequency and number of times the +timer performs its action. The most important of these is +:py:attr:`~pyface.timer.timer.PyfaceTimer.interval` which determines the time +until the first call and between any subsequent calls. + +Timers are explicitly started by explicitly calling their +:py:meth:`~pyface.timer.timer.PyfaceTimer.start` method, or by setting their +:py:attr:`~pyface.timer.timer.PyfaceTimer.active` trait to ``True``. By +default, the timer will repeat indefinately until it is explicitly +halted via :py:meth:`~pyface.timer.timer.PyfaceTimer.stop` or setting +:py:attr:`~pyface.timer.timer.PyfaceTimer.active` trait to ``False`` (or by the +application shutting down). + +Rather than controlling the active state of the timer explicitly, the number of +invocations of the :py:meth:`~pyface.timer.timer.PyfaceTimer.perfom` method can +be controlled either via setting the +:py:attr:`~pyface.timer.timer.PyfaceTimer.repeat` trait to an explicit number +of times to repeat and/or setting the +:py:attr:`~pyface.timer.timer.PyfaceTimer.expire` trait to a maximum number of +seconds for the timer to run (which could potentially mean that the timer never +gets performed). + +For example, a timer which repeats every 0.5 seconds and runs no more than 10 +times and for no longer than 10 seconds can be started like this: + +.. code-block:: python + + timer = CustomTimer(interval=0.5, repeat=10, expire=10) + timer.start() + +:py:class:`~pyface.timer.timer.PyfaceTimer` also provides two convenience class +methods for creating and starting a timer in one line. The above example +could instead be written as:: + +.. code-block:: python + + timer = CustomTimer.timer(interval=0.5, repeat=10, expire=10) + +For the common case of a "single-shot" timer that is only performed once, +there is the :py:meth:`~pyface.timer.timer.PyfaceTimer.single_shot` class +method that creates a timer that will be called once after the specified +interval:: + +.. code-block:: python + + CustomTimer.single_shot(interval=0.5) + +.. note:: + + To avoid the Python timer objects being garbage-collected prematurely, + references are kept to all active timers by Pyface. This means that you + can safely create timers without having to explicitly hold a long-term + reference to them if you do not need it for other reasons. + + +CallbackTimer +------------- + +Rather than subclassing :py:class:`~pyface.timer.timer.PyfaceTimer` for every +timer that you want, it is often enough to supply a callback function (possibly +with arguments) to be called by the timer. Pyface provides the +:py:class:`~pyface.timer.timer.CallbackTimer` class for this purpose. + +This class is meant to be directly instantiated, providing at a minimum a +callable value for the :py:attr:`~pyface.timer.timer.CallbackTimer.callback` +trait, along with an optional tuple of +:py:attr:`~pyface.timer.timer.CallbackTimer.args` and/or optional dict of +:py:attr:`~pyface.timer.timer.CallbackTimer.kwargs`. + +.. code-block:: python + + from pyface.timer.api import CallbackTimer + + def print_time(): + print("The time is {}".format(datetime.datetime.now())) + + CallbackTimer.timer(callback=print_time, interval=0.5, expire=60) + + +EventTimer +---------- + +Another common use case is that you want a Traits Event to be fired +periodically or at some future time. This permits many possible listeners +to be called from the same timer, and have them be turned on and turned off +dynamically, if desired. The :py:class:`~pyface.timer.timer.EventTimer` +provides this functionality via its +:py:class:`~pyface.timer.timer.EventTimer.timeout` event trait. + +.. code-block:: python + + from pyface.timer.api import EventTimer + + timer = EventTimer(interval=0.5, expire=60) + timer.on_trait_change(print_time, 'timeout') + + timer.start() + +The :py:class:`~pyface.timer.timer.EventTimer` class is particularly suited to +be used as an application "heartbeat" that arbitrary code can hook into to be +run periodically without having to create its own timer. + +Deprecated Classes +------------------ + +Pyface also provides a deprecated :py:class:`~pyface.timer.timer.Timer` +class for backwards compatability. This class shouldn't be used in new code. \ No newline at end of file diff -Nru python-pyface-4.5.2/docs/source/toolkits.rst python-pyface-6.1.2/docs/source/toolkits.rst --- python-pyface-4.5.2/docs/source/toolkits.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/docs/source/toolkits.rst 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,99 @@ +======== +Toolkits +======== + +Pyface is intended to provide a common API on top of distinct GUI backends to +permit the same code to be run on different systems with different GUI +toolkits and produce similar results. Pyface comes with three built-in +backends in the core library---Qt, WxPython, and a null backend---but provides +hooks for other projects to contribute toolkits and have them be discoverable. + +Toolkit Selection +================= + +Pyface uses Traits' :py:mod:`traits.etsconfig` to determine the current +toolkit being used. Applications can control which toolkit to use in two +ways: + +- by setting the environment variable ``ETS_TOOLKIT`` to the name of the + desired toolkit. +- by importing :py:obj:`ETSConfig` and setting its :py:attr:`toolkit` + attribute appropriately:: + + from tratis.etsconfig.api import ETSConfig + ETSConfig.toolkit = 'qt4' + + This must be done _before_ any widget imports in your application, including + importing :py:mod:`pyface.api`. Precisely, this must be set before the + first import of :py:mod:`pyface.toolkit`. + +If for some reason Pyface can't load a deliberately specified toolkit, then it +will raise an exception. + +If the toolkit is not specified, Pyface will try to load the ``qt4`` or ``wx`` +toolkits, in that order, and then any other toolkits that it knows about +other than ``null``. If all of those fail, then it will try to load the +``null`` toolkit. + +Once selected, the toolkit infrastructure is largely transparent to the +application. + +Toolkit Objects +=============== + +The selection of the correct backend object is carried out by each toolkit's +toolkit object. For all built-in toolkits, this is an instance of the +:py:class:`pyface.base_toolkit.Toolkit` class, but it is possible that other +backends may use their own objects. The toolkit object for the toolkit that +has been selected can be found as :py:obj:`pyface.toolkit.toolkit_object`. + +This is a callable object which expects to be given the an identifier for the +widget in the form of a relative module name and the object name, separated by +a ``':'``. This is most often used when creating new widget types for Pyface. +The API module for the new widget class typically looks something like this:: + + from pyface.toolkit import toolkit_object + MyWidget = toolkit_object('my_package.my_widget:MyWidget') + +The base toolkits use the identifier to select which module to import the +toolkit object by constructing a full module path from the partial path and +importing the object. For example the ``qt4`` backend will look for the +concrete implementation in :py:mod:`pyface.ui.qt4.my_package.my_widget` +while the ``wx`` backend will look for +:py:mod:`pyface.ui.wx.my_package.my_widget`. + +If no matching object is found, the toolkit will return a special +:py:class:`Undefined` class that will raise :py:exception:`NotImplementedError` +when instantiated. + +The basic toolkit implementation provides two other features which may be of +use. It has a trait that gives the name of the toolkit, and it has a list of +packages that it searches when trying to import a toolkit object. This +second trait provides a hook where an application can insert other packages +into the search path to override the default implementations of a toolkit's +widgets, if needed. + +Toolkit Entrypoints +=================== + +Pyface uses the standard ``pkg_resources`` "entry point" system to allow other +libraries to contribute new toolkit implementations to Pyface. The toolkit +selection process discussed above looks for things contributed to the +``pyface.toolkits`` entry point. These are specified in the ``setup.py`` of +the third party library, something like this:: + + setup( + # ... a bunch of other standard setup.py stuff + entry_points = { + 'pyface.toolkits': [ + 'my_toolkit = my_project.my_toolkit.init:toolkit_object', + ] + } + ) + +The left-hand side is the name of the toolkit, suitable for use with +:py:obj:`ETSConfig`, and the right-hand side is the location of a toolkit +object which matches the specification above: a callable object which takes +identifiers as specified and returns concrete implementations. The easiest +way to do this is to follow the examples of the current toolkits and use +a :py:class:`pyface.base_toolkit.Toolkit` instance, but this is not required. diff -Nru python-pyface-4.5.2/doc-src-requirements.txt python-pyface-6.1.2/doc-src-requirements.txt --- python-pyface-4.5.2/doc-src-requirements.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/doc-src-requirements.txt 2019-05-03 13:53:35.000000000 +0000 @@ -0,0 +1 @@ +git+http://github.com/enthought/enthought-sphinx-theme.git#egg=enthought_sphinx_theme diff -Nru python-pyface-4.5.2/examples/application/hello_world/hello_application.py python-pyface-6.1.2/examples/application/hello_world/hello_application.py --- python-pyface-4.5.2/examples/application/hello_world/hello_application.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/application/hello_world/hello_application.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,64 @@ +# Copyright (c) 2018 by Enthought, Inc., Austin, TX +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +""" +Example Command-Line Application +================================ + +This is an example of an application used in purely command-line mode. +The application itself is trivial, but it demonstrates how to use the +Application class by overriding the `_run` method to perform the desired +computation. +""" + +from __future__ import print_function + +import argparse +from pyface.application import Application +from traits.api import Str + + +class HelloApplication(Application): + """ Simple application example that greets a location. """ + + # 'HelloApplication' traits ----------------------------------------------- + + #: The location being greeted. + location = Str("world") + + # 'Application' traits ---------------------------------------------------- + + #: Human-readable application name + name = "Hello Application" + + #: The application's globally unique identifier. + id = "example_hello_application" + + def _run(self): + super(HelloApplication, self)._run() + print("Hello " + self.location) + + +def main(): + """ Hello application entrypoint. """ + app = HelloApplication() + + parser = argparse.ArgumentParser(description=app.description) + parser.add_argument( + 'location', + nargs='?', + default=app.location, + help="the location to greet", + ) + parser.parse_args(namespace=app) + + app.run() + + +if __name__ == '__main__': + main() Binary files /tmp/tmpeOISu5/RSokF2bCTe/python-pyface-4.5.2/examples/application/python_editor/images/document_new.png and /tmp/tmpeOISu5/LYlXeN4e5T/python-pyface-6.1.2/examples/application/python_editor/images/document_new.png differ Binary files /tmp/tmpeOISu5/RSokF2bCTe/python-pyface-4.5.2/examples/application/python_editor/images/document_open.png and /tmp/tmpeOISu5/LYlXeN4e5T/python-pyface-6.1.2/examples/application/python_editor/images/document_open.png differ Binary files /tmp/tmpeOISu5/RSokF2bCTe/python-pyface-4.5.2/examples/application/python_editor/images/document_save.png and /tmp/tmpeOISu5/LYlXeN4e5T/python-pyface-6.1.2/examples/application/python_editor/images/document_save.png differ diff -Nru python-pyface-4.5.2/examples/application/python_editor/images/image_LICENSE.txt python-pyface-6.1.2/examples/application/python_editor/images/image_LICENSE.txt --- python-pyface-4.5.2/examples/application/python_editor/images/image_LICENSE.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/application/python_editor/images/image_LICENSE.txt 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,18 @@ +The icons are mostly derived work from other icons. As such they are +licensed accordingly to the original license: + +Project License File +---------------------------------------------------------------------------- +PSF Trademark https://www.python.org/community/logos/ +Oxygen CC-SA 3.0 http://creativecommons.org/licenses/by-sa/3.0/ + +Unless stated in this file, icons are the work of Enthought, and are +released under a 3 clause BSD license. + +Files and orginal authors: +---------------------------------------------------------------------------- + document_new.png | Oxygen + document_open.png | Oxygen + document_save.png | Oxygen + python_icon.png | PSF + python_logo.png | PSF Binary files /tmp/tmpeOISu5/RSokF2bCTe/python-pyface-4.5.2/examples/application/python_editor/images/python_icon.png and /tmp/tmpeOISu5/LYlXeN4e5T/python-pyface-6.1.2/examples/application/python_editor/images/python_icon.png differ Binary files /tmp/tmpeOISu5/RSokF2bCTe/python-pyface-4.5.2/examples/application/python_editor/images/python_logo.png and /tmp/tmpeOISu5/LYlXeN4e5T/python-pyface-6.1.2/examples/application/python_editor/images/python_logo.png differ diff -Nru python-pyface-4.5.2/examples/application/python_editor/python_browser_pane.py python-pyface-6.1.2/examples/application/python_editor/python_browser_pane.py --- python-pyface-4.5.2/examples/application/python_editor/python_browser_pane.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/application/python_editor/python_browser_pane.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,43 @@ +# Standard library imports. +import os.path + +# Enthought library imports. +from pyface.tasks.api import TraitsDockPane +from traits.api import Event, File, List, Str +from traitsui.api import View, Item, FileEditor + + +class PythonBrowserPane(TraitsDockPane): + """ A simple Python file browser pane. + """ + + # FileBrowserPane interface ---------------------------------------------- + + # Fired when a file is double-clicked. + activated = Event + + # The list of wildcard filters for filenames. + filters = List(Str, ['*.py']) + + # The currently selected file. + selected_file = File(os.path.expanduser('~')) + + # TaskPane interface ----------------------------------------------------- + + id = 'example.python_browser_pane' + name = 'File Browser' + + # The view used to construct the dock pane's widget. + view = View( + Item( + 'selected_file', + editor=FileEditor( + dclick_name='activated', + filter_name='filters', + root_path=os.path.expanduser('~'), + ), + style='custom', + show_label=False + ), + resizable=True, + ) diff -Nru python-pyface-4.5.2/examples/application/python_editor/python_editor_application.py python-pyface-6.1.2/examples/application/python_editor/python_editor_application.py --- python-pyface-4.5.2/examples/application/python_editor/python_editor_application.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/application/python_editor/python_editor_application.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,71 @@ +# Copyright (c) 2014-18 by Enthought, Inc., Austin, TX +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +""" +Example Tasks Application +========================= + +This is a Tasks application to demonstrate a vary basic multi-tab, +multi-window editor. The application is very thin, since all we need to do +is supply the task factory for the Python editor task. More sophisticated +applications may need to subclass the application class to hold +application-global state and provide application-global functionality. +""" + +import argparse + +from pyface.tasks.api import TaskFactory, TasksApplication + +from python_editor_task import PythonEditorTask + + +def main(): + """ Main entrypoint for the application. """ + + app = TasksApplication( + id="example_python_editor_application", + name="Python Editor", + description=( + "An example Tasks application that provides a Python editor." + ), + icon='python_icon', + logo='python_logo', + task_factories=[ + TaskFactory( + id='example.python_editor_task', + name="Python Editor", + factory=PythonEditorTask + ) + ], + ) + + # get file names from arguments + parser = argparse.ArgumentParser(description=app.description) + parser.add_argument( + 'files', + nargs='*', + help="the files to open", + ) + namespace = parser.parse_args() + if len(namespace.files) == 0: + namespace.files.append(u'') + + # set up callback to open files once app is up and running + def open_files(): + """ Open files once app is active. """ + for path in namespace.files: + app.active_task.create_editor(path) + + app.on_trait_change(open_files, 'application_initialized') + + # invoke the mainloop + app.run() + + +if __name__ == '__main__': + main() diff -Nru python-pyface-4.5.2/examples/application/python_editor/python_editor.py python-pyface-6.1.2/examples/application/python_editor/python_editor.py --- python-pyface-4.5.2/examples/application/python_editor/python_editor.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/application/python_editor/python_editor.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,243 @@ +# Copyright (c) 2014-18 by Enthought, Inc., Austin, TX +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +""" +Example Python Editor +===================== + +This is a TraitsUI-based Tasks Editor that edits a Python file using the +standard TraitsUI CodeEditor. Most of the code handles loading and saving +of text, and binding traits to the code editor to give user feedback, but +this editor also demonstrates how to expose TraitsUI's undo/redo mechanisms +and use that to tell whether the file needs to be saved or not. +""" + +import os +from io import open + +from pyface.tasks.api import TraitsEditor +from traits.api import ( + Bool, File, HasStrictTraits, Int, Property, Unicode, cached_property +) +from traitsui.api import ( + CodeEditor, Item, OKCancelButtons, RangeEditor, UndoHistory, View +) + + +class LineNumberDialog(HasStrictTraits): + """ A simple line number dialog. """ + + #: The total number of lines. + max_line = Int + + #: The entered line. + line = Int + + traits_view = View( + Item( + "line", + label=u'Line Number:', + editor=RangeEditor(low=1, high_name='max_line', mode='spinner'), + ), + buttons=OKCancelButtons, + ) + + +class PythonEditor(TraitsEditor): + """ Tasks Editor that provides a code editor via TraitsUI """ + + #: The Python code being edited. + code = Unicode + + #: Whether or not undo operation is possible. + can_undo = Property(Bool, depends_on='ui.history.undoable') + + #: Whether or not redo operation is possible. + can_redo = Property(Bool, depends_on='ui.history.redoable') + + #: The current cursor line. + line = Int(1) + + #: The current cursor column. + column = Int(1) + + #: The currently selected text, if any. + selection = Unicode + + #: The length of the currently selected text. + selection_length = Property(Int, depends_on='selection') + + #: The start of the currently selected text, if any. + selection_start = Int + + #: The end of the currently selected text, if any. + selection_end = Int + + #: The position of the last save in the history. + _last_save = Int + + # IEditor traits --------------------------------------------------------- + + #: The file being edited. + obj = File + + #: The editor's user-visible name. + name = Property(Unicode, depends_on='obj') + + #: The tooltip for the editor. + tooltip = Property(Unicode, depends_on='obj') + + dirty = Property(Bool, depends_on=['obj', '_last_save', 'ui.history.now']) + + # ------------------------------------------------------------------------- + # PythonTextEditor interface + # ------------------------------------------------------------------------- + + def load(self, path=None): + """ Load text from a path, or set text empty if no path. + + This method uses the default encoding for io.open, which may or may + not make sense; a real, robust editor should use tokenize.open or + equivalent to detect file encodings. + + Parameters + ---------- + path : path or '' or None + The path of the file to load. If the path is None, use the path + providied via self.obj. + """ + if path is None: + path = self.obj + + if path: + with open(path) as fp: + self.code = fp.read() + self.obj = path + else: + self.code = u"" + + if self.ui is not None: + # reset history + self.ui.history = UndoHistory() + self._last_save = 0 + + def save(self, path=None): + """ Load text from a path, or set text empty if no path. + + This method uses the default encoding for io.open, which may or may + not make sense; a real, robust editor should detect the encoding + using the mechanisms described in `PEP 263 + `_. + + Parameters + ---------- + path : path or '' or None + The path of the file to load. If the path is None, use the path + providied via self.obj. + """ + if path is None: + path = self.obj + + with open(path) as fp: + fp.write(self.code) + + if self.ui is not None: + # update save marker + self._last_save = self.ui.history.now + + def go_to_line(self): + """ Ask the use for a line number and jump to that line. """ + max_line = len(self.code.splitlines()) + 1 + dialog = LineNumberDialog(max_line=max_line, line=self.line) + ui = dialog.edit_traits(kind='livemodal') + if ui.result: + self.column = 1 + self.line = dialog.line + + def undo(self): + """ Undo an operation. """ + if self.ui is not None and self.ui.history is not None: + self.ui.history.undo() + + def redo(self): + """ Redo an operation. """ + if self.ui is not None and self.ui.history is not None: + self.ui.history.redo() + + def create(self, parent): + """ Create and set the toolkit-specific contents of the editor. + """ + super(PythonEditor, self).create(parent) + self.ui.history = UndoHistory() + self._last_save = 0 + + # ------------------------------------------------------------------------- + # HasTraits interface + # ------------------------------------------------------------------------- + + def _get_dirty(self): + """ Whether or not the editor is matches saved data. + + This is True if there is no file path, or history is not at last + save point. + """ + return self.obj == '' or self._last_save != self.ui.history.now + + def _get_can_undo(self): + """ Whether or not undo operations can be performed. + """ + if self.ui is not None and self.ui.history is not None: + return self.ui.history.can_undo + return False + + def _get_can_redo(self): + """ Whether or not redo operations can be performed. + """ + if self.ui is not None and self.ui.history is not None: + return self.ui.history.can_redo + return False + + @cached_property + def _get_selection_length(self): + return len(self.selection) + + @cached_property + def _get_name(self): + """ The current name for the editor. + + Either the last component of the path + """ + if self.obj: + return os.path.basename(self.obj) + else: + return "untitled.py" + + @cached_property + def _get_tooltip(self): + """ The tooltip for the editor tab. + + The full path name or "untitiled.py". + """ + if self.obj: + return self.obj + else: + return "untitled.py" + + traits_view = View( + Item( + 'code', + show_label=False, + editor=CodeEditor( + selected_text='selection', + selected_start_pos='selection_start', + selected_end_pos='selection_end', + line='line', + column='column', + ) + ), + ) diff -Nru python-pyface-4.5.2/examples/application/python_editor/python_editor_task.py python-pyface-6.1.2/examples/application/python_editor/python_editor_task.py --- python-pyface-4.5.2/examples/application/python_editor/python_editor_task.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/application/python_editor/python_editor_task.py 2019-07-20 11:46:59.000000000 +0000 @@ -0,0 +1,363 @@ +# Copyright (c) 2014-18 by Enthought, Inc., Austin, TX +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +""" +Example Python Editor Task +========================== + +This is a Task that provides an editor pane and file browser, along with +support for opening and editing Python files. Much of this class is simply +creating and hooking up menus and toolbars to appropriate methods, but the +task also handles checking for unsaved files before closing and updating +window name and status bar depending on the state of the task and editor. +""" + +import os +import sys +import webbrowser + +from pyface.api import ( + CANCEL, ConfirmationDialog, FileDialog, ImageResource, OK, YES, error +) +from pyface.action.api import Action, StatusBarManager +from pyface.tasks.api import ( + EditorAreaPane, IEditor, IEditorAreaPane, PaneItem, Task, TaskLayout +) +from pyface.tasks.action.api import ( + DockPaneToggleGroup, EditorAction, SGroup, SMenu, SMenuBar, SToolBar, + TaskAction +) +from traits.api import ( + Instance, Property, Unicode, cached_property, on_trait_change +) + +from python_browser_pane import PythonBrowserPane +from python_editor import PythonEditor + +PYTHON_DOCS = 'https://docs.python.org/{}.{}'.format(*sys.version_info[:2]) + + +class OpenURLAction(Action): + """ An action that opens a web page in the system's default browser. """ + + #: The URL to open. + url = Unicode + + def perform(self, event=None): + """ Open a URL in a web browser. """ + try: + webbrowser.open(self.url) + except webbrowser.Error as exc: + error(None, str(exc)) + + +class PythonEditorTask(Task): + """ A simple task for editing Python code. + """ + + # 'Task' traits ----------------------------------------------------------- + + #: The unique id of the task. + id = 'example.python_editor_task' + + #: The human-readable name of the task. + name = u"Python Editor" + + #: The currently active editor in the editor area, if any. + active_editor = Property( + Instance(IEditor), depends_on='editor_area.active_editor' + ) + + #: The editor area for this task. + editor_area = Instance(IEditorAreaPane) + + #: The menu bar for the task. + menu_bar = SMenuBar( + SMenu( + SGroup( + TaskAction(name='New', method='new', accelerator='Ctrl+N'), + id='new_group', + ), + SGroup( + TaskAction( + name='Open...', method='open', accelerator='Ctrl+O' + ), + id='open_group', + ), + SGroup( + TaskAction( + name='Save', + method='save', + accelerator='Ctrl+S', + enabled_name='active_editor.dirty' + ), + TaskAction( + name='Save As...', + method='save_as', + accelerator='Ctrl+Shift+S' + ), + id='save_group', + ), + SGroup( + TaskAction( + name='Close Editor', + method='close_editor', + accelerator='Ctrl+W', + ), + id='close_group', + ), + id='File', + name='&File', + ), + SMenu( + SGroup( + EditorAction( + name='Undo', + method='undo', + enabled_name='can_undo', + accelerator='Ctrl+Z', + ), + EditorAction( + name='Redo', + method='redo', + enabled_name='can_redo', + accelerator='Ctrl+Shift+Z', + ), + id='undo_group', + ), + SGroup( + EditorAction( + name='Go to Line...', + method='go_to_line', + accelerator='Ctrl+G', + ), + id='search_group', + ), + id='Edit', + name='&Edit', + ), + SMenu( + DockPaneToggleGroup(), + id='View', + name='&View', + ), + SMenu( + SGroup( + OpenURLAction( + name='Python Documentation', + id='python_docs', + url=PYTHON_DOCS, + ), + id="documentation_group", + ), + id='Help', + name='&Help', + ) + ) + + #: The tool bars for the task. + tool_bars = [ + SToolBar( + TaskAction( + method='new', + tooltip='New file', + image=ImageResource('document_new'), + ), + TaskAction( + method='open', + tooltip='Open a file', + image=ImageResource('document_open') + ), + TaskAction( + method='save', + tooltip='Save the current file', + image=ImageResource('document_save'), + enabled_name='active_editor.dirty' + ), + image_size=(16, 16), + show_tool_names=False + ), + ] + + #: The status bar for the window when this task is active. + status_bar = Instance(StatusBarManager, ()) + + # ------------------------------------------------------------------------- + # 'PythonEditorTask' interface. + # ------------------------------------------------------------------------- + + def create_editor(self, path=''): + """ Create a new editor in the editor pane. + + Parameters + ---------- + path : path or '' + The path to the file to edit, or '' for an empty editor. + """ + if path: + path = os.path.abspath(path) + use_existing = (path != '') + self.editor_area.edit( + path, + factory=PythonEditor, + use_existing=use_existing, + ) + if path: + self.active_editor.load() + + def close_editor(self): + """ Close the active editor, or if no editors, close the Task window. + """ + if self.editor_area.active_editor is not None: + self.editor_area.remove_editor(self.editor_area.active_editor) + else: + self.window.close() + + def new(self): + """ Open a new empty window + """ + self.create_editor() + + def open(self): + """ Shows a dialog to open a Python file. + """ + dialog = FileDialog(parent=self.window.control, wildcard='*.py') + if dialog.open() == OK: + self.create_editor(dialog.path) + + def save(self): + """ Save the current file. + + If needed, this code prompts for a path. + + Returns + ------- + saved : bool + Whether or not the file was saved. + """ + editor = self.active_editor + try: + editor.save() + except IOError: + # If you are trying to save to a file that doesn't exist, open up a + # FileDialog with a 'save as' action. + dialog = FileDialog( + parent=self.window.control, + action='save as', + wildcard='*.py', + ) + if dialog.open() == OK: + editor.save(dialog.path) + else: + return False + return True + + # ------------------------------------------------------------------------- + # 'Task' interface. + # ------------------------------------------------------------------------- + + def _default_layout_default(self): + """ The default layout with the browser pane on the left. + """ + return TaskLayout( + left=PaneItem('example.python_browser_pane', width=200) + ) + + def create_central_pane(self): + """ Create the central pane: the script editor. + """ + self.editor_area = EditorAreaPane() + return self.editor_area + + def create_dock_panes(self): + """ Create the file browser and connect to its double click event. + """ + browser = PythonBrowserPane() + + def handler(path): + if os.path.isfile(path): + return self.create_editor(path) + + browser.on_trait_change(handler, 'activated') + return [browser] + + # ------------------------------------------------------------------------- + # Protected interface. + # ------------------------------------------------------------------------- + + def _prompt_for_save(self): + """ Prompts the user to save if necessary. Returns whether the dialog + was cancelled. + """ + dirty_editors = { + editor.name: editor + for editor in self.editor_area.editors + if editor.dirty and (editor.obj or editor.code) + } + if not dirty_editors: + return True + + message = 'You have unsaved files. Would you like to save them?' + dialog = ConfirmationDialog( + parent=self.window.control, + message=message, + cancel=True, + default=CANCEL, + title='Save Changes?' + ) + result = dialog.open() + if result == CANCEL: + return False + elif result == YES: + for name, editor in dirty_editors.items(): + editor.save(editor.path) + return True + + # Trait change handlers -------------------------------------------------- + + @on_trait_change('window:closing') + def _prompt_on_close(self, event): + """ Prompt the user to save when exiting. + """ + close = self._prompt_for_save() + event.veto = not close + + @on_trait_change('active_editor.name') + def _change_title(self): + """ Update the window title when the active editor changes. + """ + if self.window.active_task == self: + if self.active_editor is not None: + self.window.title = self.active_editor.name + else: + self.window.title = self.name + + @on_trait_change('active_editor.[line,column,selection_length]') + def _update_status(self): + if self.active_editor is not None: + editor = self.active_editor + if editor.selection_length: + self.status_bar.messages = [ + "Ln {}, Col {} ({} selected)".format( + editor.line, editor.column, editor.selection_length + ) + ] + else: + self.status_bar.messages = [ + "Ln {}, Col {}".format(editor.line, editor.column) + ] + else: + self.status_bar.messages = [] + + # Trait property getter/setters ------------------------------------------ + + @cached_property + def _get_active_editor(self): + if self.editor_area is not None: + return self.editor_area.active_editor + return None diff -Nru python-pyface-4.5.2/examples/application/python_shell/images/image_LICENSE.txt python-pyface-6.1.2/examples/application/python_shell/images/image_LICENSE.txt --- python-pyface-4.5.2/examples/application/python_shell/images/image_LICENSE.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/application/python_shell/images/image_LICENSE.txt 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,11 @@ +The icons are mostly derived work from other icons. As such they are +licensed accordingly to the original license: + +Project License File +---------------------------------------------------------------------------- +PSF Trademark https://www.python.org/community/logos/ + +Files and orginal authors: +---------------------------------------------------------------------------- + python_icon.png | PSF + python_logo.png | PSF Binary files /tmp/tmpeOISu5/RSokF2bCTe/python-pyface-4.5.2/examples/application/python_shell/images/python_icon.png and /tmp/tmpeOISu5/LYlXeN4e5T/python-pyface-6.1.2/examples/application/python_shell/images/python_icon.png differ Binary files /tmp/tmpeOISu5/RSokF2bCTe/python-pyface-4.5.2/examples/application/python_shell/images/python_logo.png and /tmp/tmpeOISu5/LYlXeN4e5T/python-pyface-6.1.2/examples/application/python_shell/images/python_logo.png differ diff -Nru python-pyface-4.5.2/examples/application/python_shell/python_shell_application.py python-pyface-6.1.2/examples/application/python_shell/python_shell_application.py --- python-pyface-4.5.2/examples/application/python_shell/python_shell_application.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/application/python_shell/python_shell_application.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,103 @@ +# Copyright (c) 2014-18 by Enthought, Inc., Austin, TX +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +""" +Example GUI Application +======================= + +This is an example of a Pyface GUI application. The key bulk of the work is +done by the create_python_shell_window function which creates a +PythonShellWindow instance and overrides the window's menu bar to add +additional application-level menu items. + +This also shows how to provide branding for window icons, splash-screen images +and about dialogs. +""" + +import argparse + +from pyface.api import GUIApplication +from pyface.action.api import ( + AboutAction, CloseActiveWindowAction, CreateWindowAction, ExitAction, + Group, MenuBarManager, MenuManager +) + +from python_shell_window import ( + OpenURLAction, PYTHON_DOCS, PythonShellWindow, RunFileAction +) + + +def create_python_shell_window(application, **kwargs): + """ Factory method for constructing application window instances. """ + window = PythonShellWindow(**kwargs) + + # Override the window's menubar with an enhanced one. + # One of the advantages of Tasks is that we can extend easily, rather + # than just overriding. + window.menu_bar_manager = MenuBarManager( + MenuManager( + Group( + CreateWindowAction(application=application), + id='new_group', + ), + Group( + CloseActiveWindowAction(application=application), + ExitAction(application=application), + id='close_group', + ), + name='&File', + id='File', + ), + MenuManager( + Group( + RunFileAction(window=window), + id='run_group', + ), + name='&Run', + id='Run', + ), + MenuManager( + Group( + OpenURLAction( + name='Python Documentation', + id='python_docs', + url=PYTHON_DOCS, + ), + id="documentation_group", + ), + Group( + AboutAction(application=application), + id='about_group', + ), + name='&Help', + id='Help', + ) + ) + return window + + +def main(): + """ GUI application entrypoint. """ + app = GUIApplication( + id="example_python_shell_application", + name="Python Shell", + description="An example application that provides a Python shell.", + icon='python_icon', + logo='python_logo', + window_factory=create_python_shell_window, + ) + + # handle --help etc. + parser = argparse.ArgumentParser(description=app.description) + parser.parse_args(namespace=app) + + app.run() + + +if __name__ == '__main__': + main() diff -Nru python-pyface-4.5.2/examples/application/python_shell/python_shell_window.py python-pyface-6.1.2/examples/application/python_shell/python_shell_window.py --- python-pyface-4.5.2/examples/application/python_shell/python_shell_window.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/application/python_shell/python_shell_window.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,120 @@ +# Copyright (c) 2014-18 by Enthought, Inc., Austin, TX +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +""" +Example Python Shell Window +=========================== + +This is an example of an application window subclass that contains a Pyface +Python shell. This can be used stand-alone, but is also suitable for use as +a window in a GUI application. +""" + +import sys +import webbrowser + +from pyface.api import ( + ApplicationWindow, FileDialog, ImageResource, OK, PythonShell, error +) +from pyface.action.api import ( + Action, CloseWindowAction, Group, MenuBarManager, MenuManager, + StatusBarManager, WindowAction +) +from traits.api import Instance, Unicode + +PYTHON_DOCS = 'https://docs.python.org/{}.{}'.format(*sys.version_info[:2]) + + +class RunFileAction(WindowAction): + """ Action that calls the do_run_file method of a PythonShellWindow """ + name = 'Run File...' + accelerator = 'Ctrl+R' + method = 'do_run_file' + window = Instance('PythonShellWindow') + + +class OpenURLAction(Action): + """ An action that opens a web page in the system's default browser. """ + + #: The URL to open. + url = Unicode + + def perform(self, event=None): + """ Open a URL in a web browser. """ + try: + webbrowser.open(self.url) + except webbrowser.Error as exc: + error(None, str(exc)) + + +class PythonShellWindow(ApplicationWindow): + """ An application window that displays a simple Python shell. """ + + #: The title of the window. + title = "Python Shell" + + #: The icon for the window. + icon = ImageResource("python_icon") + + #: The Python shell widget to use. + shell = Instance('pyface.i_python_shell.IPythonShell') + + def do_run_file(self): + """ Run a file selected by the user. """ + dialog = FileDialog(wildcard=FileDialog.WILDCARD_PY) + result = dialog.open() + if result == OK: + self.shell.execute_file(dialog.path) + + def _create_contents(self, parent): + """ Create the shell widget. """ + self.shell = PythonShell(parent) + return self.shell.control + + def _menu_bar_manager_default(self): + menu_bar = MenuBarManager( + MenuManager( + Group( + CloseWindowAction(window=self), + id='close_group', + ), + name='&File', + id='File', + ), + MenuManager( + Group( + RunFileAction(window=self), + id='run_group', + ), + name='&Run', + id='Run', + ), + MenuManager( + Group( + OpenURLAction( + name='Python Documentation', + id='python_docs', + url=PYTHON_DOCS, + ), + id="documentation_group", + ), + name='&Help', + id='Help', + ), + ) + return menu_bar + + def _status_bar_manager_default(self): + return StatusBarManager() + + +if __name__ == '__main__': + from pyface.api import GUI + window = PythonShellWindow() + window.open() + GUI().start_event_loop() diff -Nru python-pyface-4.5.2/examples/chained_wizard.py python-pyface-6.1.2/examples/chained_wizard.py --- python-pyface-4.5.2/examples/chained_wizard.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/chained_wizard.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,6 +13,7 @@ #------------------------------------------------------------------------------ """ Chained wizard example. """ +from __future__ import print_function # Standard library imports. import os @@ -99,8 +100,8 @@ # Open the wizard. if wizard.open() == OK: - print 'Wizard completed successfully' + print('Wizard completed successfully') else: - print 'Wizard cancelled' + print('Wizard cancelled') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/examples/dialog.py python-pyface-6.1.2/examples/dialog.py --- python-pyface-4.5.2/examples/dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -12,7 +12,7 @@ # Description: #------------------------------------------------------------------------------ """ Dialog example. """ - +from __future__ import print_function # Standard library imports. import os, sys @@ -21,8 +21,8 @@ sys.path.append(os.path.abspath(r'..\..\..')) # Enthought library imports. -from pyface.api import confirm, error, information, warning, YES -from pyface.api import ApplicationWindow, GUI +from pyface.api import (ApplicationWindow, GUI, YES, choose_one, confirm, + error, information, warning) from pyface.action.api import Action, MenuBarManager, MenuManager @@ -58,6 +58,8 @@ parent = self.control + print(choose_one(parent, "Make a choice", ['one', 'two', 'three'])) + information(parent, 'Going...') warning(parent, 'Going......') error(parent, 'Gone!') @@ -65,8 +67,6 @@ if confirm(parent, 'Should I exit?') == YES: self.close() - return - # Application entry point. if __name__ == '__main__': @@ -79,5 +79,3 @@ # Start the GUI event loop! gui.start_event_loop() - -##### EOF ##################################################################### diff -Nru python-pyface-4.5.2/examples/dock/dock_test3.py python-pyface-6.1.2/examples/dock/dock_test3.py --- python-pyface-4.5.2/examples/dock/dock_test3.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/dock/dock_test3.py 2019-07-20 11:46:59.000000000 +0000 @@ -28,8 +28,6 @@ from pyface.image_resource \ import ImageResource -from etsdevtools.developer.tools.ui_debugger import UIDebugger - #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- @@ -61,7 +59,6 @@ button12 = Button code1 = Code code2 = Code - debug = Instance(UIDebugger) #--------------------------------------------------------------------------- # Traits view definitions: @@ -78,7 +75,6 @@ HSplit( 'button9', 'button10' ), Group( 'code1@', '|<>', image = image1 ), Group( 'code2@', '|<>', image = image2 ), - Group( 'debug', '|<>' ), Group( 'button11', 'button12' ) ), id = 'dock_window' diff -Nru python-pyface-4.5.2/examples/explorer.py python-pyface-6.1.2/examples/explorer.py --- python-pyface-4.5.2/examples/explorer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/explorer.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,6 +13,7 @@ #------------------------------------------------------------------------------ """ A file explorer example. """ +from __future__ import print_function # Standard library imports. import os, sys @@ -42,7 +43,7 @@ def perform(self): """ Performs the action. """ - print 'Performing', self.name + print('Performing', self.name) return diff -Nru python-pyface-4.5.2/examples/hello_world.py python-pyface-6.1.2/examples/hello_world.py --- python-pyface-4.5.2/examples/hello_world.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/hello_world.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,56 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2009, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# +# Thanks for using Enthought open source! +# +#------------------------------------------------------------------------------ +""" Hello world example. """ + +# Enthought library imports. +from pyface.api import ApplicationWindow, GUI, HeadingText + + +class MainWindow(ApplicationWindow): + """ The main application window. """ + + #-------------------------------------------------------------------------- + # 'IWindow' interface + #-------------------------------------------------------------------------- + + # The window title. + title = 'Hello World' + + #-------------------------------------------------------------------------- + # 'IApplicationWindow' interface. + #-------------------------------------------------------------------------- + + def _create_contents(self, parent): + """ Create the editor. """ + + self._label = HeadingText(parent, text="Hello World") + + return self._label.control + + +def main(): + # Create the GUI. + gui = GUI() + + # Create and open the main window. + window = MainWindow() + window.open() + + # Start the GUI event loop! + gui.start_event_loop() + + +# Application entry point. +if __name__ == '__main__': + main() diff -Nru python-pyface-4.5.2/examples/menu_manager.py python-pyface-6.1.2/examples/menu_manager.py --- python-pyface-4.5.2/examples/menu_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/menu_manager.py 2019-05-03 08:18:49.000000000 +0000 @@ -11,6 +11,8 @@ # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ +from __future__ import print_function + # Standard library imports. import os, sys @@ -79,25 +81,25 @@ def new_project(): - print 'new project' + print('new project') def open_project(): - print 'open project' + print('open project') def close_project(): - print 'close project' + print('close project') def close_active_editor(): - print 'close active editor' + print('close active editor') def export_to_html(): - print 'export to html' + print('export to html') def printit(): - print 'print' + print('print') def exit(): - print 'exit' + print('exit') file_menu = MenuManager( diff -Nru python-pyface-4.5.2/examples/node_tree.py python-pyface-6.1.2/examples/node_tree.py --- python-pyface-4.5.2/examples/node_tree.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/node_tree.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,6 +13,7 @@ #------------------------------------------------------------------------------ """ Node tree example. """ +from __future__ import print_function # Standard library imports. import os, sys @@ -73,7 +74,7 @@ def _on_tree_anytrait_changed(self, tree, trait_name, old, new): """ Called when any trait on the tree has changed. """ - print 'trait', trait_name, 'value', new + print('trait', trait_name, 'value', new) return diff -Nru python-pyface-4.5.2/examples/progress_dialog.py python-pyface-6.1.2/examples/progress_dialog.py --- python-pyface-4.5.2/examples/progress_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/progress_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,6 +1,8 @@ # # simple example of its use # +from __future__ import print_function + import time from pyface.api import GUI, ApplicationWindow, ProgressDialog from pyface.action.api import Action, MenuManager, MenuBarManager @@ -11,7 +13,7 @@ for i in range(0,t+1): time.sleep(1) - print i + print(i) (cont, skip) = progress.update(i) if not cont or skip: break diff -Nru python-pyface-4.5.2/examples/python_editor.py python-pyface-6.1.2/examples/python_editor.py --- python-pyface-4.5.2/examples/python_editor.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/python_editor.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,11 +13,17 @@ #------------------------------------------------------------------------------ """ Python editor example. """ +from __future__ import print_function, unicode_literals -# Enthought library imports. -from pyface.api import ApplicationWindow, FileDialog, GUI, OK, \ - PythonEditor -from pyface.action.api import Action, MenuManager, MenuBarManager +from pyface.api import ( + ApplicationWindow, FileDialog, GUI, OK, PythonEditor +) +from pyface.action.api import ( + Action, FieldAction, Group, MenuManager, MenuBarManager, + ToolBarManager +) +from pyface.fields.api import ComboField +from pyface.toolkit import toolkit_object class MainWindow(ApplicationWindow): @@ -34,13 +40,69 @@ super(MainWindow, self).__init__(**traits) # Add a menu bar. - self.menu_bar_manager = MenuBarManager(MenuManager( - Action(name='&Open...', on_perform=self._open_file), - Action(name='&Save', on_perform=self._save_file), - Action(name='E&xit', on_perform=self.close), - name='&File')) - - return + self.menu_bar_manager = MenuBarManager( + MenuManager( + Group( + Action( + name='&Open...', + accelerator='Ctrl+O', + on_perform=self.on_open_file + ), + Action( + name='&Save', + accelerator='Ctrl+S', + on_perform=self.on_save_file + ), + id='document_group', + ), + Action( + name='&Close', + accelerator='Ctrl+W', + on_perform=self.close + ), + name='&File') + ) + + # Add a tool bar if we are using qt4 - wx has layout issues + if toolkit_object.toolkit == 'qt4': + from pygments.styles import STYLE_MAP + styles = list(STYLE_MAP) + + self.tool_bar_manager = ToolBarManager( + Group( + Action( + name='Open...', + on_perform=self.on_open_file + ), + Action( + name='Save', + on_perform=self.on_save_file + ), + Action( + name='Close', + on_perform=self.close + ), + id='document_group', + ), + Group( + Action( + name="Lines", + style='toggle', + on_perform=self.on_show_line_numbers, + checked=True, + ), + FieldAction( + name='Style', + field_type=ComboField, + field_defaults={ + 'values': styles, + 'value': 'default', + 'tooltip': 'Style', + }, + on_perform=self.on_style_changed, + ), + ) + ) ########################################################################### # Protected 'IApplication' interface. @@ -57,38 +119,52 @@ # Private interface. ########################################################################### - def _open_file(self): + def on_open_file(self): """ Open a new file. """ if self.control: - dlg = FileDialog(parent=self.control, wildcard="*.py") + dlg = FileDialog(parent=self.control, wildcard='*.py') if dlg.open() == OK: self._editor.path = dlg.path - def _save_file(self): + def on_save_file(self): """ Save the file. """ if self.control: try: self._editor.save() - except IOError, e: + except IOError: # If you are trying to save to a file that doesn't exist, # open up a FileDialog with a 'save as' action. - dlg = FileDialog(parent=self.control, action='save as', wildcard="*.py") + dlg = FileDialog(parent=self.control, action='save as', + wildcard="*.py") if dlg.open() == OK: self._editor.save(dlg.path) + def on_show_line_numbers(self): + self._editor.show_line_numbers = not self._editor.show_line_numbers + + def on_style_changed(self, value): + from pygments.styles import get_style_by_name + + # XXX surface this to a proper API on the editor widget + # XXX Qt backend only + highlighter = self._editor.control.code.highlighter + highlighter._style = get_style_by_name(value) + highlighter._brushes = {} + highlighter._formats = {} + highlighter.rehighlight() + + # Application entry point. if __name__ == '__main__': # Create the GUI. gui = GUI() # Create and open the main window. - window = MainWindow() + window = MainWindow(size=(800, 600)) window.open() # Start the GUI event loop! gui.start_event_loop() - -##### EOF ##################################################################### diff -Nru python-pyface-4.5.2/examples/splash_screen.py python-pyface-6.1.2/examples/splash_screen.py --- python-pyface-4.5.2/examples/splash_screen.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/splash_screen.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,7 @@ """Example of using a splash screen (and the use of pyface Timer).""" +from __future__ import print_function + import time from pyface.timer.api import Timer @@ -58,7 +60,7 @@ """The method run periodically by the timer.""" self.counter += 1 - print "counter = %d" % self.counter + print("counter = %d" % self.counter) if __name__ == "__main__": @@ -74,4 +76,3 @@ # Start the GUI event loop! gui.start_event_loop() - diff -Nru python-pyface-4.5.2/examples/tasks/advanced/example_task.py python-pyface-6.1.2/examples/tasks/advanced/example_task.py --- python-pyface-4.5.2/examples/tasks/advanced/example_task.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/advanced/example_task.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,6 +1,6 @@ # Enthought library imports. from pyface.tasks.api import Task, TaskLayout, PaneItem, IEditor, \ - IEditorAreaPane, SplitEditorAreaPane + IEditorAreaPane, EditorAreaPane from pyface.tasks.action.api import DockPaneToggleGroup, SMenuBar, \ SMenu, SToolBar, TaskAction from pyface.api import ConfirmationDialog, FileDialog, \ @@ -44,7 +44,7 @@ TaskAction(method='save', tooltip='Save the current file', image=ImageResource('document_save')), - image_size = (32, 32)), ] + image_size = (32, 32), show_tool_names=False), ] ########################################################################### # 'Task' interface. @@ -64,7 +64,7 @@ def create_central_pane(self): """ Create the central pane: the script editor. """ - self.editor_area = SplitEditorAreaPane() + self.editor_area = EditorAreaPane() return self.editor_area def create_dock_panes(self): diff -Nru python-pyface-4.5.2/examples/tasks/advanced/python_editor.py python-pyface-6.1.2/examples/tasks/advanced/python_editor.py --- python-pyface-4.5.2/examples/tasks/advanced/python_editor.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/advanced/python_editor.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,193 +1,8 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2007, Riverbank Computing Limited -# All rights reserved. -# -# This software is provided without warranty under the terms of the BSD license. -# However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply +from pyface.toolkit import toolkit -# -# Author: Riverbank Computing Limited -# Description: -#------------------------------------------------------------------------------ - - -# Standard library imports. -import sys -from os.path import basename - -# Major package imports. -from pyface.qt import QtCore, QtGui - -# Enthought library imports. -from traits.api import Bool, Event, Instance, File, Unicode, Property, provides -from pyface.tasks.api import Editor - -# Local imports. -from i_python_editor import IPythonEditor -from pyface.key_pressed_event import KeyPressedEvent - -@provides(IPythonEditor) -class PythonEditor(Editor): - """ The toolkit specific implementation of a PythonEditor. See the - IPythonEditor interface for the API documentation. - """ - - #### 'IPythonEditor' interface ############################################ - - obj = Instance(File) - - path = Unicode - - dirty = Bool(False) - - name = Property(Unicode, depends_on='path') - - tooltip = Property(Unicode, depends_on='path') - - show_line_numbers = Bool(True) - - #### Events #### - - changed = Event - - key_pressed = Event(KeyPressedEvent) - - def _get_tooltip(self): - return self.path - - def _get_name(self): - return basename(self.path) or 'Untitled' - - ########################################################################### - # 'PythonEditor' interface. - ########################################################################### - - def create(self, parent): - self.control = self._create_control(parent) - - def load(self, path=None): - """ Loads the contents of the editor. - """ - if path is None: - path = self.path - - # We will have no path for a new script. - if len(path) > 0: - f = open(self.path, 'r') - text = f.read() - f.close() - else: - text = '' - - self.control.code.setPlainText(text) - self.dirty = False - - def save(self, path=None): - """ Saves the contents of the editor. - """ - if path is None: - path = self.path - - f = file(path, 'w') - f.write(self.control.code.toPlainText()) - f.close() - - self.dirty = False - - def select_line(self, lineno): - """ Selects the specified line. - """ - self.control.code.set_line_column(lineno, 0) - self.control.code.moveCursor(QtGui.QTextCursor.EndOfLine, - QtGui.QTextCursor.KeepAnchor) - - ########################################################################### - # Trait handlers. - ########################################################################### - - def _path_changed(self): - if self.control is not None: - self.load() - - def _show_line_numbers_changed(self): - if self.control is not None: - self.control.code.line_number_widget.setVisible( - self.show_line_numbers) - self.control.code.update_line_number_width() - - ########################################################################### - # Private interface. - ########################################################################### - - def _create_control(self, parent): - """ Creates the toolkit-specific control for the widget. - """ - from pyface.ui.qt4.code_editor.code_widget import AdvancedCodeWidget - self.control = control = AdvancedCodeWidget(parent) - self._show_line_numbers_changed() - - # Install event filter to trap key presses. - event_filter = PythonEditorEventFilter(self, self.control) - self.control.installEventFilter(event_filter) - self.control.code.installEventFilter(event_filter) - - # Connect signals for text changes. - control.code.modificationChanged.connect(self._on_dirty_changed) - control.code.textChanged.connect(self._on_text_changed) - - # Load the editor's contents. - self.load() - - return control - - def _on_dirty_changed(self, dirty): - """ Called whenever a change is made to the dirty state of the - document. - """ - self.dirty = dirty - - def _on_text_changed(self): - """ Called whenever a change is made to the text of the document. - """ - self.changed = True - - -class PythonEditorEventFilter(QtCore.QObject): - """ A thin wrapper around the advanced code widget to handle the key_pressed - Event. - """ - - def __init__(self, editor, parent): - super(PythonEditorEventFilter, self).__init__(parent) - self.__editor = editor - - def eventFilter(self, obj, event): - """ Reimplemented to trap key presses. - """ - if self.__editor.control and obj == self.__editor.control and \ - event.type() == QtCore.QEvent.FocusOut: - # Hack for Traits UI compatibility. - self.__editor.control.emit(QtCore.SIGNAL('lostFocus')) - - elif self.__editor.control and obj == self.__editor.control.code and \ - event.type() == QtCore.QEvent.KeyPress: - # Pyface doesn't seem to be Unicode aware. Only keep the key code - # if it corresponds to a single Latin1 character. - kstr = event.text() - try: - kcode = ord(str(kstr)) - except: - kcode = 0 - - mods = event.modifiers() - self.key_pressed = KeyPressedEvent( - alt_down = ((mods & QtCore.Qt.AltModifier) == - QtCore.Qt.AltModifier), - control_down = ((mods & QtCore.Qt.ControlModifier) == - QtCore.Qt.ControlModifier), - shift_down = ((mods & QtCore.Qt.ShiftModifier) == - QtCore.Qt.ShiftModifier), - key_code = kcode, - event = event) - - return super(PythonEditorEventFilter, self).eventFilter(obj, event) +if toolkit.toolkit == "wx": + from python_editor_wx import PythonEditor +elif toolkit.toolkit == "qt4": + from python_editor_qt4 import PythonEditor +else: + raise RuntimeError("Unsupported toolkit %s" % toolkit.toolkit) diff -Nru python-pyface-4.5.2/examples/tasks/advanced/python_editor_qt4.py python-pyface-6.1.2/examples/tasks/advanced/python_editor_qt4.py --- python-pyface-4.5.2/examples/tasks/advanced/python_editor_qt4.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/advanced/python_editor_qt4.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,193 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2007, Riverbank Computing Limited +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD license. +# However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply + +# +# Author: Riverbank Computing Limited +# Description: +#------------------------------------------------------------------------------ + + +# Standard library imports. +import sys +from os.path import basename + +# Major package imports. +from pyface.qt import QtCore, QtGui + +# Enthought library imports. +from traits.api import Bool, Event, Instance, File, Unicode, Property, provides +from pyface.tasks.api import Editor + +# Local imports. +from i_python_editor import IPythonEditor +from pyface.key_pressed_event import KeyPressedEvent + +@provides(IPythonEditor) +class PythonEditor(Editor): + """ The toolkit specific implementation of a PythonEditor. See the + IPythonEditor interface for the API documentation. + """ + + #### 'IPythonEditor' interface ############################################ + + obj = Instance(File) + + path = Unicode + + dirty = Bool(False) + + name = Property(Unicode, depends_on='path') + + tooltip = Property(Unicode, depends_on='path') + + show_line_numbers = Bool(True) + + #### Events #### + + changed = Event + + key_pressed = Event(KeyPressedEvent) + + def _get_tooltip(self): + return self.path + + def _get_name(self): + return basename(self.path) or 'Untitled' + + ########################################################################### + # 'PythonEditor' interface. + ########################################################################### + + def create(self, parent): + self.control = self._create_control(parent) + + def load(self, path=None): + """ Loads the contents of the editor. + """ + if path is None: + path = self.path + + # We will have no path for a new script. + if len(path) > 0: + f = open(self.path, 'r') + text = f.read() + f.close() + else: + text = '' + + self.control.code.setPlainText(text) + self.dirty = False + + def save(self, path=None): + """ Saves the contents of the editor. + """ + if path is None: + path = self.path + + f = open(path, 'w') + f.write(self.control.code.toPlainText()) + f.close() + + self.dirty = False + + def select_line(self, lineno): + """ Selects the specified line. + """ + self.control.code.set_line_column(lineno, 0) + self.control.code.moveCursor(QtGui.QTextCursor.EndOfLine, + QtGui.QTextCursor.KeepAnchor) + + ########################################################################### + # Trait handlers. + ########################################################################### + + def _path_changed(self): + if self.control is not None: + self.load() + + def _show_line_numbers_changed(self): + if self.control is not None: + self.control.code.line_number_widget.setVisible( + self.show_line_numbers) + self.control.code.update_line_number_width() + + ########################################################################### + # Private interface. + ########################################################################### + + def _create_control(self, parent): + """ Creates the toolkit-specific control for the widget. + """ + from pyface.ui.qt4.code_editor.code_widget import AdvancedCodeWidget + self.control = control = AdvancedCodeWidget(parent) + self._show_line_numbers_changed() + + # Install event filter to trap key presses. + event_filter = PythonEditorEventFilter(self, self.control) + self.control.installEventFilter(event_filter) + self.control.code.installEventFilter(event_filter) + + # Connect signals for text changes. + control.code.modificationChanged.connect(self._on_dirty_changed) + control.code.textChanged.connect(self._on_text_changed) + + # Load the editor's contents. + self.load() + + return control + + def _on_dirty_changed(self, dirty): + """ Called whenever a change is made to the dirty state of the + document. + """ + self.dirty = dirty + + def _on_text_changed(self): + """ Called whenever a change is made to the text of the document. + """ + self.changed = True + + +class PythonEditorEventFilter(QtCore.QObject): + """ A thin wrapper around the advanced code widget to handle the key_pressed + Event. + """ + + def __init__(self, editor, parent): + super(PythonEditorEventFilter, self).__init__(parent) + self.__editor = editor + + def eventFilter(self, obj, event): + """ Reimplemented to trap key presses. + """ + if self.__editor.control and obj == self.__editor.control and \ + event.type() == QtCore.QEvent.FocusOut: + # Hack for Traits UI compatibility. + self.__editor.control.lostFocus.emit() + + elif self.__editor.control and obj == self.__editor.control.code and \ + event.type() == QtCore.QEvent.KeyPress: + # Pyface doesn't seem to be Unicode aware. Only keep the key code + # if it corresponds to a single Latin1 character. + kstr = event.text() + try: + kcode = ord(str(kstr)) + except: + kcode = 0 + + mods = event.modifiers() + self.key_pressed = KeyPressedEvent( + alt_down = ((mods & QtCore.Qt.AltModifier) == + QtCore.Qt.AltModifier), + control_down = ((mods & QtCore.Qt.ControlModifier) == + QtCore.Qt.ControlModifier), + shift_down = ((mods & QtCore.Qt.ShiftModifier) == + QtCore.Qt.ShiftModifier), + key_code = kcode, + event = event) + + return super(PythonEditorEventFilter, self).eventFilter(obj, event) diff -Nru python-pyface-4.5.2/examples/tasks/advanced/python_editor_wx.py python-pyface-6.1.2/examples/tasks/advanced/python_editor_wx.py --- python-pyface-4.5.2/examples/tasks/advanced/python_editor_wx.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/advanced/python_editor_wx.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,281 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2007, Riverbank Computing Limited +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD license. +# However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply + +# +# Author: Riverbank Computing Limited +# Description: +#------------------------------------------------------------------------------ + + +# Standard library imports. +import sys +from os.path import basename + +# Major package imports. +import wx +import wx.stc + +# Enthought library imports. +from traits.api import Bool, Event, Instance, File, Unicode, Property, provides +from pyface.tasks.api import Editor +from pyface.wx.python_stc import PythonSTC, faces + +# Local imports. +from i_python_editor import IPythonEditor +from pyface.key_pressed_event import KeyPressedEvent + +@provides(IPythonEditor) +class PythonEditor(Editor): + """ The toolkit specific implementation of a StyledTextEditor. See the + IStyledTextEditor interface for the API documentation. + """ + + #### 'IPythonEditor' interface ############################################ + + obj = Instance(File) + + path = Unicode + + dirty = Bool(False) + + name = Property(Unicode, depends_on='path') + + tooltip = Property(Unicode, depends_on='path') + + show_line_numbers = Bool(True) + + #### Events #### + + changed = Event + + key_pressed = Event(KeyPressedEvent) + + def _get_tooltip(self): + return self.path + + def _get_name(self): + return basename(self.path) or 'Untitled' + + ########################################################################### + # 'PythonEditor' interface. + ########################################################################### + + def create(self, parent): + self.control = self._create_control(parent) + + def load(self, path=None): + """ Loads the contents of the editor. + """ + if path is None: + path = self.path + + # We will have no path for a new script. + if len(path) > 0: + f = open(self.path, 'r') + text = f.read() + f.close() + else: + text = '' + + self.control.SetText(text) + self.dirty = False + + def save(self, path=None): + """ Saves the contents of the editor. + """ + if path is None: + path = self.path + + f = file(path, 'w') + f.write(self.control.GetText()) + f.close() + + self.dirty = False + + def select_line(self, lineno): + """ Selects the specified line. + """ + start = self.control.PositionFromLine(lineno) + end = self.control.GetLineEndPosition(lineno) + + self.control.SetSelection(start, end) + + def set_style(self, n, fore, back): + self.control.StyleSetForeground(n, fore) + #self.StyleSetBackground(n, '#c0c0c0') + #self.StyleSetBackground(n, '#ffffff') + self.control.StyleSetBackground(n, back) + self.control.StyleSetFaceName(n, "courier new") + self.control.StyleSetSize(n, faces['size']) + + ########################################################################### + # Trait handlers. + ########################################################################### + + def _path_changed(self): + if self.control is not None: + self.load() + + def _show_line_numbers_changed(self): + if self.control is not None: + c = self.control + if self.show_line_numbers: + c.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER) + c.SetMarginWidth(1, 45) + else: + c.SetMarginWidth(1, 4) + + ########################################################################### + # Private interface. + ########################################################################### + + def _create_control(self, parent): + """ Creates the toolkit-specific control for the widget. + """ + from pyface.ui.qt4.code_editor.code_widget import AdvancedCodeWidget + self.control = control = AdvancedCodeWidget(parent) + self._show_line_numbers_changed() + + def _create_control(self, parent): + """ Creates the toolkit-specific control for the widget. """ + + # Base-class constructor. + self.control = stc = PythonSTC(parent, -1) + + # No folding! + stc.SetProperty("fold", "0") + + # Mark the maximum line size. + stc.SetEdgeMode(wx.stc.STC_EDGE_LINE) + stc.SetEdgeColumn(79) + + stc.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER) + stc.SetMarginMask(1, ~wx.stc.STC_MASK_FOLDERS) + # Display line numbers in the margin. + if self.show_line_numbers: + stc.SetMarginWidth(1, 45) + self.set_style(wx.stc.STC_STYLE_LINENUMBER, "#000000", "#c0c0c0") + else: + stc.SetMarginWidth(1, 4) + self.set_style(wx.stc.STC_STYLE_LINENUMBER, "#ffffff", "#ffffff") + + # Create 'tabs' out of spaces! + stc.SetUseTabs(False) + + # One 'tab' is 4 spaces. + stc.SetIndent(4) + + # Line ending mode. + stc.SetEOLMode(wx.stc.STC_EOL_LF) # Unix + #self.SetEOLMode(wx.stc.STC_EOL_CR) # Apple Mac + #self.SetEOLMode(wx.stc.STC_EOL_CRLF) # Windows + + ########################################## + # Global styles for all languages. + ########################################## + + self.set_style(wx.stc.STC_STYLE_DEFAULT, "#000000", "#ffffff") + self.set_style(wx.stc.STC_STYLE_CONTROLCHAR, "#000000", "#ffffff") + self.set_style(wx.stc.STC_STYLE_BRACELIGHT, "#000000", "#ffffff") + self.set_style(wx.stc.STC_STYLE_BRACEBAD, "#000000", "#ffffff") + + ########################################## + # Python styles. + ########################################## + + # White space + self.set_style(wx.stc.STC_P_DEFAULT, "#000000", "#ffffff") + + # Comment + self.set_style(wx.stc.STC_P_COMMENTLINE, "#007f00", "#ffffff") + + # Number + self.set_style(wx.stc.STC_P_NUMBER, "#007f7f", "#ffffff") + + # String + self.set_style(wx.stc.STC_P_STRING, "#7f007f", "#ffffff") + + # Single quoted string + self.set_style(wx.stc.STC_P_CHARACTER, "#7f007f", "#ffffff") + + # Keyword + self.set_style(wx.stc.STC_P_WORD, "#00007f", "#ffffff") + + # Triple quotes + self.set_style(wx.stc.STC_P_TRIPLE, "#7f0000", "#ffffff") + + # Triple double quotes + self.set_style(wx.stc.STC_P_TRIPLEDOUBLE, "#ff0000", "#ffffff") + + # Class name definition + self.set_style(wx.stc.STC_P_CLASSNAME, "#0000ff", "#ffffff") + + # Function or method name definition + self.set_style(wx.stc.STC_P_DEFNAME, "#007f7f", "#ffffff") + + # Operators + self.set_style(wx.stc.STC_P_OPERATOR, "#000000", "#ffffff") + + # Identifiers + self.set_style(wx.stc.STC_P_IDENTIFIER, "#000000", "#ffffff") + + # Comment-blocks + self.set_style(wx.stc.STC_P_COMMENTBLOCK, "#007f00", "#ffffff") + + # End of line where string is not closed + self.set_style(wx.stc.STC_P_STRINGEOL, "#000000", "#ffffff") + + ########################################## + # Events. + ########################################## + + # By default, the will fire EVT_STC_CHANGE evented for all mask values + # (STC_MODEVENTMASKALL). This generates too many events. + stc.SetModEventMask(wx.stc.STC_MOD_INSERTTEXT | + wx.stc.STC_MOD_DELETETEXT | + wx.stc.STC_PERFORMED_UNDO | + wx.stc.STC_PERFORMED_REDO) + + # Listen for changes to the file. + wx.stc.EVT_STC_CHANGE(stc, stc.GetId(), self._on_stc_changed) + + # Listen for key press events. + wx.EVT_CHAR(stc, self._on_char) + + # Load the editor's contents. + self.load() + + return stc + + #### wx event handlers #################################################### + + def _on_stc_changed(self, event): + """ Called whenever a change is made to the text of the document. """ + + self.dirty = True + self.changed = True + + # Give other event handlers a chance. + event.Skip() + + return + + def _on_char(self, event): + """ Called whenever a change is made to the text of the document. """ + + self.key_pressed = KeyPressedEvent( + alt_down = event.m_altDown == 1, + control_down = event.m_controlDown == 1, + shift_down = event.m_shiftDown == 1, + key_code = event.m_keyCode, + event = event + ) + + # Give other event handlers a chance. + event.Skip() + + return diff -Nru python-pyface-4.5.2/examples/tasks/steps/mac-menubar-switching.py python-pyface-6.1.2/examples/tasks/steps/mac-menubar-switching.py --- python-pyface-4.5.2/examples/tasks/steps/mac-menubar-switching.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/steps/mac-menubar-switching.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,128 @@ +"""Incremental demo for wx support of tasks. + +Multiple tasks + +Note that naively subclassing SecondTask from ExampleTask, it initially used +the same menu_bar and tool_bars traits from ExampleTask. This caused the +incorrect tying of the controls to SecondTask because the class attributes +were shared between both classes. +""" +# Enthought library imports. +from pyface.api import GUI, ConfirmationDialog, FileDialog, \ + ImageResource, YES, OK, CANCEL +from pyface.tasks.api import Task, TaskWindow, TaskLayout, PaneItem, IEditor, \ + IEditorAreaPane, EditorAreaPane, Editor, DockPane, HSplitter, VSplitter +from pyface.tasks.action.api import DockPaneToggleGroup, SMenuBar, \ + SMenu, SToolBar, TaskAction, TaskToggleGroup +from traits.api import on_trait_change, Property, Instance + +class ExampleTask(Task): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.example_task' + name = 'Multi-Tab Editor' + + active_editor = Property(Instance(IEditor), + depends_on='editor_area.active_editor') + + editor_area = Instance(IEditorAreaPane) + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _menu_bar_default(self): + return SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + TaskToggleGroup(), + id='View', name='&View')) + + def create_central_pane(self): + """ Create the central pane: the script editor. + """ + self.editor_area = EditorAreaPane() + return self.editor_area + + ########################################################################### + # 'ExampleTask' interface. + ########################################################################### + + def new(self): + """ Opens a new empty window + """ + editor = Editor() + self.editor_area.add_editor(editor) + self.editor_area.activate_editor(editor) + self.activated() + + #### Trait property getter/setters ######################################## + + def _get_active_editor(self): + if self.editor_area is not None: + return self.editor_area.active_editor + return None + +class SecondTask(ExampleTask): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.second_task' + name = 'Second Multi-Tab Editor' + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _menu_bar_default(self): + return SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + TaskToggleGroup(), + id='View', name='&View'), + SMenu(TaskAction(name='Item 1', method='item1'), + TaskAction(name='Item 2', method='item2'), + id='Task2', name='&Task2'),) + + +def main(argv): + """ A simple example of using Tasks. + """ + # Create the GUI (this does NOT start the GUI event loop). + gui = GUI() + + # Create a Task and add it to a TaskWindow. + task1 = ExampleTask() + window = TaskWindow(size=(800, 600)) + window.add_task(task1) + window.open() + + task2 = SecondTask() + window = TaskWindow(size=(800, 600)) + window.add_task(task2) + window.open() + + # Start the GUI event loop. + gui.start_event_loop() + + +if __name__ == '__main__': + import sys + main(sys.argv) diff -Nru python-pyface-4.5.2/examples/tasks/steps/README.txt python-pyface-6.1.2/examples/tasks/steps/README.txt --- python-pyface-4.5.2/examples/tasks/steps/README.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/steps/README.txt 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,2 @@ +Set the environment variable ETS_DEBUG to force the actual cause of import +errors to be shown. diff -Nru python-pyface-4.5.2/examples/tasks/steps/step1.py python-pyface-6.1.2/examples/tasks/steps/step1.py --- python-pyface-4.5.2/examples/tasks/steps/step1.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/steps/step1.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,47 @@ +""" +Simple demo of tasks used to develop the wx support for tasks. +""" +# Enthought library imports. +from pyface.api import GUI +from pyface.tasks.api import Task, TaskWindow, EditorAreaPane + +class BlankTask(Task): + """ A task that does nothing + """ + + #### Task interface ####################################################### + + id = 'example.blank_task' + name = 'Blank' + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def create_central_pane(self): + """ Create the central pane: the script editor. + """ + self.editor_area = EditorAreaPane() + return self.editor_area + +def main(argv): + """ A simple example of using Tasks. + """ + # Create the GUI (this does NOT start the GUI event loop). + gui = GUI() + + # Create a Task and add it to a TaskWindow. + task = BlankTask() + window = TaskWindow(size=(800, 600)) + window.add_task(task) + + # Show the window. + window.open() + + # Start the GUI event loop. + gui.start_event_loop() + + +if __name__ == '__main__': + import sys + main(sys.argv) diff -Nru python-pyface-4.5.2/examples/tasks/steps/step2.py python-pyface-6.1.2/examples/tasks/steps/step2.py --- python-pyface-4.5.2/examples/tasks/steps/step2.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/steps/step2.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,89 @@ +"""Second demo for wx support of tasks. + +Create and delete editors in the main notebook area. Also adds menu and toolbar +support +""" +# Enthought library imports. +from pyface.api import GUI, ConfirmationDialog, FileDialog, \ + ImageResource, YES, OK, CANCEL +from pyface.tasks.api import Task, TaskWindow, TaskLayout, PaneItem, IEditor, \ + IEditorAreaPane, EditorAreaPane, Editor +from pyface.tasks.action.api import DockPaneToggleGroup, SMenuBar, \ + SMenu, SToolBar, TaskAction +from traits.api import on_trait_change, Property, Instance + +class ExampleTask(Task): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.example_task' + name = 'Multi-Tab Editor' + + active_editor = Property(Instance(IEditor), + depends_on='editor_area.active_editor') + + editor_area = Instance(IEditorAreaPane) + + menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + id='View', name='&View')) + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def create_central_pane(self): + """ Create the central pane: the script editor. + """ + self.editor_area = EditorAreaPane() + return self.editor_area + + ########################################################################### + # 'ExampleTask' interface. + ########################################################################### + + def new(self): + """ Opens a new empty window + """ + editor = Editor() + self.editor_area.add_editor(editor) + self.editor_area.activate_editor(editor) + self.activated() + + #### Trait property getter/setters ######################################## + + def _get_active_editor(self): + if self.editor_area is not None: + return self.editor_area.active_editor + return None + +def main(argv): + """ A simple example of using Tasks. + """ + # Create the GUI (this does NOT start the GUI event loop). + gui = GUI() + + # Create a Task and add it to a TaskWindow. + task = ExampleTask() + window = TaskWindow(size=(800, 600)) + window.add_task(task) + + # Show the window. + window.open() + + # Start the GUI event loop. + gui.start_event_loop() + + +if __name__ == '__main__': + import sys + main(sys.argv) diff -Nru python-pyface-4.5.2/examples/tasks/steps/step3.py python-pyface-6.1.2/examples/tasks/steps/step3.py --- python-pyface-4.5.2/examples/tasks/steps/step3.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/steps/step3.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,107 @@ +"""Incremental demo for wx support of tasks. + +Create and delete task panes +""" +# Enthought library imports. +from pyface.api import GUI, ConfirmationDialog, FileDialog, \ + ImageResource, YES, OK, CANCEL +from pyface.tasks.api import Task, TaskWindow, TaskLayout, PaneItem, IEditor, \ + IEditorAreaPane, EditorAreaPane, Editor, DockPane +from pyface.tasks.action.api import DockPaneToggleGroup, SMenuBar, \ + SMenu, SToolBar, TaskAction +from traits.api import on_trait_change, Property, Instance + +class ExamplePane(DockPane): + """ A simple file browser pane. + """ + + #### TaskPane interface ################################################### + + id = 'steps.example_pane' + name = 'Example Pane' + +class ExampleTask(Task): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.example_task' + name = 'Multi-Tab Editor' + + active_editor = Property(Instance(IEditor), + depends_on='editor_area.active_editor') + + editor_area = Instance(IEditorAreaPane) + + menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + id='View', name='&View')) + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _default_layout_default(self): + return TaskLayout( + top=PaneItem('steps.example_pane')) + + def create_central_pane(self): + """ Create the central pane: the script editor. + """ + self.editor_area = EditorAreaPane() + return self.editor_area + + def create_dock_panes(self): + """ Create the file browser and connect to its double click event. + """ + pane = ExamplePane() + return [ pane ] + + ########################################################################### + # 'ExampleTask' interface. + ########################################################################### + + def new(self): + """ Opens a new empty window + """ + editor = Editor() + self.editor_area.add_editor(editor) + self.editor_area.activate_editor(editor) + self.activated() + + #### Trait property getter/setters ######################################## + + def _get_active_editor(self): + if self.editor_area is not None: + return self.editor_area.active_editor + return None + +def main(argv): + """ A simple example of using Tasks. + """ + # Create the GUI (this does NOT start the GUI event loop). + gui = GUI() + + # Create a Task and add it to a TaskWindow. + task = ExampleTask() + window = TaskWindow(size=(800, 600)) + window.add_task(task) + + # Show the window. + window.open() + + # Start the GUI event loop. + gui.start_event_loop() + + +if __name__ == '__main__': + import sys + main(sys.argv) diff -Nru python-pyface-4.5.2/examples/tasks/steps/step4.py python-pyface-6.1.2/examples/tasks/steps/step4.py --- python-pyface-4.5.2/examples/tasks/steps/step4.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/steps/step4.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,144 @@ +"""Incremental demo for wx support of tasks. + +Multiple tasks + +Note that naively subclassing SecondTask from ExampleTask, it initially used +the same menu_bar and tool_bars traits from ExampleTask. This caused the +incorrect tying of the controls to SecondTask because the class attributes +were shared between both classes. +""" +# Enthought library imports. +from pyface.api import GUI, ConfirmationDialog, FileDialog, \ + ImageResource, YES, OK, CANCEL +from pyface.tasks.api import Task, TaskWindow, TaskLayout, PaneItem, IEditor, \ + IEditorAreaPane, EditorAreaPane, Editor, DockPane +from pyface.tasks.action.api import DockPaneToggleGroup, SMenuBar, \ + SMenu, SToolBar, TaskAction, TaskToggleGroup +from traits.api import on_trait_change, Property, Instance + +class ExamplePane(DockPane): + """ A simple file browser pane. + """ + + #### TaskPane interface ################################################### + + id = 'steps.example_pane' + name = 'Example Pane' + +class ExampleTask(Task): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.example_task' + name = 'Multi-Tab Editor' + + active_editor = Property(Instance(IEditor), + depends_on='editor_area.active_editor') + + editor_area = Instance(IEditorAreaPane) + + menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + TaskToggleGroup(), + id='View', name='&View')) + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _default_layout_default(self): + return TaskLayout( + top=PaneItem('steps.example_pane')) + + def create_central_pane(self): + """ Create the central pane: the script editor. + """ + self.editor_area = EditorAreaPane() + return self.editor_area + + def create_dock_panes(self): + """ Create the file browser and connect to its double click event. + """ + pane = ExamplePane() + return [ pane ] + + ########################################################################### + # 'ExampleTask' interface. + ########################################################################### + + def new(self): + """ Opens a new empty window + """ + editor = Editor() + self.editor_area.add_editor(editor) + self.editor_area.activate_editor(editor) + self.activated() + + #### Trait property getter/setters ######################################## + + def _get_active_editor(self): + if self.editor_area is not None: + return self.editor_area.active_editor + return None + +class SecondTask(ExampleTask): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.second_task' + name = 'Second Multi-Tab Editor' + + menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + TaskToggleGroup(), + id='View', name='&View')) + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _default_layout_default(self): + return TaskLayout( + bottom=PaneItem('steps.example_pane')) + +def main(argv): + """ A simple example of using Tasks. + """ + # Create the GUI (this does NOT start the GUI event loop). + gui = GUI() + + # Create a Task and add it to a TaskWindow. + task1 = ExampleTask() + task2 = SecondTask() + window = TaskWindow(size=(800, 600)) + window.add_task(task1) + window.add_task(task2) + + # Show the window. + window.open() + + # Start the GUI event loop. + gui.start_event_loop() + + +if __name__ == '__main__': + import sys + main(sys.argv) diff -Nru python-pyface-4.5.2/examples/tasks/steps/step5.py python-pyface-6.1.2/examples/tasks/steps/step5.py --- python-pyface-4.5.2/examples/tasks/steps/step5.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/steps/step5.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,156 @@ +"""Incremental demo for wx support of tasks. + +Multiple tasks + +Note that naively subclassing SecondTask from ExampleTask, it initially used +the same menu_bar and tool_bars traits from ExampleTask. This caused the +incorrect tying of the controls to SecondTask because the class attributes +were shared between both classes. +""" +# Enthought library imports. +from pyface.api import GUI, ConfirmationDialog, FileDialog, \ + ImageResource, YES, OK, CANCEL +from pyface.tasks.api import Task, TaskWindow, TaskLayout, PaneItem, IEditor, \ + IEditorAreaPane, EditorAreaPane, Editor, DockPane, Tabbed +from pyface.tasks.action.api import DockPaneToggleGroup, SMenuBar, \ + SMenu, SToolBar, TaskAction, TaskToggleGroup +from traits.api import on_trait_change, Property, Instance + +class FirstPane(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.first_pane' + name = 'First Pane' + +class SecondPane(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.second_pane' + name = 'Second Pane' + +class ThirdPane(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.third_pane' + name = 'Third Pane' + +class ExampleTask(Task): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.example_task' + name = 'Multi-Tab Editor' + + active_editor = Property(Instance(IEditor), + depends_on='editor_area.active_editor') + + editor_area = Instance(IEditorAreaPane) + + menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + TaskToggleGroup(), + id='View', name='&View')) + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _default_layout_default(self): + return TaskLayout( + top=Tabbed(PaneItem('steps.first_pane'), + PaneItem('steps.second_pane'), + PaneItem('steps.third_pane'))) + + def create_central_pane(self): + """ Create the central pane: the script editor. + """ + self.editor_area = EditorAreaPane() + return self.editor_area + + def create_dock_panes(self): + """ Create the file browser and connect to its double click event. + """ + return [ FirstPane(), SecondPane(), ThirdPane() ] + + ########################################################################### + # 'ExampleTask' interface. + ########################################################################### + + def new(self): + """ Opens a new empty window + """ + editor = Editor() + self.editor_area.add_editor(editor) + self.editor_area.activate_editor(editor) + self.activated() + + #### Trait property getter/setters ######################################## + + def _get_active_editor(self): + if self.editor_area is not None: + return self.editor_area.active_editor + return None + +class SecondTask(ExampleTask): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.second_task' + name = 'Second Multi-Tab Editor' + + menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + TaskToggleGroup(), + id='View', name='&View')) + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _default_layout_default(self): + return TaskLayout( + left=Tabbed(PaneItem('steps.first_pane'), + PaneItem('steps.second_pane'), + PaneItem('steps.third_pane'))) + +def main(argv): + """ A simple example of using Tasks. + """ + # Create the GUI (this does NOT start the GUI event loop). + gui = GUI() + + # Create a Task and add it to a TaskWindow. + task1 = ExampleTask() + task2 = SecondTask() + window = TaskWindow(size=(800, 600)) + window.add_task(task1) + window.add_task(task2) + + # Show the window. + window.open() + + # Start the GUI event loop. + gui.start_event_loop() + + +if __name__ == '__main__': + import sys + main(sys.argv) diff -Nru python-pyface-4.5.2/examples/tasks/steps/step6a.py python-pyface-6.1.2/examples/tasks/steps/step6a.py --- python-pyface-4.5.2/examples/tasks/steps/step6a.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/steps/step6a.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,194 @@ +"""Incremental demo for wx support of tasks. + +Multiple tasks + +Note that naively subclassing SecondTask from ExampleTask, it initially used +the same menu_bar and tool_bars traits from ExampleTask. This caused the +incorrect tying of the controls to SecondTask because the class attributes +were shared between both classes. +""" +# Enthought library imports. +from pyface.api import GUI, ConfirmationDialog, FileDialog, \ + ImageResource, YES, OK, CANCEL +from pyface.tasks.api import Task, TaskWindow, TaskLayout, PaneItem, IEditor, \ + IEditorAreaPane, EditorAreaPane, Editor, DockPane, HSplitter, VSplitter +from pyface.tasks.action.api import DockPaneToggleGroup, SMenuBar, \ + SMenu, SToolBar, TaskAction, TaskToggleGroup +from traits.api import on_trait_change, Property, Instance + +class Pane1(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane1' + name = 'Pane 1' + +class Pane2(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane2' + name = 'Pane 2' + +class Pane3(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane3' + name = 'Pane 3' + +class Pane4(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane4' + name = 'Pane 4' + +class Pane5(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane5' + name = 'Pane 5' + +class Pane6(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane6' + name = 'Pane 6' + +class Pane7(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane7' + name = 'Pane 7' + +class ExampleTask(Task): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.example_task' + name = 'Multi-Tab Editor' + + active_editor = Property(Instance(IEditor), + depends_on='editor_area.active_editor') + + editor_area = Instance(IEditorAreaPane) + + menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + TaskToggleGroup(), + id='View', name='&View')) + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _default_layout_default(self): + return TaskLayout( + top=VSplitter( + HSplitter( + PaneItem('steps.pane1'), + PaneItem('steps.pane2'), + PaneItem('steps.pane3')), + HSplitter( + PaneItem('steps.pane4'), + PaneItem('steps.pane5'), + PaneItem('steps.pane6')), + )) + + def create_central_pane(self): + """ Create the central pane: the script editor. + """ + self.editor_area = EditorAreaPane() + return self.editor_area + + def create_dock_panes(self): + """ Create the file browser and connect to its double click event. + """ + return [ Pane1(), Pane2(), Pane3(), Pane4(), Pane5(), Pane6() ] + + ########################################################################### + # 'ExampleTask' interface. + ########################################################################### + + def new(self): + """ Opens a new empty window + """ + editor = Editor() + self.editor_area.add_editor(editor) + self.editor_area.activate_editor(editor) + self.activated() + + #### Trait property getter/setters ######################################## + + def _get_active_editor(self): + if self.editor_area is not None: + return self.editor_area.active_editor + return None + +class SecondTask(ExampleTask): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.second_task' + name = 'Second Multi-Tab Editor' + + menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + TaskToggleGroup(), + id='View', name='&View')) + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _default_layout_default(self): + return TaskLayout( + left=VSplitter( + HSplitter( + PaneItem('steps.pane1'), + PaneItem('steps.pane2'), + PaneItem('steps.pane3')), + HSplitter( + PaneItem('steps.pane4'), + PaneItem('steps.pane5'), + PaneItem('steps.pane6')), + )) + +def main(argv): + """ A simple example of using Tasks. + """ + # Create the GUI (this does NOT start the GUI event loop). + gui = GUI() + + # Create a Task and add it to a TaskWindow. + task1 = ExampleTask() + task2 = SecondTask() + window = TaskWindow(size=(800, 600)) + window.add_task(task1) + window.add_task(task2) + + # Show the window. + window.open() + + # Start the GUI event loop. + gui.start_event_loop() + + +if __name__ == '__main__': + import sys + main(sys.argv) diff -Nru python-pyface-4.5.2/examples/tasks/steps/step6.py python-pyface-6.1.2/examples/tasks/steps/step6.py --- python-pyface-4.5.2/examples/tasks/steps/step6.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/steps/step6.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,184 @@ +"""Incremental demo for wx support of tasks. + +Multiple tasks + +Note that naively subclassing SecondTask from ExampleTask, it initially used +the same menu_bar and tool_bars traits from ExampleTask. This caused the +incorrect tying of the controls to SecondTask because the class attributes +were shared between both classes. +""" +# Enthought library imports. +from pyface.api import GUI, ConfirmationDialog, FileDialog, \ + ImageResource, YES, OK, CANCEL +from pyface.tasks.api import Task, TaskWindow, TaskLayout, PaneItem, IEditor, \ + IEditorAreaPane, EditorAreaPane, Editor, DockPane, HSplitter, VSplitter +from pyface.tasks.action.api import DockPaneToggleGroup, SMenuBar, \ + SMenu, SToolBar, TaskAction, TaskToggleGroup +from traits.api import on_trait_change, Property, Instance + +class Pane1(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane1' + name = 'Pane 1' + +class Pane2(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane2' + name = 'Pane 2' + +class Pane3(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane3' + name = 'Pane 3' + +class Pane4(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane4' + name = 'Pane 4' + +class Pane5(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane5' + name = 'Pane 5' + +class Pane6(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane6' + name = 'Pane 6' + +class Pane7(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane7' + name = 'Pane 7' + +class ExampleTask(Task): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.example_task' + name = 'Multi-Tab Editor' + + active_editor = Property(Instance(IEditor), + depends_on='editor_area.active_editor') + + editor_area = Instance(IEditorAreaPane) + + menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + TaskToggleGroup(), + id='View', name='&View')) + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _default_layout_default(self): + return TaskLayout( + top=HSplitter( + PaneItem('steps.pane1'), + PaneItem('steps.pane2'), + PaneItem('steps.pane3'), + )) + + def create_central_pane(self): + """ Create the central pane: the script editor. + """ + self.editor_area = EditorAreaPane() + return self.editor_area + + def create_dock_panes(self): + """ Create the file browser and connect to its double click event. + """ + return [ Pane1(), Pane2(), Pane3() ] + + ########################################################################### + # 'ExampleTask' interface. + ########################################################################### + + def new(self): + """ Opens a new empty window + """ + editor = Editor() + self.editor_area.add_editor(editor) + self.editor_area.activate_editor(editor) + self.activated() + + #### Trait property getter/setters ######################################## + + def _get_active_editor(self): + if self.editor_area is not None: + return self.editor_area.active_editor + return None + +class SecondTask(ExampleTask): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.second_task' + name = 'Second Multi-Tab Editor' + + menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + TaskToggleGroup(), + id='View', name='&View')) + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _default_layout_default(self): + return TaskLayout( + left=VSplitter( + PaneItem('steps.pane1'), + PaneItem('steps.pane2'), + PaneItem('steps.pane3'), + )) + +def main(argv): + """ A simple example of using Tasks. + """ + # Create the GUI (this does NOT start the GUI event loop). + gui = GUI() + + # Create a Task and add it to a TaskWindow. + task1 = ExampleTask() + task2 = SecondTask() + window = TaskWindow(size=(800, 600)) + window.add_task(task1) + window.add_task(task2) + + # Show the window. + window.open() + + # Start the GUI event loop. + gui.start_event_loop() + + +if __name__ == '__main__': + import sys + main(sys.argv) diff -Nru python-pyface-4.5.2/examples/tasks/steps/step7.py python-pyface-6.1.2/examples/tasks/steps/step7.py --- python-pyface-4.5.2/examples/tasks/steps/step7.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/steps/step7.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,177 @@ +"""Incremental demo for wx support of tasks. + +Multiple tasks + +Note that naively subclassing SecondTask from ExampleTask, it initially used +the same menu_bar and tool_bars traits from ExampleTask. This caused the +incorrect tying of the controls to SecondTask because the class attributes +were shared between both classes. +""" + +import logging +logging.basicConfig(level=logging.DEBUG) + +import wx + +# Enthought library imports. +from pyface.api import GUI, ConfirmationDialog, FileDialog, \ + ImageResource, YES, OK, CANCEL +from pyface.tasks.api import Task, TaskWindow, TaskLayout, PaneItem, IEditor, \ + IEditorAreaPane, EditorAreaPane, Editor, DockPane, HSplitter, VSplitter +from pyface.tasks.action.api import DockPaneToggleGroup, SMenuBar, \ + SMenu, SToolBar, TaskAction, TaskToggleGroup +from traits.api import on_trait_change, Property, Instance, Str, List + + +class Pane1(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane1' + name = 'Pane 1' + +class Pane2(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane2' + name = 'Pane 2' + + #### FileBrowserPane interface ############################################ + + # The list of wildcard filters for filenames. + filters = List(Str) + + def create_contents(self, parent): + control = wx.GenericDirCtrl(parent, -1, size=(200,-1), style=wx.NO_BORDER) + control.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.on_selected) + return control + + def on_selected(self, evt): + selected_file = self.control.GetFilePath() + wx.CallAfter(self.task.window.application.load_file, selected_file, self.task, in_current_window=True) + +class ExampleTask(Task): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.example_task' + name = 'Multi-Tab Editor' + + active_editor = Property(Instance(IEditor), + depends_on='editor_area.active_editor') + + editor_area = Instance(IEditorAreaPane) + + menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + TaskToggleGroup(), + id='View', name='&View')) + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _default_layout_default(self): + return TaskLayout( + top=VSplitter( + HSplitter( + PaneItem('steps.pane1'), + PaneItem('steps.pane2')), + )) + + def create_central_pane(self): + """ Create the central pane: the script editor. + """ + self.editor_area = EditorAreaPane() + return self.editor_area + + def create_dock_panes(self): + """ Create the file browser and connect to its double click event. + """ + return [ Pane1(), Pane2() ] + + ########################################################################### + # 'ExampleTask' interface. + ########################################################################### + + def new(self): + """ Opens a new empty window + """ + editor = Editor() + self.editor_area.add_editor(editor) + self.editor_area.activate_editor(editor) + self.activated() + + #### Trait property getter/setters ######################################## + + def _get_active_editor(self): + if self.editor_area is not None: + return self.editor_area.active_editor + return None + +class SecondTask(ExampleTask): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.second_task' + name = 'Second Multi-Tab Editor' + + menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + TaskToggleGroup(), + id='View', name='&View')) + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _default_layout_default(self): + return TaskLayout( + left=VSplitter( + HSplitter( + PaneItem('steps.pane1'), + PaneItem('steps.pane2')), + )) + +def main(argv): + """ A simple example of using Tasks. + """ + # Create the GUI (this does NOT start the GUI event loop). + gui = GUI() + + # Create a Task and add it to a TaskWindow. + task1 = ExampleTask() + task2 = SecondTask() + window = TaskWindow(size=(800, 600)) + window.add_task(task1) + window.add_task(task2) + + # Show the window. + window.open() + + # Start the GUI event loop. + gui.start_event_loop() + + +if __name__ == '__main__': + import sys + main(sys.argv) diff -Nru python-pyface-4.5.2/examples/tasks/steps/step8.py python-pyface-6.1.2/examples/tasks/steps/step8.py --- python-pyface-4.5.2/examples/tasks/steps/step8.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/tasks/steps/step8.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,226 @@ +"""Incremental demo for wx support of tasks. + +Multiple tasks + +Note that naively subclassing SecondTask from ExampleTask, it initially used +the same menu_bar and tool_bars traits from ExampleTask. This caused the +incorrect tying of the controls to SecondTask because the class attributes +were shared between both classes. +""" + +import logging +logging.basicConfig(level=logging.DEBUG) + +import wx + +# Enthought library imports. +from pyface.api import GUI, ConfirmationDialog, FileDialog, \ + ImageResource, YES, OK, CANCEL +from pyface.tasks.api import Task, TaskWindow, TaskLayout, PaneItem, IEditor, \ + IEditorAreaPane, EditorAreaPane, Editor, DockPane, HSplitter, VSplitter +from pyface.tasks.action.api import DockPaneToggleGroup, SMenuBar, \ + SMenu, SToolBar, TaskAction, TaskToggleGroup +from traits.api import on_trait_change, Property, Instance, Str, List + + +class Pane1(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane1' + name = 'Pane 1' + +class Pane2(DockPane): + #### TaskPane interface ################################################### + + id = 'steps.pane2' + name = 'Pane 2' + + #### FileBrowserPane interface ############################################ + + # The list of wildcard filters for filenames. + filters = List(Str) + + def create_contents(self, parent): + control = wx.GenericDirCtrl(parent, -1, size=(200,-1), style=wx.NO_BORDER) + control.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.on_selected) + return control + + def on_selected(self, evt): + selected_file = self.control.GetFilePath() + wx.CallAfter(self.task.window.application.load_file, selected_file, self.task, in_current_window=True) + +class ExampleTask(Task): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.example_task' + name = 'Multi-Tab Editor' + + active_editor = Property(Instance(IEditor), + depends_on='editor_area.active_editor') + + editor_area = Instance(IEditorAreaPane) + + menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new', + accelerator='Ctrl+N'), + TaskAction(name='Add Task', method='add_task', + accelerator='Ctrl+A'), + TaskAction(name='Remove Task', method='remove_task', + accelerator='Ctrl+R'), + id='File', name='&File'), + SMenu(DockPaneToggleGroup(), + TaskToggleGroup(), + id='View', name='&View')) + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _default_layout_default(self): + return TaskLayout( + top=VSplitter( + HSplitter( + PaneItem('steps.pane1'), + PaneItem('steps.pane2')), + )) + + def create_central_pane(self): + """ Create the central pane: the script editor. + """ + self.editor_area = EditorAreaPane() + return self.editor_area + + def create_dock_panes(self): + """ Create the file browser and connect to its double click event. + """ + return [ Pane1(), Pane2() ] + + ########################################################################### + # 'ExampleTask' interface. + ########################################################################### + + def new(self): + """ Opens a new empty window + """ + editor = Editor() + self.editor_area.add_editor(editor) + self.editor_area.activate_editor(editor) + self.activated() + + def add_task(self): + """ Opens a new empty window + """ + task3 = ThirdTask() + self.window.add_task(task3) + self.window.activate_task(task3) + + def remove_task(self): + """ Opens a new empty window + """ + task = self.window.tasks[0] + window = self.window + window.remove_task(self) + window.activate_task(task) + + #### Trait property getter/setters ######################################## + + def _get_active_editor(self): + if self.editor_area is not None: + return self.editor_area.active_editor + return None + +class SecondTask(ExampleTask): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.second_task' + name = 'Second Multi-Tab Editor' + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _default_layout_default(self): + return TaskLayout( + left=VSplitter( + HSplitter( + PaneItem('steps.pane1'), + PaneItem('steps.pane2')), + )) + +class ThirdTask(ExampleTask): + """ A simple task for opening a blank editor. + """ + + #### Task interface ####################################################### + + id = 'example.third_task' + name = 'Third Multi-Tab Editor' + + tool_bars = [ SToolBar(TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + TaskAction(method='new', + tooltip='New file', + image=ImageResource('document_new')), + image_size = (32, 32)), + ] + + ########################################################################### + # 'Task' interface. + ########################################################################### + + def _default_layout_default(self): + return TaskLayout( + right=VSplitter( + HSplitter( + PaneItem('steps.pane1'), + PaneItem('steps.pane2')), + )) + +def main(argv): + """ A simple example of using Tasks. + """ + # Create the GUI (this does NOT start the GUI event loop). + gui = GUI() + + # Create a Task and add it to a TaskWindow. + task1 = ExampleTask() + task2 = SecondTask() + window = TaskWindow(size=(800, 600)) + window.add_task(task1) + window.add_task(task2) + + # Show the window. + window.open() + + # Start the GUI event loop. + gui.start_event_loop() + + +if __name__ == '__main__': + import sys + main(sys.argv) diff -Nru python-pyface-4.5.2/examples/timer.py python-pyface-6.1.2/examples/timer.py --- python-pyface-4.5.2/examples/timer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/timer.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,11 +1,12 @@ """Example of using a pyface Timer.""" - +from __future__ import print_function from pyface.timer.api import Timer from pyface.api import GUI, ApplicationWindow from pyface.action.api import Action, MenuManager, MenuBarManager from traits.api import Any, Int + class MainWindow(ApplicationWindow): """ The main application window. """ @@ -53,7 +54,7 @@ """The method run periodically by the timer.""" self.counter += 1 - print "counter = %d" % self.counter + print("counter = %d" % self.counter) if __name__ == "__main__": @@ -65,4 +66,3 @@ # Start the GUI event loop! gui.start_event_loop() - diff -Nru python-pyface-4.5.2/examples/traitsui_window.py python-pyface-6.1.2/examples/traitsui_window.py --- python-pyface-4.5.2/examples/traitsui_window.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/examples/traitsui_window.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,79 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2009, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# +# Thanks for using Enthought open source! +# +#------------------------------------------------------------------------------ +""" IPython widget example. """ + +# Enthought library imports. +from pyface.api import ApplicationWindow, GUI +from traits.api import Enum, HasTraits, Instance, Int, Str +from traitsui.api import View, Item + + +class Person(HasTraits): + """ Model class representing a person """ + + #: the name of the person + name = Str + + #: the age of the person + age = Int(18) + + #: the gender of the person + gender = Enum('female', 'male') + + # a default traits view + view = View( + Item('name', resizable=True), + Item('age', resizable=True), + Item('gender', resizable=True), + resizable=True, + ) + + +class MainWindow(ApplicationWindow): + """ The main application window. """ + + #### 'IWindow' interface ################################################## + + # The size of the window. + size = (320, 240) + + # The window title. + title = 'TraitsUI Person' + + # The traits object to display + person = Instance(Person, ()) + + ########################################################################### + # Protected 'IApplication' interface. + ########################################################################### + + def _create_contents(self, parent): + """ Create the editor. """ + self._ui = self.person.edit_traits(kind='panel', parent=parent) + return self._ui.control + + +# Application entry point. +if __name__ == '__main__': + # Create the GUI. + gui = GUI() + + # Create and open the main window. + window = MainWindow() + window.open() + + # Start the GUI event loop! + gui.start_event_loop() + +##### EOF ##################################################################### diff -Nru python-pyface-4.5.2/examples/tree.py python-pyface-6.1.2/examples/tree.py --- python-pyface-4.5.2/examples/tree.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/tree.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,6 +13,7 @@ #------------------------------------------------------------------------------ """ Tree example. """ +from __future__ import print_function # Standard library imports. import os, sys @@ -72,7 +73,7 @@ def _on_tree_anytrait_changed(self, tree, trait_name, old, new): """ Called when any trait on the tree has changed. """ - print 'trait', trait_name, 'value', new + print('trait', trait_name, 'value', new) return diff -Nru python-pyface-4.5.2/examples/tree_viewer.py python-pyface-6.1.2/examples/tree_viewer.py --- python-pyface-4.5.2/examples/tree_viewer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/tree_viewer.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,6 +13,7 @@ #------------------------------------------------------------------------------ """ Tree viewer example. """ +from __future__ import print_function # Standard library imports. import os, sys @@ -73,7 +74,7 @@ def _on_tree_anytrait_changed(self, viewer, trait_name, old, new): """ Called when any trait on the tree has changed. """ - print 'trait', trait_name, 'value', new + print('trait', trait_name, 'value', new) return diff -Nru python-pyface-4.5.2/examples/wizard.py python-pyface-6.1.2/examples/wizard.py --- python-pyface-4.5.2/examples/wizard.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/wizard.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,6 +13,7 @@ #------------------------------------------------------------------------------ """ Wizard example. """ +from __future__ import print_function # Standard library imports. import os @@ -91,8 +92,8 @@ # Create and open the wizard. if wizard.open() == OK: - print 'Wizard completed successfully' + print('Wizard completed successfully') else: - print 'Wizard cancelled' + print('Wizard cancelled') ##### EOF ##################################################################### diff -Nru python-pyface-4.5.2/examples/workbench/run.py python-pyface-6.1.2/examples/workbench/run.py --- python-pyface-4.5.2/examples/workbench/run.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/examples/workbench/run.py 2019-05-03 08:18:49.000000000 +0000 @@ -14,7 +14,7 @@ # Log to stderr. logger = logging.getLogger() -logger.addHandler(logging.StreamHandler(file('example_workbench.log', 'w'))) +logger.addHandler(logging.StreamHandler(open('example_workbench.log', 'w'))) logger.setLevel(logging.DEBUG) diff -Nru python-pyface-4.5.2/MANIFEST.in python-pyface-6.1.2/MANIFEST.in --- python-pyface-4.5.2/MANIFEST.in 2015-07-21 14:05:50.000000000 +0000 +++ python-pyface-6.1.2/MANIFEST.in 2019-05-03 08:18:49.000000000 +0000 @@ -1,7 +1,7 @@ include *.txt include README.rst include MANIFEST.in -recursive-include pyface *.py *.png *.jpg *.gif *.svg +recursive-include pyface *.py *.png *.jpg *.gif *.svg *.zip *.txt graft docs prune docs/build recursive-exclude docs *.pyc diff -Nru python-pyface-4.5.2/PKG-INFO python-pyface-6.1.2/PKG-INFO --- python-pyface-4.5.2/PKG-INFO 2015-08-14 15:55:52.000000000 +0000 +++ python-pyface-6.1.2/PKG-INFO 2019-07-22 09:15:12.000000000 +0000 @@ -1,16 +1,27 @@ Metadata-Version: 1.1 Name: pyface -Version: 4.5.2 +Version: 6.1.2 Summary: traits-capable windowing framework -Home-page: https://docs.enthought.com/pyface +Home-page: http://docs.enthought.com/pyface Author: ETS Developers Author-email: enthought-dev@enthought.com License: BSD Download-URL: https://github.com/enthought/pyface +Description-Content-Type: UNKNOWN Description: ========================================== pyface: traits-capable windowing framework ========================================== + .. image:: https://travis-ci.org/enthought/pyface.svg?branch=master + :target: https://travis-ci.org/enthought/pyface + + .. image:: https://ci.appveyor.com/api/projects/status/68nfb049cdq9wqd1/branch/master?svg=true + :target: https://ci.appveyor.com/project/EnthoughtOSS/pyface/branch/master + + .. image:: https://codecov.io/github/enthought/pyface/coverage.svg?branch=master + :target: https://codecov.io/github/enthought/pyface?branch=master + + The pyface project contains a toolkit-independent GUI abstraction layer, which is used to support the "visualization" features of the Traits package. Thus, you can write code in terms of the Traits API (views, items, editors, @@ -23,8 +34,8 @@ - PyQt - PySide - **Warning:** In Pyface version 5.0 the default GUI backend will change from - ``wx`` to ``qt4``. + **Warning:** The default toolkit if none is supplied is ``qt4``. + This changed from ``wx`` in Pyface 5.0.. Documentation ------------- @@ -44,8 +55,7 @@ * Pygments for syntax highlighting in the Qt code editor widget. - * some widgets may have additional optional dependencies. For example, the - IPython shell widgets require IPython to be installed. + * some widgets may have additional optional dependencies. Platform: Windows Platform: Linux @@ -62,6 +72,10 @@ Classifier: Operating System :: POSIX Classifier: Operating System :: Unix Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 Classifier: Topic :: Scientific/Engineering Classifier: Topic :: Software Development Classifier: Topic :: Software Development :: Libraries diff -Nru python-pyface-4.5.2/pyface/about_dialog.py python-pyface-6.1.2/pyface/about_dialog.py --- python-pyface-4.5.2/pyface/about_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/about_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,9 +13,10 @@ #------------------------------------------------------------------------------ """ The implementation of a simple 'About' dialog. """ +from __future__ import absolute_import # Import the toolkit specific version. -from toolkit import toolkit_object +from .toolkit import toolkit_object AboutDialog = toolkit_object('about_dialog:AboutDialog') ### EOF ####################################################################### diff -Nru python-pyface-4.5.2/pyface/action/action_controller.py python-pyface-6.1.2/pyface/action/action_controller.py --- python-pyface-4.5.2/pyface/action/action_controller.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/action_controller.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,28 +13,68 @@ ########################################################################### def perform(self, action, event): - """ Control an action invocation. """ + """ Control an action invocation. + Parameters + ---------- + action : Action instance + The action to perform. + event : ActionEvent instance + The event that triggered the action. + + Returns + ------- + result : any + The result of the action's perform method (usually None). + """ return action.perform(event) def can_add_to_menu(self, action): - """ Returns True if the action can be added to a menu/menubar. """ + """ Can add an action to a menu + Parameters + ---------- + action : Action instance + The action to consider. + + Returns + ------- + can_add : bool + ``True` if the action can be added to a menu/menubar. + """ return True def add_to_menu(self, action): - """ Called when an action is added to the a menu/menubar. """ + """ Called when an action is added to the a menu/menubar. - return + Parameters + ---------- + action : Action instance + The action added to the menu. + """ + pass def can_add_to_toolbar(self, action): - """ Returns True if the action can be added to a toolbar. """ + """ Returns True if the action can be added to a toolbar. + Parameters + ---------- + action : Action instance + The action to consider. + + Returns + ------- + can_add : bool + ``True` if the action can be added to a toolbar. + """ return True def add_to_toolbar(self, action): - """ Called when an action is added to the a toolbar. """ + """ Called when an action is added to the a toolbar. - return - -#### EOF ###################################################################### + Parameters + ---------- + action : Action instance + The action added to the toolbar. + """ + pass diff -Nru python-pyface-4.5.2/pyface/action/action_event.py python-pyface-6.1.2/pyface/action/action_event.py --- python-pyface-4.5.2/pyface/action/action_event.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/action_event.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,7 +13,7 @@ #### 'ActionEvent' interface ############################################## - # When the action was performed (time.time()). + #: When the action was performed (time.time()). when = Float ########################################################################### @@ -24,19 +24,9 @@ """ Creates a new action event. Note: Every keyword argument becoames a public attribute of the event. - """ - # Base-class constructor. super(ActionEvent, self).__init__(**traits) - # fixme: We currently allow anything to be tagged onto the event, which - # is going to make code very hard to read. - self.__dict__.update(traits) - # When the action was performed. self.when = time.time() - - return - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/action/action_item.py python-pyface-6.1.2/pyface/action/action_item.py --- python-pyface-4.5.2/pyface/action/action_item.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/action_item.py 2019-05-03 08:18:49.000000000 +0000 @@ -18,8 +18,8 @@ from traits.api import Any, Instance, List, Property, Str, on_trait_change # Local imports. -from action import Action -from action_manager_item import ActionManagerItem +from pyface.action.action import Action +from pyface.action.action_manager_item import ActionManagerItem # Import the toolkit specific versions of the internal classes. from pyface.toolkit import toolkit_object @@ -33,29 +33,29 @@ #### 'ActionManagerItem' interface ######################################## - # The item's unique identifier ('unique' in this case means unique within - # its group). + #: The item's unique identifier ('unique' in this case means unique within + #: its group). id = Property(Str) #### 'ActionItem' interface ############################################### - # The action! + #: The action! action = Instance(Action) - # The toolkit specific control created for this item. + #: The toolkit specific control created for this item. control = Any - # The toolkit specific Id of the control created for this item. + #: The toolkit specific Id of the control created for this item. # - # We have to keep the Id as well as the control because wx tool bar tools - # are created as 'wxObjectPtr's which do not have Ids, and the Id is - # required to manipulate the state of a tool via the tool bar 8^( + #: We have to keep the Id as well as the control because wx tool bar tools + #: are created as 'wxObjectPtr's which do not have Ids, and the Id is + #: required to manipulate the state of a tool via the tool bar 8^( # FIXME v3: Why is this part of the public interface? control_id = Any #### Private interface #################################################### - # All of the internal instances that wrap this item. + #: All of the internal instances that wrap this item. _wrappers = List(Any) ########################################################################### @@ -65,30 +65,19 @@ #### Trait properties ##################################################### def _get_id(self): - """ Return's the item's Id. """ - return self.action.id #### Trait change handlers ################################################ def _enabled_changed(self, trait_name, old, new): - """ Static trait change handler. """ - self.action.enabled = new - return - def _visible_changed(self, trait_name, old, new): - """ Static trait change handler. """ - self.action.visible = new - return - @on_trait_change('_wrappers.control') def _on_destroy(self, object, name, old, new): - """ Handle the destruction of the wrapper. - """ + """ Handle the destruction of the wrapper. """ if name == 'control' and new is None: self._wrappers.remove(object) @@ -97,8 +86,17 @@ ########################################################################### def add_to_menu(self, parent, menu, controller): - """ Adds the item to a menu. """ + """ Add the item to a menu. + Parameters + ---------- + parent : toolkit control + The parent of the new menu item control. + menu : toolkit menu + The menu to add the action item to. + controller : ActionController instance or None + The controller to use. + """ if (controller is None) or controller.can_add_to_menu(self.action): wrapper = _MenuItem(parent, menu, self, controller) @@ -109,12 +107,23 @@ self._wrappers.append(wrapper) - return - def add_to_toolbar(self, parent, tool_bar, image_cache, controller, show_labels=True): - """ Adds the item to a tool bar. """ + """ Adds the item to a tool bar. + Parameters + ---------- + parent : toolkit control + The parent of the new menu item control. + tool_bar : toolkit toolbar + The toolbar to add the action item to. + image_cache : ImageCache instance + The image cache for resized images. + controller : ActionController instance or None + The controller to use. + show_labels : bool + Should the toolbar item show a label. + """ if (controller is None) or controller.can_add_to_toolbar(self.action): wrapper = _Tool( parent, tool_bar, image_cache, self, controller, show_labels @@ -127,25 +136,26 @@ self._wrappers.append(wrapper) - return - def add_to_palette(self, tool_palette, image_cache, show_labels=True): - """ Adds the item to a tool palette. """ + """ Adds the item to a tool palette. + Parameters + ---------- + parent : toolkit control + The parent of the new menu item control. + tool_palette : toolkit tool palette + The tool palette to add the action item to. + image_cache : ImageCache instance + The image cache for resized images. + show_labels : bool + Should the toolbar item show a label. + """ wrapper = _PaletteTool(tool_palette, image_cache, self, show_labels) - self._wrappers.append(wrapper) - return - def destroy(self): """ Called when the action is no longer required. By default this method calls 'destroy' on the action itself. """ - self.action.destroy() - - return - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/action/action_manager_item.py python-pyface-6.1.2/pyface/action/action_manager_item.py --- python-pyface-4.5.2/pyface/action/action_manager_item.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/action_manager_item.py 2019-05-03 08:18:49.000000000 +0000 @@ -31,17 +31,17 @@ """ - # The item's unique identifier ('unique' in this case means unique within - # its group) + #: The item's unique identifier ('unique' in this case means unique within + #: its group) id = Str - # The group the item belongs to. + #: The group the item belongs to. parent = Instance('pyface.action.api.Group') - # Is the item enabled? + #: Is the item enabled? enabled = Bool(True) - # Is the item visible? + #: Is the item visible? visible = Bool(True) ########################################################################### @@ -49,13 +49,33 @@ ########################################################################### def add_to_menu(self, parent, menu, controller): - """ Adds the item to a menu. """ + """ Adds the item to a menu. + Parameters + ---------- + parent : toolkit control + The parent of the new menu item control. + menu : toolkit menu + The menu to add the action item to. + controller : ActionController instance or None + The controller to use. + """ raise NotImplementedError def add_to_toolbar(self, parent, tool_bar, image_cache, controller): - """ Adds the item to a tool bar. """ + """ Adds the item to a tool bar. + Parameters + ---------- + parent : toolkit control + The parent of the new menu item control. + tool_bar : toolkit toolbar + The toolbar to add the action item to. + image_cache : ImageCache instance + The image cache for resized images. + controller : ActionController instance or None + The controller to use. + show_labels : bool + Should the toolbar item show a label. + """ raise NotImplementedError - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/action/action_manager.py python-pyface-6.1.2/pyface/action/action_manager.py --- python-pyface-4.5.2/pyface/action/action_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/action_manager.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,12 +15,14 @@ # Enthought library imports. +from __future__ import print_function from traits.api import Bool, Constant, Event, HasTraits, Instance from traits.api import List, Property, Str # Local imports. -from action_controller import ActionController -from group import Group +from pyface.action.action_controller import ActionController +from pyface.action.group import Group +import six class ActionManager(HasTraits): @@ -39,32 +41,32 @@ #### 'ActionManager' interface ############################################ - # The Id of the default group. + #: The Id of the default group. DEFAULT_GROUP = Constant('additions') - # The action controller (if any) used to control how actions are performed. + #: The action controller (if any) used to control how actions are performed. controller = Instance(ActionController) - # Is the action manager enabled? + #: Is the action manager enabled? enabled = Bool(True) - # All of the contribution groups in the manager. + #: All of the contribution groups in the manager. groups = Property(List(Group)) - # The manager's unique identifier (if it has one). + #: The manager's unique identifier (if it has one). id = Str - # Is the action manager visible? + #: Is the action manager visible? visible = Bool(True) #### Events #### - # fixme: We probably need more granular events than this! + #: fixme: We probably need more granular events than this! changed = Event #### Private interface #################################################### - # All of the contribution groups in the manager. + #: All of the contribution groups in the manager. _groups = List(Group) ########################################################################### @@ -72,8 +74,23 @@ ########################################################################### def __init__(self, *args, **traits): - """ Creates a new menu manager. """ + """ Creates a new action manager. + Parameters + ---------- + args : collection of strings, Group instances, or ActionManagerItem instances + Positional arguments are interpreted as Items or Groups managed + by the action manager. + + Notes + ----- + + If a Group is passed as a positional agrument then it is added to the + manager and any subsequent Items arguments are appended to the Group + until another Group is encountered. + + If a string is passed, a Group is created with id set to the string. + """ # Base class constructor. super(ActionManager, self).__init__(**traits) @@ -87,7 +104,7 @@ for arg in args: # We allow a group to be defined by simply specifying a string (its # Id). - if isinstance(arg, basestring): + if isinstance(arg, six.string_types): # Create a group with the specified Id. arg = Group(id=arg) @@ -109,8 +126,6 @@ group.append(arg) - return - ########################################################################### # 'ActionManager' interface. ########################################################################### @@ -118,206 +133,247 @@ #### Trait properties ##################################################### def _get_groups(self): - """ Returns the groups in the manager. """ - return self._groups[:] #### Trait change handlers ################################################ def _enabled_changed(self, trait_name, old, new): - """ Static trait change handler. """ - for group in self._groups: group.enabled = new - return - def _visible_changed(self, trait_name, old, new): - """ Static trait change handler. """ - for group in self._groups: group.visible = new - return - #### Methods ############################################################## def append(self, item): """ Append an item to the manager. - See the documentation for 'insert'. - + Parameters + ---------- + item : string, Group instance or ActionManagerItem instance + The item to append. + + Notes + ----- + + If the item is a group, the Group is appended to the manager's list + of groups. It the item is a string, then a group is created with + the string as the ``id`` and the new group is appended to the list + of groups. If the item is an ActionManagerItem then the item is + appended to the manager's defualt group. """ + item = self._prepare_item(item) + if isinstance(item, Group): + group = self._groups - return self.insert(len(self._groups), item) + else: + group = self._get_default_group() + + group.append(item) + return group def destroy(self): """ Called when the manager is no longer required. By default this method simply calls 'destroy' on all of the manager's groups. - """ - for group in self.groups: group.destroy() - return - def insert(self, index, item): """ Insert an item into the manager at the specified index. - The item can be:- - - 1) A 'Group' instance. - - In which case the group is inserted into the manager's list of - groups. - - 2) A string. - - In which case a 'Group' instance is created with that Id, and then - inserted into the manager's list of groups. - - 3) An 'ActionManagerItem' instance. - - In which case the item is inserted into the manager's default - group. - + Parameters + ---------- + index : int + The position at which to insert the object + item : string, Group instance or ActionManagerItem instance + The item to insert. + + Notes + ----- + + If the item is a group, the Group is inserted into the manager's list + of groups. It the item is a string, then a group is created with + the string as the ``id`` and the new group is inserted into the list + of groups. If the item is an ActionManagerItem then the item is + inserted into the manager's defualt group. """ + item = self._prepare_item(item) - # 1) The item is a 'Group' instance. if isinstance(item, Group): - group = item - - # Insert the group into the manager. - group.parent = self - self._groups.insert(index, item) - - # 2) The item is a string. - elif isinstance(item, basestring): - # Create a group with that Id. - group = Group(id=item) + group = self._groups - # Insert the group into the manager. - group.parent = self - self._groups.insert(index, group) - - # 3) The item is an 'ActionManagerItem' instance. else: - # Find the default group. group = self._get_default_group() - # Insert the item into the default group. - group.insert(index, item) - + group.insert(index, item) return group def find_group(self, id): - """ Return the group with the specified Id. - - Return None if no such group exists. + """ Find a group with a specified Id. + Parameters + ---------- + id : str + The id of the group to find. + + Returns + ------- + group : Group instance + The group which matches the id, or None if no such group exists. """ - for group in self._groups: if group.id == id: - break - + return group else: - group = None - - return group + return None def find_item(self, path): - """ Return the item found at the specified path. - - 'path' is a '/' separated list of contribution Ids. - - Returns None if any component of the path is not found. + """ Find an item using a path. + Parameters + ---------- + path : str + A '/' separated list of contribution Ids. + + Returns + ------- + item : ActionManagerItem or None + Returns the matching ActionManagerItem, or None if any component + of the path is not found. """ - components = path.split('/') # If there is only one component, then the path is just an Id so look # it up in this manager. if len(components) > 0: item = self._find_item(components[0]) - if len(components) > 1 and item is not None: item = item.find_item('/'.join(components[1:])) - else: item = None return item def walk(self, fn): - """ Walk the manager applying a function at every item. """ + """ Walk the manager applying a function at every item. + The components are walked in pre-order. + + Parameters + ---------- + fn : callable + A callable to apply to the tree of groups and items, starting with + the manager. + """ fn(self) for group in self._groups: self.walk_group(group, fn) - return - def walk_group(self, group, fn): - """ Walk a group applying a function at every item. """ + """ Walk a group applying a function at every item. + + The components are walked in pre-order. + Parameters + ---------- + fn : callable + A callable to apply to the tree of groups and items. + """ fn(group) for item in group.items: if isinstance(item, Group): self.walk_group(item, fn) - else: self.walk_item(item, fn) - return - def walk_item(self, item, fn): - """ Walk an item (may be a sub-menu manager remember!). """ + """ Walk an item (may be a sub-menu manager remember!). + The components are walked in pre-order. + + Parameters + ---------- + fn : callable + A callable to apply to the tree of items and subgroups. + """ if hasattr(item, 'groups'): item.walk(fn) - else: fn(item) - return - ########################################################################### # Private interface. ########################################################################### def _get_default_group(self): - """ Returns the manager's default group. """ + """ Returns the manager's default group. + + This will create this group if it doesn't already exist. + Returns + ------- + group : Group instance + The manager's default group. + """ group = self.find_group(self.DEFAULT_GROUP) if group is None: - group = Group(id=self.DEFAULT_GROUP) - self.append(group) + group = self._prepare_item(self.DEFAULT_GROUP) + self._groups.append(group) return group - def _find_item(self, id): - """ Returns the item with the specified Id. - - Returns None if no such item exists. + def _prepare_item(self, item): + """ Prepare an item to be added to this ActionManager. + Parameters + ---------- + item : string, Group instance or ActionManagerItem instance + The item to be added to this ActionManager + + Returns + ------- + item : Group or ActionManagerItem + Modified item """ + # 1) The item is a 'Group' instance. + if isinstance(item, Group): + item.parent = self + + # 2) The item is a string. + elif isinstance(item, six.string_types): + # Create a group with that Id. + item = Group(id=item) + item.parent = self + + return item + + def _find_item(self, id): + """ Find an item with a spcified Id. + Parameters + ---------- + id : str + The id of the item to be found. + + Returns + ------- + item : ActionManagerItem or None + Returns the item with the specified Id, or None if no such item + exists. + """ for group in self.groups: item = group.find(id) if item is not None: - break - + return item else: - item = None - - return item + return None ########################################################################### # Debugging interface. @@ -325,31 +381,25 @@ def dump(self, indent=''): """ Render a manager! """ - - print indent, 'Manager', self.id + print(indent, 'Manager', self.id) indent += ' ' for group in self._groups: self.render_group(group, indent) - return - def render_group(self, group, indent=''): """ Render a group! """ - - print indent, 'Group', group.id + print(indent, 'Group', group.id) indent += ' ' for item in group.items: if isinstance(item, Group): - print 'Surely, a group cannot contain another group!!!!' + print('Surely, a group cannot contain another group!!!!') self.render_group(item, indent) else: self.render_item(item, indent) - return - def render_item(self, item, indent=''): """ Render an item! """ @@ -357,8 +407,4 @@ item.dump(indent) else: - print indent, 'Item', item.id - - return - -#### EOF ###################################################################### + print(indent, 'Item', item.id) diff -Nru python-pyface-4.5.2/pyface/action/action.py python-pyface-6.1.2/pyface/action/action.py --- python-pyface-4.5.2/pyface/action/action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/action.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,11 +13,13 @@ #------------------------------------------------------------------------------ """ The base class for all actions. """ +from functools import partial # Enthought library imports. -from traits.api import Bool, Callable, Enum, HasTraits, Instance, Str +from traits.api import Bool, Callable, Enum, HasTraits, Str from traits.api import Unicode -from traitsui.ui_traits import Image + +from pyface.ui_traits import Image class Action(HasTraits): @@ -34,42 +36,45 @@ #### 'Action' interface ################################################### - # Keyboard accelerator (by default the action has NO accelerator). + #: Keyboard accelerator (by default the action has NO accelerator). accelerator = Unicode - # Is the action checked? This is only relevant if the action style is - # 'radio' or 'toggle'. + #: Is the action checked? This is only relevant if the action style is + #: 'radio' or 'toggle'. checked = Bool(False) - # A longer description of the action (used for context sensitive help etc). - # If no description is specified, the tooltip is used instead (and if there - # is no tooltip, then well, maybe you just hate your users ;^). + #: A longer description of the action (used for context sensitive help etc). + #: If no description is specified, the tooltip is used instead (and if there + #: is no tooltip, then well, maybe you just hate your users ;^). description = Unicode - # Is the action enabled? + #: Is the action enabled? enabled = Bool(True) - # Is the action visible? + #: Is the action visible? visible = Bool(True) - # The action's unique identifier (may be None). + #: The action's unique identifier (may be None). id = Str - # The action's image (displayed on tool bar tools etc). + #: The action's image (displayed on tool bar tools etc). image = Image - # The action's name (displayed on menus/tool bar tools etc). + #: The action's name (displayed on menus/tool bar tools etc). name = Unicode - # An (optional) callable that will be invoked when the action is performed. + #: An (optional) callable that will be invoked when the action is performed. on_perform = Callable - # The action's style. - style = Enum('push', 'radio', 'toggle') + #: The action's style. + style = Enum('push', 'radio', 'toggle', 'widget') - # A short description of the action used for tooltip text etc. + #: A short description of the action used for tooltip text etc. tooltip = Unicode + #: An (optional) callable to create the toolkit control for widget style. + control_factory = Callable + ########################################################################### # 'Action' interface. ########################################################################### @@ -77,28 +82,63 @@ #### Initializers ######################################################### def _id_default(self): - """ Initializes the 'id' trait. """ + """ Initializes the 'id' trait. + The default is the ``name`` trait. + """ return self.name #### Methods ############################################################## + def create_control(self, parent): + """ Called when creating a "widget" style action. + + By default this will call whatever callable is supplied via the + 'control_factory' trait which is a callable that should take the parent + control and the action as arguments and return an appropriate toolkit + control. Some operating systems (Mac OS in particular) may limit what + widgets can be displayed in menus. + + This method is only used when the 'style' is "widget" and is ignored by + other styles. + + Parameters + ---------- + parent : toolkit control + The toolkit control, usually a toolbar. + + Returns + ------- + control : toolkit control + A toolkit control or None. + """ + if self.style == 'widget' and self.control_factory is not None: + return self.control_factory(parent, self) + return None + def destroy(self): """ Called when the action is no longer required. By default this method does nothing, but this would be a great place to unhook trait listeners etc. - """ - return - def perform(self, event): - """ Performs the action. """ + """ Performs the action. + Parameters + ---------- + event : ActionEvent instance + The event which triggered the action. + """ if self.on_perform is not None: self.on_perform() - return + @classmethod + def factory(cls, *args, **kwargs): + """ Create a factory for an action with the given arguments. -#### EOF ###################################################################### + This is particularly useful for passing context to Tasks schema + additions. + """ + return partial(cls, *args, **kwargs) \ No newline at end of file diff -Nru python-pyface-4.5.2/pyface/action/api.py python-pyface-6.1.2/pyface/action/api.py --- python-pyface-4.5.2/pyface/action/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/api.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2005-18, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,32 +6,33 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ - -from action import Action -from action_controller import ActionController -from action_event import ActionEvent -from action_item import ActionItem -from action_manager import ActionManager -from action_manager_item import ActionManagerItem -from group import Group, Separator -from menu_manager import MenuManager -from menu_bar_manager import MenuBarManager -from status_bar_manager import StatusBarManager -from tool_bar_manager import ToolBarManager -from window_action import WindowAction +from __future__ import absolute_import +from .action import Action +from .action_controller import ActionController +from .action_event import ActionEvent +from .action_item import ActionItem +from .action_manager import ActionManager +from .action_manager_item import ActionManagerItem +from .field_action import FieldAction +from .group import Group, Separator +from .gui_application_action import ( + AboutAction, CloseActiveWindowAction, CreateWindowAction, ExitAction, + GUIApplicationAction +) +from .listening_action import ListeningAction +from .menu_manager import MenuManager +from .menu_bar_manager import MenuBarManager +from .status_bar_manager import StatusBarManager +from .tool_bar_manager import ToolBarManager +from .traitsui_widget_action import TraitsUIWidgetAction +from .window_action import CloseWindowAction, WindowAction -############################################################################### # This part of the module handles widgets that are still wx specific. This # will all be removed when everything has been ported to PyQt and pyface # becomes toolkit agnostic. -############################################################################### from traits.etsconfig.api import ETSConfig if ETSConfig.toolkit == 'wx': - from tool_palette_manager import ToolPaletteManager + from .tool_palette_manager import ToolPaletteManager diff -Nru python-pyface-4.5.2/pyface/action/field_action.py python-pyface-6.1.2/pyface/action/field_action.py --- python-pyface-4.5.2/pyface/action/field_action.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/field_action.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,75 @@ +# Copyright (c) 2019, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + +from traits.api import Any, Constant, Dict, Str, Type + +from pyface.fields.i_field import IField +from .action import Action +from .action_event import ActionEvent + + +class FieldAction(Action): + """ A widget action containing an IField + + When the value in the field is changed, the `on_peform` method is called + with the new value as the argument. + """ + + #: This is a widget action. + style = Constant("widget") + + #: The field to display. + field_type = Type(IField) + + #: The default trait values for the field. + field_defaults = Dict(Str, Any) + + def create_control(self, parent): + """ Called when creating a "widget" style action. + + This constructs an IField-based control directly and binds changes to + the value to the `value_updated` method. + + Parameters + ---------- + parent : toolkit control + The toolkit control, usually a toolbar. + + Returns + ------- + control : toolkit control + A toolkit control or None. + """ + field = self.field_type(parent=parent, **self.field_defaults) + field._create() + field.on_trait_change(self.value_updated, 'value') + field.control._field = field + return field.control + + def value_updated(self, value): + """ Handle changes to the field value by calling perform. + + The event passed to `perform` has the `value` as an attribute. + """ + action_event = ActionEvent(value=value) + self.perform(action_event) + + def perform(self, event): + """ Performs the action. + + This dispacthes to the on_perform method with the new value passed + as an argument. + + Parameters + ---------- + event : ActionEvent instance + The event which triggered the action. + """ + if self.on_perform is not None: + self.on_perform(event.value) diff -Nru python-pyface-4.5.2/pyface/action/group.py python-pyface-6.1.2/pyface/action/group.py --- python-pyface-4.5.2/pyface/action/group.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/group.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,6 +13,7 @@ #------------------------------------------------------------------------------ """ A group of action manager items. """ +from functools import partial # Enthought library imports. from traits.api import Any, Bool, HasTraits, Instance, List, Property @@ -20,9 +21,9 @@ from traits.trait_base import user_name_for # Local imports. -from action import Action -from action_item import ActionItem -from action_manager_item import ActionManagerItem +from pyface.action.action import Action +from pyface.action.action_item import ActionItem +from pyface.action.action_manager_item import ActionManagerItem class Group(HasTraits): @@ -36,37 +37,42 @@ #### 'Group' interface #### - # Is the group enabled? + #: Is the group enabled? enabled = Bool(True) - # Is the group visible? + #: Is the group visible? visible = Bool(True) - # The group's unique identifier (only needs to be unique within the action - # manager that the group belongs to). + #: The group's unique identifier (only needs to be unique within the action + #: manager that the group belongs to). id = Str - # All of the items in the group. + #: All of the items in the group. items = Property - # The action manager that the group belongs to. - parent = Any#Instance('pyface.action.ActionManager') + #: The action manager that the group belongs to. + parent = Any #Instance('pyface.action.ActionManager') - # Does this group require a separator when it is visualized? + #: Does this group require a separator when it is visualized? separator = Bool(True) #### Private interface #### - # All of the items in the group. - _items = List#(ActionManagerItem) + #: All of the items in the group. + _items = List #(ActionManagerItem) ########################################################################### # 'object' interface. ########################################################################### - def __init__(self, *items, **traits): - """ Creates a new menu manager. """ + def __init__(self, *items, **traits): + """ Creates a new menu manager. + Parameters + ---------- + items : collection of ActionManagerItems + Items to add to the group. + """ # Base class constructor. super(Group, self).__init__(**traits) @@ -74,8 +80,6 @@ for item in items: self.append(item) - return - ########################################################################### # 'Group' interface. ########################################################################### @@ -83,75 +87,78 @@ #### Trait Properties ##################################################### def _get_items(self): - """ Returns the items in the group. """ - return self._items[:] #### Trait change handlers ################################################ def _enabled_changed(self, trait_name, old, new): - """ Static trait change handler. """ - for item in self.items: item.enabled = new - return - #### Methods ############################################################## def append(self, item): """ Appends an item to the group. - See the documentation for 'insert'. - + Parameters + ---------- + item : ActionManagerItem, Action or callable + The item to append. + + Returns + ------- + item : ActionManagerItem + The actually inserted item. + + Notes + ----- + If the item is an ActionManagerItem instance it is simply appended. + If the item is an Action instance, an ActionItem is created for the + action, and that is appended. If the item is a callable, then an + Action is created for the callable, and then that is handled as above. """ - return self.insert(len(self._items), item) def clear(self): """ Remove all items from the group. """ - self._items = [] - return - def destroy(self): """ Called when the manager is no longer required. By default this method simply calls 'destroy' on all items in the group. - """ - for item in self.items: item.destroy() - return - def insert(self, index, item): """ Inserts an item into the group at the specified index. - 1) An 'ActionManagerItem' instance. - - In which case the item is simply inserted into the group. - - 2) An 'Action' instance. - - In which case an 'ActionItem' instance is created with the action - and then inserted into the group. - - 3) A Python callable (ie.'callable(item)' returns True). - - In which case an 'Action' is created that calls the callable when - it is performed, and the action is then wrapped as in 2). - + Parameters + ---------- + index : int + The position to insert the item. + item : ActionManagerItem, Action or callable + The item to insert. + + Returns + ------- + item : ActionManagerItem + The actually inserted item. + + Notes + ----- + + If the item is an ActionManagerItem instance it is simply inserted. + If the item is an Action instance, an ActionItem is created for the + action, and that is inserted. If the item is a callable, then an + Action is created for the callable, and then that is handled as above. """ - if isinstance(item, Action): item = ActionItem(action=item) - elif callable(item): - name = user_name_for(item.func_name) + name = user_name_for(item.__name__) item = ActionItem(action=Action(name=name, on_perform=item)) item.parent = self @@ -160,54 +167,97 @@ return item def remove(self, item): - """ Removes an item from the group. """ + """ Removes an item from the group. + Parameters + ---------- + item : ActionManagerItem + The item to remove. + """ self._items.remove(item) item.parent = None - return - def insert_before(self, before, item): """ Inserts an item into the group before the specified item. - See the documentation for 'insert'. - + Parameters + ---------- + before : ActionManagerItem + The item to insert before. + item : ActionManagerItem, Action or callable + The item to insert. + + Returns + ------- + index, item : int, ActionManagerItem + The position inserted, and the item actually inserted. + + Notes + ----- + + If the item is an ActionManagerItem instance it is simply inserted. + If the item is an Action instance, an ActionItem is created for the + action, and that is inserted. If the item is a callable, then an + Action is created for the callable, and then that is handled as above. """ - index = self._items.index(before) - self.insert(index, item) - return (index, item) def insert_after(self, after, item): """ Inserts an item into the group after the specified item. - See the documentation for 'insert'. - + Parameters + ---------- + before : ActionManagerItem + The item to insert after. + item : ActionManagerItem, Action or callable + The item to insert. + + Returns + ------- + index, item : int, ActionManagerItem + The position inserted, and the item actually inserted. + + Notes + ----- + + If the item is an ActionManagerItem instance it is simply inserted. + If the item is an Action instance, an ActionItem is created for the + action, and that is inserted. If the item is a callable, then an + Action is created for the callable, and then that is handled as above. """ - index = self._items.index(after) - self.insert(index + 1, item) - return (index, item) def find(self, id): - """ Returns the item with the specified Id. - - Returns None if no such item exists. + """ Find the item with the specified id. + Parameters + ---------- + id : str + The id of the item + + Returns + ------- + item : ActionManagerItem + The item with the specified Id, or None if no such item exists. """ - for item in self._items: if item.id == id: - break - + return item else: - item = None + return None - return item + @classmethod + def factory(cls, *args, **kwargs): + """ Create a factory for a group with the given arguments. + + This is particularly useful for passing context to Tasks schema + additions. + """ + return partial(cls, *args, **kwargs) class Separator(Group): @@ -223,9 +273,5 @@ ) Hopefully, 'Separator' is more readable than 'Group'... - """ - pass - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/action/gui_application_action.py python-pyface-6.1.2/pyface/action/gui_application_action.py --- python-pyface-4.5.2/pyface/action/gui_application_action.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/gui_application_action.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,101 @@ +# Copyright (c) 2005-2018, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +""" Abstract base class for all application actions. """ + +import platform + +# Enthought library imports. +from traits.api import Instance, Property, cached_property + +# Local imports. +from pyface.action.listening_action import ListeningAction + +IS_WINDOWS = platform.system() == 'Windows' + + +class GUIApplicationAction(ListeningAction): + """ Abstract base class for GUI Application actions. """ + + # 'ListeningAction' interface -------------------------------------------- + + object = Property(depends_on='application') + + # 'WindowAction' interface ----------------------------------------------- + + #: The application that the action is associated with. + application = Instance('pyface.gui_application.GUIApplication') + + # ------------------------------------------------------------------------ + # Protected interface. + # ------------------------------------------------------------------------ + + def _get_object(self): + return self.application + + def destroy(self): + # Disconnect listeners to application and dependent properties. + self.application = None + super(GUIApplicationAction, self).destroy() + + +class ActiveWindowAction(GUIApplicationAction): + """ Abstract base class for application active window actions. """ + + # 'ListeningAction' interface -------------------------------------------- + + object = Property(depends_on='application.active_window') + + # ------------------------------------------------------------------------ + # Protected interface. + # ------------------------------------------------------------------------ + + @cached_property + def _get_object(self): + if self.application is not None: + return self.application.active_window + + +class CreateWindowAction(GUIApplicationAction): + """ A standard 'New Window' menu action. """ + name = u'New Window' + accelerator = 'Ctrl+N' + + def perform(self, event=None): + window = self.application.create_window() + self.application.add_window(window) + + +class ExitAction(GUIApplicationAction): + """ A standard 'Quit' or 'Exit' menu action. """ + accelerator = 'Alt+F4' if IS_WINDOWS else 'Ctrl+Q' + method = 'exit' + + def _name_default(self): + return (u'Exit ' if IS_WINDOWS else u'Quit ') + self.application.name + + +class AboutAction(GUIApplicationAction): + """ A standard 'About' dialog menu action. """ + method = 'do_about' + + def _name_default(self): + return u"About " + self.application.name + + +class CloseActiveWindowAction(ActiveWindowAction): + """ A standard 'Close window' menu action at the application level. + + This method closes the active window of the application. + """ + name = u'Close Window' + accelerator = 'Ctrl+W' + method = 'close' diff -Nru python-pyface-4.5.2/pyface/action/listening_action.py python-pyface-6.1.2/pyface/action/listening_action.py --- python-pyface-4.5.2/pyface/action/listening_action.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/listening_action.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,149 @@ +# Copyright (c) 2005-2018, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: + +# Standard library imports. +import logging + +# Enthought library imports. +from pyface.action.action import Action +from traits.api import Any, Str + +# Logging. +logger = logging.getLogger(__name__) + + +class ListeningAction(Action): + """ An Action that listens and makes a callback to an object. + """ + + # ListeningAction interface ---------------------------------------------- + + #: The (extended) name of the method to call. By default, the on_perform + #: function will be called with the event. + method = Str + + #: The (extended) name of the attribute that determines whether the action + #: is enabled. By default, the action is always enabled when an object is + #: set. + enabled_name = Str + + #: The (extended) name of the attribute that determines whether the action + #: is visible. By default, the action is always visible. + visible_name = Str + + #: The object to which the names above apply. + object = Any + + # ------------------------------------------------------------------------- + # 'Action' interface. + # ------------------------------------------------------------------------- + + def destroy(self): + """ Called when the action is no longer required. + + Removes all the task listeners. + """ + + if self.object: + self.object.on_trait_change( + self._enabled_update, self.enabled_name, remove=True + ) + self.object.on_trait_change( + self._visible_update, self.visible_name, remove=True + ) + + def perform(self, event=None): + """ Call the appropriate function. + + This looks for a method to call based on the extended method name + stored in the :py:attr:`method` trait. If the method is empty, then + this follows the usual Action method resolution. + """ + if self.method != '': + method = self._get_attr(self.object, self.method) + if method: + method() + else: + super(ListeningAction, self).perform(event) + + # ------------------------------------------------------------------------- + # Protected interface. + # ------------------------------------------------------------------------- + + def _get_attr(self, obj, name, default=None): + """ Perform an extended look up of a dotted name. """ + try: + for attr in name.split('.'): + # Perform the access in the Trait name style: if the object is + # None, assume it simply hasn't been initialized and don't show + # the warning. + if obj is None: + return default + else: + obj = getattr(obj, attr) + except AttributeError: + logger.error("Did not find name %r on %r" % (attr, obj)) + return default + return obj + + # Trait change handlers -------------------------------------------------- + + def _enabled_name_changed(self, old, new): + obj = self.object + if obj is not None: + if old: + obj.on_trait_change(self._enabled_update, old, remove=True) + if new: + obj.on_trait_change(self._enabled_update, new) + self._enabled_update() + + def _visible_name_changed(self, old, new): + obj = self.object + if obj is not None: + if old: + obj.on_trait_change(self._visible_update, old, remove=True) + if new: + obj.on_trait_change(self._visible_update, new) + self._visible_update() + + def _object_changed(self, old, new): + for kind in ('enabled', 'visible'): + method = getattr(self, '_%s_update' % kind) + name = getattr(self, '%s_name' % kind) + if name: + if old: + old.on_trait_change(method, name, remove=True) + if new: + new.on_trait_change(method, name) + method() + + def _enabled_update(self): + if self.enabled_name: + if self.object: + self.enabled = bool( + self._get_attr(self.object, self.enabled_name, False) + ) + else: + self.enabled = False + else: + self.enabled = bool(self.object) + + def _visible_update(self): + if self.visible_name: + if self.object: + self.visible = bool( + self._get_attr(self.object, self.visible_name, False) + ) + else: + self.visible = False + else: + self.visible = True diff -Nru python-pyface-4.5.2/pyface/action/tests/test_action_controller.py python-pyface-6.1.2/pyface/action/tests/test_action_controller.py --- python-pyface-4.5.2/pyface/action/tests/test_action_controller.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/tests/test_action_controller.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,6 +1,6 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest +import unittest from ..action import Action from ..action_controller import ActionController diff -Nru python-pyface-4.5.2/pyface/action/tests/test_action_event.py python-pyface-6.1.2/pyface/action/tests/test_action_event.py --- python-pyface-4.5.2/pyface/action/tests/test_action_event.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/tests/test_action_event.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,8 +1,7 @@ from __future__ import absolute_import import time - -from traits.testing.unittest_tools import unittest +import unittest from ..action_event import ActionEvent diff -Nru python-pyface-4.5.2/pyface/action/tests/test_action_item.py python-pyface-6.1.2/pyface/action/tests/test_action_item.py --- python-pyface-4.5.2/pyface/action/tests/test_action_item.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/tests/test_action_item.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,9 +1,13 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import UnittestTools, unittest +import unittest -from ...image_cache import ImageCache -from ...window import Window +from traits.testing.unittest_tools import UnittestTools + +from pyface.image_cache import ImageCache +from pyface.toolkit import toolkit_object +from pyface.widget import Widget +from pyface.window import Window from ..action import Action from ..action_controller import ActionController from ..action_item import ActionItem @@ -37,6 +41,17 @@ self.action = Action(name='Test', on_perform=perform) + def control_factory(self, parent, action): + if toolkit_object.toolkit == 'wx': + import wx + control = wx.Control(parent) + elif toolkit_object.toolkit == 'qt4': + from pyface.qt import QtGui + control = QtGui.QWidget(parent) + else: + control = None + return control + def test_default_id(self): action_item = ActionItem(action=self.action) self.assertEqual(action_item.id, 'Test') @@ -144,3 +159,19 @@ action_item.add_to_toolbar(window.control, menu, image_cache, controller, True) window.close() + + def test_add_to_toolbar_widget(self): + self.action.style = "widget" + self.action.control_factory = self.control_factory + + window = Window() + window.open() + action_item = ActionItem(action=self.action) + toolbar_manager = ToolBarManager(name='Test') + image_cache = ImageCache(height=32, width=32) + menu = toolbar_manager.create_tool_bar(window.control) + + try: + action_item.add_to_toolbar(window.control, menu, image_cache, None, True) + finally: + window.close() diff -Nru python-pyface-4.5.2/pyface/action/tests/test_action_manager.py python-pyface-6.1.2/pyface/action/tests/test_action_manager.py --- python-pyface-4.5.2/pyface/action/tests/test_action_manager.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/tests/test_action_manager.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,6 +1,8 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import UnittestTools, unittest +import unittest + +from traits.testing.unittest_tools import UnittestTools from ..action import Action from ..action_item import ActionItem @@ -101,6 +103,20 @@ self.assertEqual(action_manager.groups, [default_group, self.group]) self.assertEqual(default_group.items, [self.action_item]) + def test_append_item_order(self): + # Regression test for enthought/pyface#289 + expected = [ + self.action_item, + ActionItem(action=Action(name="Test2")), + ActionItem(action=Action(name="Test3")), + ] + action_manager = ActionManager() + for item in expected: + action_manager.append(item) + + default_group = action_manager._get_default_group() + self.assertEqual(default_group.items, expected) + def test_destroy(self): action_manager = ActionManager(self.group) # XXX items doesn't fire a change event. Should it? diff -Nru python-pyface-4.5.2/pyface/action/tests/test_action.py python-pyface-6.1.2/pyface/action/tests/test_action.py --- python-pyface-4.5.2/pyface/action/tests/test_action.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/tests/test_action.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,6 +1,6 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest +import unittest from ..action import Action from ..action_event import ActionEvent @@ -39,3 +39,21 @@ action = Action(name='Test') # does nothing, but shouldn't error action.destroy() + + def test_widget_action(self): + # test whether function is called by updating list + # XXX should really use mock + memo = [] + + def control_factory(parent, action): + memo.append((parent, action)) + + action = Action( + name="Dummy", + style='widget', + control_factory=control_factory + ) + parent = None + action.create_control(parent) + + self.assertEqual(memo, [(parent, action)]) diff -Nru python-pyface-4.5.2/pyface/action/tests/test_field_action.py python-pyface-6.1.2/pyface/action/tests/test_field_action.py --- python-pyface-4.5.2/pyface/action/tests/test_field_action.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/tests/test_field_action.py 2019-06-14 12:22:56.000000000 +0000 @@ -0,0 +1,121 @@ +# Copyright (c) 2019, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +import unittest + +from pyface.fields.api import ComboField, SpinField, TextField +from pyface.gui import GUI +from pyface.window import Window +from ..field_action import FieldAction + + +class TestFieldAction(unittest.TestCase): + + def setUp(self): + self.gui = GUI() + + self.parent = Window() + self.parent._create() + self.addCleanup(self._destroy_parent) + + def _destroy_parent(self): + self.parent.destroy() + self.parent = None + + def test_combo_field_action(self): + # test whether function is called by updating list + # XXX should really use mock + memo = [] + + def perform(value): + memo.append(value) + + action = FieldAction( + name="Dummy", + field_type=ComboField, + field_defaults={ + 'values': ['a', 'b', 'c'], + 'value': 'a', + 'tooltip': 'Dummy', + }, + on_perform=perform, + ) + control = action.create_control(self.parent.control) + try: + self.gui.process_events() + + control._field.value = 'b' + self.gui.process_events() + + self.assertEqual(memo, ['b']) + finally: + control._field.destroy() + + def test_text_field_action(self): + # test whether function is called by updating list + # XXX should really use mock + memo = [] + + def perform(value): + memo.append(value) + + action = FieldAction( + name="Dummy", + field_type=TextField, + field_defaults={ + 'value': 'a', + 'tooltip': 'Dummy', + }, + on_perform=perform, + ) + control = action.create_control(self.parent.control) + + try: + self.gui.process_events() + + control._field.value = 'b' + self.gui.process_events() + + self.assertEqual(memo, ['b']) + finally: + control._field.destroy() + + def test_spin_field_action(self): + # test whether function is called by updating list + # XXX should really use mock + memo = [] + + def perform(value): + memo.append(value) + + action = FieldAction( + name="Dummy", + field_type=SpinField, + field_defaults={ + 'value': 1, + 'bounds': (0, 100), + 'tooltip': 'Dummy', + }, + on_perform=perform, + ) + control = action.create_control(self.parent.control) + + try: + self.gui.process_events() + + control._field.value = 5 + self.gui.process_events() + + self.assertEqual(memo, [5]) + finally: + control._field.destroy() diff -Nru python-pyface-4.5.2/pyface/action/tests/test_group.py python-pyface-6.1.2/pyface/action/tests/test_group.py --- python-pyface-4.5.2/pyface/action/tests/test_group.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/tests/test_group.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,6 +1,8 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import UnittestTools, unittest +import unittest + +from traits.testing.unittest_tools import UnittestTools from ..action import Action from ..action_item import ActionItem diff -Nru python-pyface-4.5.2/pyface/action/tests/test_gui_application_action.py python-pyface-6.1.2/pyface/action/tests/test_gui_application_action.py --- python-pyface-4.5.2/pyface/action/tests/test_gui_application_action.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/tests/test_gui_application_action.py 2019-06-14 12:22:56.000000000 +0000 @@ -0,0 +1,58 @@ +from __future__ import absolute_import + +import unittest + +from traits.testing.unittest_tools import UnittestTools + +from pyface.gui_application import GUIApplication +from ..gui_application_action import GUIApplicationAction +from ..action_event import ActionEvent + + +class TestAction(unittest.TestCase, UnittestTools): + def setUp(self): + self.application = GUIApplication() + + def test_defaults(self): + action = GUIApplicationAction() + event = ActionEvent() + + # does nothing, but shouldn't error + action.perform(event) + + self.assertTrue(action.enabled) + self.assertTrue(action.visible) + self.assertIsNone(action.object) + + def test_application(self): + action = GUIApplicationAction(application=self.application) + event = ActionEvent() + + # does nothing, but shouldn't error + action.perform(event) + + self.assertTrue(action.enabled) + self.assertTrue(action.visible) + self.assertEqual(action.object, self.application) + + def test_application_changed(self): + action = GUIApplicationAction() + + self.assertIsNone(action.object) + + with self.assertTraitChanges(action, 'object', 1): + action.application = self.application + + self.assertEqual(action.object, self.application) + + with self.assertTraitChanges(action, 'object', 1): + action.application = None + + self.assertIsNone(action.object) + + def test_destroy(self): + action = GUIApplicationAction(application=self.application) + + action.destroy() + + self.assertEqual(action.object, None) \ No newline at end of file diff -Nru python-pyface-4.5.2/pyface/action/tests/test_listening_action.py python-pyface-6.1.2/pyface/action/tests/test_listening_action.py --- python-pyface-4.5.2/pyface/action/tests/test_listening_action.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/tests/test_listening_action.py 2019-06-14 12:22:56.000000000 +0000 @@ -0,0 +1,241 @@ +from __future__ import absolute_import + +import unittest + +from traits.api import Any, Bool, HasTraits +from traits.testing.unittest_tools import UnittestTools + +from ..listening_action import ListeningAction +from ..action_event import ActionEvent + + +class WatchedObject(HasTraits): + + #: Trait to watch for enabled state + is_enabled = Bool(True) + + #: Other trait to watch for enabled state + is_also_enabled = Bool(True) + + #: Trait to watch for visible state + is_visible = Bool(True) + + #: Other trait to watch for visible state + is_also_visible = Bool(True) + + #: Flag that is set when method called + was_called = Bool + + #: Child object to test dotted lookup + child = Any + + def callback(self): + self.was_called = True + + +class TestListeningAction(unittest.TestCase, UnittestTools): + def setUp(self): + self.object = WatchedObject() + + def perform_with_callback(self, action): + # test whether function is called by updating list + # XXX should really use mock + memo = [] + + def perform(): + memo.append('called') + + action.on_perform = perform + event = ActionEvent() + + action.perform(event) + + return memo + + def test_defaults(self): + action = ListeningAction() + event = ActionEvent() + + # does nothing, but shouldn't error + action.perform(event) + + self.assertTrue(action.enabled) + self.assertTrue(action.visible) + + def test_perform_no_object(self): + action = ListeningAction() + + memo = self.perform_with_callback(action) + + self.assertEqual(memo, ['called']) + + def test_perform_no_method(self): + action = ListeningAction(object=self.object) + + memo = self.perform_with_callback(action) + + self.assertFalse(self.object.was_called) + self.assertEqual(memo, ['called']) + + def test_perform_method(self): + action = ListeningAction(object=self.object, method='callback') + + memo = self.perform_with_callback(action) + + self.assertTrue(self.object.was_called) + self.assertEqual(memo, []) + + def test_perform_method_missing(self): + action = ListeningAction(object=self.object, method='fallback') + + # does nothing, but shouldn't error + memo = self.perform_with_callback(action) + + self.assertFalse(self.object.was_called) + self.assertEqual(memo, []) + + def test_perform_child_method(self): + self.object.child = WatchedObject() + action = ListeningAction(object=self.object, method='child.callback') + + memo = self.perform_with_callback(action) + + self.assertTrue(self.object.child.was_called) + self.assertFalse(self.object.was_called) + self.assertEqual(memo, []) + + def test_perform_missing_child_method(self): + action = ListeningAction(object=self.object, method='child.callback') + + # does nothing, but shouldn't error + memo = self.perform_with_callback(action) + + self.assertFalse(self.object.was_called) + self.assertEqual(memo, []) + + def test_enabled(self): + action = ListeningAction(object=self.object, enabled_name='is_enabled') + + self.assertTrue(action.enabled) + + with self.assertTraitChanges(action, 'enabled', 1): + self.object.is_enabled = False + + self.assertFalse(action.enabled) + + with self.assertTraitChanges(action, 'enabled', 1): + self.object.is_enabled = True + + self.assertTrue(action.enabled) + + def test_enabled_child(self): + self.object.child = WatchedObject() + action = ListeningAction( + object=self.object, enabled_name='child.is_enabled' + ) + + self.assertTrue(action.enabled) + + with self.assertTraitChanges(action, 'enabled', 1): + self.object.child.is_enabled = False + + self.assertFalse(action.enabled) + + with self.assertTraitChanges(action, 'enabled', 1): + self.object.child.is_enabled = True + + self.assertTrue(action.enabled) + + def test_enabled_missing_child(self): + action = ListeningAction( + object=self.object, enabled_name='child.is_enabled' + ) + + self.assertFalse(action.enabled) + + with self.assertTraitChanges(action, 'enabled', 1): + self.object.child = WatchedObject() + + self.assertTrue(action.enabled) + + with self.assertTraitChanges(action, 'enabled', 1): + self.object.child = None + + self.assertFalse(action.enabled) + + def test_enabled_name_change(self): + self.object.is_also_enabled = False + action = ListeningAction(object=self.object, enabled_name='is_enabled') + + self.assertTrue(action.enabled) + + with self.assertTraitChanges(action, 'enabled', 1): + action.enabled_name = 'is_also_enabled' + + self.assertFalse(action.enabled) + + def test_visible(self): + action = ListeningAction(object=self.object, visible_name='is_visible') + + self.assertTrue(action.visible) + + with self.assertTraitChanges(action, 'visible', 1): + self.object.is_visible = False + + self.assertFalse(action.visible) + + with self.assertTraitChanges(action, 'visible', 1): + self.object.is_visible = True + + self.assertTrue(action.visible) + + def test_visible_child(self): + self.object.child = WatchedObject() + action = ListeningAction( + object=self.object, visible_name='child.is_visible' + ) + + self.assertTrue(action.visible) + + with self.assertTraitChanges(action, 'visible', 1): + self.object.child.is_visible = False + + self.assertFalse(action.visible) + + with self.assertTraitChanges(action, 'visible', 1): + self.object.child.is_visible = True + + self.assertTrue(action.visible) + + def test_visible_missing_child(self): + action = ListeningAction( + object=self.object, visible_name='child.is_visible' + ) + + self.assertFalse(action.visible) + + with self.assertTraitChanges(action, 'visible', 1): + self.object.child = WatchedObject() + + self.assertTrue(action.visible) + + with self.assertTraitChanges(action, 'visible', 1): + self.object.child = None + + self.assertFalse(action.visible) + + def test_visible_name_change(self): + self.object.is_also_visible = False + action = ListeningAction(object=self.object, visible_name='is_visible') + + self.assertTrue(action.visible) + + with self.assertTraitChanges(action, 'visible', 1): + action.visible_name = 'is_also_visible' + + self.assertFalse(action.visible) + + def test_destroy(self): + action = ListeningAction(object=self.object) + + action.destroy() \ No newline at end of file diff -Nru python-pyface-4.5.2/pyface/action/tests/test_traitsui_widget_action.py python-pyface-6.1.2/pyface/action/tests/test_traitsui_widget_action.py --- python-pyface-4.5.2/pyface/action/tests/test_traitsui_widget_action.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/tests/test_traitsui_widget_action.py 2019-06-14 12:22:56.000000000 +0000 @@ -0,0 +1,160 @@ +# Copyright (c) 2019, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +import unittest + +from traits.api import Enum, HasTraits +from traits.testing.unittest_tools import UnittestTools + +from pyface.gui import GUI +from pyface.toolkit import toolkit +from pyface.util.testing import has_traitsui +from pyface.window import Window +from ..traitsui_widget_action import TraitsUIWidgetAction + + +@unittest.skipIf(not has_traitsui(), "TraitsUI not installed") +class TestTraitsUIWidgetAction(unittest.TestCase, UnittestTools): + + def setUp(self): + self.gui = GUI() + self.parent = Window() + self.parent._create() + self.parent.open() + self.addCleanup(self._destroy_parent) + self.gui.process_events() + + def _destroy_parent(self): + self.parent.destroy() + self.gui.process_events() + self.parent = None + + def create_model(self): + from traitsui.api import View, Item + + class SimpleEnum(HasTraits): + value = Enum('a', 'b', 'c') + view = View(Item('value')) + + return SimpleEnum() + + def test_traitsui_widget_action(self): + from traitsui.api import View, Item + + class SimpleEnumAction(TraitsUIWidgetAction): + value = Enum('a', 'b', 'c') + view = View(Item('value')) + + action = SimpleEnumAction(name="Simple") + control = action.create_control(self.parent.control) + self.gui.process_events() + + editor = control._ui.get_editors('value')[0] + + with self.assertTraitChanges(action, 'value', count=1): + if toolkit.toolkit in {'qt', 'qt4'}: + editor.control.setCurrentIndex(1) + editor.control.activated.emit(1) + elif toolkit.toolkit == 'wx': + import wx + event = wx.CommandEvent(wx.EVT_CHOICE.typeId, + editor.control.GetId()) + event.SetString('b') + wx.PostEvent(editor.control.GetEventHandler(), event) + else: + self.skipTest("Unknown toolkit") + self.gui.process_events() + + self.assertEqual(action.value, 'b') + + def test_traitsui_widget_action_model(self): + from traitsui.api import View, Item + + class SimpleEnumAction(TraitsUIWidgetAction): + view = View(Item('value')) + + model = self.create_model() + action = SimpleEnumAction(name="Simple", model=model) + control = action.create_control(self.parent.control) + self.gui.process_events() + + editor = control._ui.get_editors('value')[0] + + with self.assertTraitChanges(model, 'value', count=1): + if toolkit.toolkit in {'qt', 'qt4'}: + editor.control.setCurrentIndex(1) + editor.control.activated.emit(1) + elif toolkit.toolkit == 'wx': + import wx + event = wx.CommandEvent(wx.EVT_CHOICE.typeId, + editor.control.GetId()) + event.SetString('b') + wx.PostEvent(editor.control.GetEventHandler(), event) + else: + self.skipTest("Unknown toolkit") + self.gui.process_events() + + self.assertEqual(model.value, 'b') + + def test_traitsui_widget_action_model_view(self): + from traitsui.api import HGroup, View, Item + + class ComplexEnumAction(TraitsUIWidgetAction): + value = Enum('a', 'b', 'c') + + view = View( + HGroup( + Item('value'), + Item('action.value'), + ) + ) + + model = self.create_model() + action = ComplexEnumAction(name="Simple", model=model) + control = action.create_control(self.parent.control) + self.gui.process_events() + + editor = control._ui.get_editors('value')[0] + + with self.assertTraitChanges(model, 'value', count=1): + if toolkit.toolkit in {'qt', 'qt4'}: + editor.control.setCurrentIndex(1) + editor.control.activated.emit(1) + elif toolkit.toolkit == 'wx': + import wx + event = wx.CommandEvent(wx.EVT_CHOICE.typeId, + editor.control.GetId()) + event.SetString('b') + wx.PostEvent(editor.control.GetEventHandler(), event) + else: + self.skipTest("Unknown toolkit") + self.gui.process_events() + + self.assertEqual(model.value, 'b') + + editor = control._ui.get_editors('value')[1] + + with self.assertTraitChanges(action, 'value', count=1): + if toolkit.toolkit in {'qt', 'qt4'}: + editor.control.setCurrentIndex(2) + editor.control.activated.emit(2) + elif toolkit.toolkit == 'wx': + event = wx.CommandEvent(wx.EVT_CHOICE.typeId, + editor.control.GetId()) + event.SetString('c') + wx.PostEvent(editor.control.GetEventHandler(), event) + else: + self.skipTest("Unknown toolkit") + self.gui.process_events() + + self.assertEqual(action.value, 'c') diff -Nru python-pyface-4.5.2/pyface/action/traitsui_widget_action.py python-pyface-6.1.2/pyface/action/traitsui_widget_action.py --- python-pyface-4.5.2/pyface/action/traitsui_widget_action.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/traitsui_widget_action.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,71 @@ +# Copyright (c) 2019, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + +from traits.api import Constant, HasTraits, Instance + +from .action import Action + + +class TraitsUIWidgetAction(Action): + """ A widget action containing a TraitsUI. + + If a object is supplied, then the UI is generated from the object's view, + otherwise the ui is generated on using the Action object. + + Notes + ----- + This is currently only supported by the Qt backend. + """ + + # TraitsUIWidgetAction traits ------------------------------------------- + + #: The underlying traits model to be displayed, or None. + model = Instance(HasTraits) + + # Action traits --------------------------------------------------------- + + #: This is a widget action. + style = Constant("widget") + + # ------------------------------------------------------------------------ + # Action interface + # ------------------------------------------------------------------------ + + def create_control(self, parent): + """ Called when creating a "widget" style action. + + This constructs an TraitsUI subpanel-based control. It does no binding + to the `perform` method. + + Parameters + ---------- + parent : toolkit control + The toolkit control, usually a toolbar. + + Returns + ------- + control : toolkit control + A toolkit control or None. + """ + ui = self.edit_traits(kind='subpanel', parent=parent) + control = ui.control + control._ui = ui + return control + + # ------------------------------------------------------------------------ + # HasTraits interface + # ------------------------------------------------------------------------ + + def trait_context(self): + """ Use the model object for the Traits UI context, if appropriate. + """ + if self.model is not None: + context = {'object': self.model, 'action': self} + return context + return super(TraitsUIWidgetAction, self).trait_context() diff -Nru python-pyface-4.5.2/pyface/action/window_action.py python-pyface-6.1.2/pyface/action/window_action.py --- python-pyface-4.5.2/pyface/action/window_action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/action/window_action.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2005-2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -10,24 +9,43 @@ # # Author: Enthought, Inc. # Description: -#------------------------------------------------------------------------------ """ Abstract base class for all window actions. """ - # Enthought library imports. from pyface.window import Window -from traits.api import Instance +from traits.api import Instance, Property # Local imports. -from action import Action +from pyface.action.listening_action import ListeningAction + + +class WindowAction(ListeningAction): + """ Abstract base class for window actions. """ + # 'ListeningAction' interface -------------------------------------------- -class WindowAction(Action): - """ Abstract base class for all window actions. """ + object = Property(depends_on='window') - #### 'WindowAction' interface ############################################# + # 'WindowAction' interface ----------------------------------------------- - # The window that the action is in. + #: The window that the action is associated with. window = Instance(Window) -#### EOF ###################################################################### + # ------------------------------------------------------------------------ + # Protected interface. + # ------------------------------------------------------------------------ + + def _get_object(self): + return self.window + + def destroy(self): + # Disconnect listeners to window and dependent properties. + self.window = None + super(WindowAction, self).destroy() + + +class CloseWindowAction(WindowAction): + """ Close the specified window """ + name = u'Close' + accelerator = 'Ctrl+W' + method = 'close' \ No newline at end of file diff -Nru python-pyface-4.5.2/pyface/api.py python-pyface-6.1.2/pyface/api.py --- python-pyface-4.5.2/pyface/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/api.py 2019-05-03 08:18:49.000000000 +0000 @@ -12,53 +12,60 @@ # Description: #------------------------------------------------------------------------------ +from __future__ import absolute_import -from about_dialog import AboutDialog -from application_window import ApplicationWindow -from beep import beep -from clipboard import clipboard, Clipboard -from confirmation_dialog import confirm, ConfirmationDialog -from constant import OK, CANCEL, YES, NO -from dialog import Dialog -from directory_dialog import DirectoryDialog -from file_dialog import FileDialog -from filter import Filter -from gui import GUI -from heading_text import HeadingText -from image_cache import ImageCache -from image_resource import ImageResource -from key_pressed_event import KeyPressedEvent -from message_dialog import error, information, warning, MessageDialog -from progress_dialog import ProgressDialog -from python_editor import PythonEditor -from python_shell import PythonShell -from sorter import Sorter -from splash_screen import SplashScreen -from split_application_window import SplitApplicationWindow -from split_dialog import SplitDialog -from split_panel import SplitPanel -from system_metrics import SystemMetrics -from window import Window -from widget import Widget - - -############################################################################### -# This part of the module handles widgets that are still wx specific. This -# will all be removed when everything has been ported to PyQt and pyface -# becomes toolkit agnostic. -############################################################################### +from .about_dialog import AboutDialog +from .application import Application +from .application_window import ApplicationWindow +from .beep import beep +from .clipboard import clipboard, Clipboard +from .confirmation_dialog import confirm, ConfirmationDialog +from .constant import OK, CANCEL, YES, NO +from .dialog import Dialog +from .directory_dialog import DirectoryDialog +from .file_dialog import FileDialog +from .filter import Filter +from .gui import GUI +from .gui_application import GUIApplication +from .heading_text import HeadingText +from .image_cache import ImageCache +from .image_resource import ImageResource +from .key_pressed_event import KeyPressedEvent +from .message_dialog import error, information, warning, MessageDialog +from .progress_dialog import ProgressDialog +from .python_editor import PythonEditor +from .python_shell import PythonShell +from .sorter import Sorter +from .single_choice_dialog import choose_one, SingleChoiceDialog +from .splash_screen import SplashScreen +from .split_application_window import SplitApplicationWindow +from .split_dialog import SplitDialog +from .split_panel import SplitPanel +from .system_metrics import SystemMetrics +from .ui_traits import Alignment, Border, HasBorder, HasMargin, Image, Margin +from .window import Window +from .widget import Widget + +# ---------------------------------------------------------------------------- +# Legacy and Wx-specific imports. +# ---------------------------------------------------------------------------- + +# These widgets currently only have Wx implementations +# will return Unimplemented for Qt. + +from .expandable_panel import ExpandablePanel +from .image_widget import ImageWidget +from .layered_panel import LayeredPanel +from .mdi_application_window import MDIApplicationWindow +from .mdi_window_menu import MDIWindowMenu +from .multi_toolbar_window import MultiToolbarWindow +# This code isn't toolkit widget code, but is wx-specific from traits.etsconfig.api import ETSConfig if ETSConfig.toolkit == 'wx': - from expandable_panel import ExpandablePanel - from image_widget import ImageWidget - from layered_panel import LayeredPanel - from mdi_application_window import MDIApplicationWindow - from mdi_window_menu import MDIWindowMenu - from multi_toolbar_window import MultiToolbarWindow - from single_choice_dialog import SingleChoiceDialog # Fix for broken Pycrust introspect module. - import util.fix_introspect_bug + # XXX move this somewhere better? - CJW 2017 + from .util import fix_introspect_bug del ETSConfig diff -Nru python-pyface-4.5.2/pyface/application.py python-pyface-6.1.2/pyface/application.py --- python-pyface-4.5.2/pyface/application.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/application.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,314 @@ +# Copyright (c) 2014-2018 by Enthought, Inc., Austin, TX +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +""" +This module defines the :py:class:`Application` class for Pyface, Tasks +and similar applications. Although the primary use cases are for GUI +applications, the :py:class:`Application` class does not have any explicit +dependency on GUI code, and can be used for CLI or server applications. + +Usual usage is to subclass :py:class:`Application`, overriding at least the +:py:method:`Application._run` method, but usually the +:py:method:`Application.start` and :py:method:`Application.stop` +methods as well. + +However the class can be used as-is by listening to the +:py:attr:`Application.application_initialized` event and performing +appropriate work there:: + + def do_work(): + print("Hello world") + + app = Application() + app.on_trait_change(do_work, 'application_initialized') + +""" + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) +import logging +import os + +from traits.api import ( + Directory, Event, HasStrictTraits, Instance, ReadOnly, Unicode, Vetoable, + VetoableEvent +) + +logger = logging.getLogger(__name__) + + +class ApplicationException(Exception): + """ Exception subclass for Application-centric exceptions """ + pass + + +class ApplicationExit(ApplicationException): + """ Exception which indicates application should try to exit. + + If no arguments, then assumed to be a normal exit, otherwise the arguments + give information about the problem. + """ + pass + + +class ApplicationEvent(HasStrictTraits): + """ An event associated with an application """ + + #: The application that the event happened to. + application = ReadOnly + + #: The type of application event. + event_type = ReadOnly + + +class Application(HasStrictTraits): + """ A base class for applications. + + This class handles the basic lifecycle of an application and a few + fundamental facilities. It is suitable as a base for any application, + not just GUI applications. + """ + + # 'Application' traits ---------------------------------------------------- + + # Branding ---------------------------------------------------------------- + + #: Human-readable application name + name = Unicode('Pyface Application') + + #: Human-readable company name + company = Unicode + + #: Human-readable description of the application + description = Unicode + + # Infrastructure --------------------------------------------------------- + + #: The application's globally unique identifier. + id = Unicode + + #: Application home directory (for preferences, logging, etc.) + home = Directory + + #: User data directory (for user files, projects, etc) + user_data = Directory + + # Application lifecycle -------------------------------------------------- + + #: Fired when the application is starting. Called immediately before the + #: start method is run. + starting = Event(Instance(ApplicationEvent)) + + #: Upon successful completion of the start method. + started = Event(Instance(ApplicationEvent)) + + #: Fired after the GUI event loop has been started during the run method. + application_initialized = Event(Instance(ApplicationEvent)) + + #: Fired when the application is starting. Called immediately before the + #: stop method is run. + exiting = VetoableEvent + + #: Fired when the application is starting. Called immediately before the + #: stop method is run. + stopping = Event(Instance(ApplicationEvent)) + + #: Upon successful completion of the stop method. + stopped = Event(Instance(ApplicationEvent)) + + # ------------------------------------------------------------------------- + # Application interface + # ------------------------------------------------------------------------- + + # Application lifecycle methods ------------------------------------------ + + def start(self): + """ Start the application, setting up things that are required + + Subclasses should call the superclass start() method before doing any + work themselves. + """ + return True + + def stop(self): + """ Stop the application, cleanly releasing resources if possible. + + Subclasses should call the superclass stop() method after doing any + work themselves. + """ + return True + + def run(self): + """ Run the application. + + Return + ------ + status : bool + Whether or not the application ran normally + """ + run = stopped = False + + # Start up the application. + logger.info('---- Application starting ----') + self._fire_application_event('starting') + started = self.start() + if started: + + logger.info('---- Application started ----') + self._fire_application_event('started') + + try: + run = self._run() + except ApplicationExit as exc: + if exc.args == (): + logger.info("---- ApplicationExit raised ----") + else: + logger.exception("---- ApplicationExit raised ----") + run = (exc.args == ()) + finally: + # Try to shut the application down. + logger.info('---- Application stopping ----') + self._fire_application_event('stopping') + stopped = self.stop() + if stopped: + self._fire_application_event('stopped') + logger.info('---- Application stopped ----') + + return started and run and stopped + + def exit(self, force=False): + """ Exits the application. + + This method handles a request to shut down the application by the user, + eg. from a menu. If force is False, the application can potentially + veto the close event, leaving the application in the state that it was + before the exit method was called. + + Parameters + ---------- + force : bool, optional (default False) + If set, windows will receive no closing events and will be + destroyed unconditionally. This can be useful for reliably tearing + down regression tests, but should be used with caution. + + Raises + ------ + ApplicationExit + Some subclasses may trigger the exit by raising ApplicationExit. + """ + logger.info('---- Application exit started ----') + if force or self._can_exit(): + try: + self._prepare_exit() + except Exception: + logger.exception("Error preparing for application exit") + finally: + logger.info('---- Application exit ----') + self._exit() + else: + logger.info('---- Application exit vetoed ----') + + # Initialization utilities ----------------------------------------------- + + def initialize_application_home(self): + """ Set up the home directory for the application + + This is where logs, preference files and other config files will be + stored. + """ + if not os.path.exists(self.home): + logger.info('Application home directory does not exist, creating') + os.makedirs(self.home) + + # ------------------------------------------------------------------------- + # Private interface + # ------------------------------------------------------------------------- + + # Main method ------------------------------------------------------------- + + def _run(self): + """ Actual implementation of running the application + + This should be completely overriden by applications which want to + actually do something. Usually this method starts an event loop and + blocks, but for command-line applications this could be where the + main application logic is called from. + """ + # Fire a notification that the app is running. If the app has an + # event loop (eg. a GUI, Tornado web app, etc.) then this should be + # fired _after_ the event loop starts using an appropriate callback + # (eg. gui.set_trait_later). + self._fire_application_event('application_initialized') + return True + + # Utilities --------------------------------------------------------------- + + def _fire_application_event(self, event_type): + event = ApplicationEvent(application=self, event_type=event_type) + setattr(self, event_type, event) + + # Destruction methods ----------------------------------------------------- + + def _can_exit(self): + """ Is exit vetoed by anything? + + The default behaviour is to fire the :py:attr:`exiting` event and check + to see if any listeners veto. Subclasses may wish to override to + perform additional checks. + + Returns + ------- + can_exit : bool + Return True if exit is OK, False if something vetoes the exit. + """ + self.exiting = event = Vetoable() + return not event.veto + + def _prepare_exit(self): + """ Do any application-level state saving and clean-up + + Subclasses should override this method. + """ + pass + + def _exit(self): + """ Shut down the application + + This is where application event loops and similar should be shut down. + """ + # invoke a normal exit from the application + raise ApplicationExit() + + # Traits defaults --------------------------------------------------------- + + def _id_default(self): + """ Use the application's directory as the id """ + from traits.etsconfig.etsconfig import ETSConfig + return ETSConfig._get_application_dirname() + + def _home_default(self): + """ Default home comes from ETSConfig. """ + from traits.etsconfig.etsconfig import ETSConfig + return os.path.join(ETSConfig.application_data, self.id) + + def _user_data_default(self): + """ Default user_data comes from ETSConfig. """ + from traits.etsconfig.etsconfig import ETSConfig + return ETSConfig.user_data + + def _company_default(self): + """ Default company comes from ETSConfig. """ + from traits.etsconfig.etsconfig import ETSConfig + return ETSConfig.company + + def _description_default(self): + """ Default description is the docstring of the application class. """ + from inspect import getdoc + text = getdoc(self) + return text diff -Nru python-pyface-4.5.2/pyface/application_window.py python-pyface-6.1.2/pyface/application_window.py --- python-pyface-4.5.2/pyface/application_window.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/application_window.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,9 +13,10 @@ #------------------------------------------------------------------------------ """ The implementation of a top-level application window. """ +from __future__ import absolute_import # Import the toolkit specific version. -from toolkit import toolkit_object +from .toolkit import toolkit_object ApplicationWindow = toolkit_object('application_window:ApplicationWindow') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/base_toolkit.py python-pyface-6.1.2/pyface/base_toolkit.py --- python-pyface-4.5.2/pyface/base_toolkit.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/base_toolkit.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,283 @@ +""" Common toolkit loading utilities and classes + +This module provides common code for ETS packages that need to do GUI toolkit +discovery and loading. The common patterns that ETS has settled on are that +where different GUI toolkits require alternative implementations of features +the toolkit is expected to provide a callable object which takes a relative +module path and an object name, separated by a colon and return the toolkit's +implementation of that object (usually this is a class, but it could be +anything). The assumption is that this is implemented by objects in +sub-modules of the toolkit, but plugin authors are free to use whatever methods +they like. + +Which toolkit to use is specified via the :py:mod:`traits.etsconfig.etsconfig` +package, but if this is not explicitly set by an application at startup or via +environment variables, there needs to be a way of discovering and loading any +available working toolkit implementations. The default mechanism is via the +now-standard :py:mod:`pkg_resources` and :py:mod:`setuptools` "entry point" +system. + +This module provides three things: + +- a function :py:func:`import_toolkit` that attempts to find and load a toolkit + entry point for a specified toolkit name + +- a function :py:func:`find_toolkit` that attempts to find a toolkit entry + point that works + +- a class :py:class:`Toolkit` class that implements the standard logic for + finding toolkit objects. + +These are done in a library-agnostic way so that the same tools can be used +not just for different pyface backends, but also for TraitsUI and ETS +libraries where we need to switch between different GUI toolkit +implementations. + +Note that there is no requirement for new toolkit implementations to use this +:py:class:`Toolkit` implementation, but they should be compatible with it. + +Default toolkit loading logic +----------------------------- + +The :py_func:`find_toolkit` function uses the following logic when attempting +to load toolkits: + +- if ETSConfig.toolkit is set, try to load a plugin with a matching name. + If it succeeds, we are good, and if it fails then we error out. + +- after that, we try every 'pyface.toolkit' plugin we can find. If one + succeeds, we consider ourselves good, and set the ETSConfig.toolkit + appropriately. The order is configurable, and by default will try to load + the `qt4` toolkit first, `wx` next, then all others in arbitrary order, + and `null` last. + +- finally, if all else fails, we try to load the null toolkit. +""" + +import logging +import os +import pkg_resources +import sys + +from traits.api import HasTraits, List, ReadOnly, Str, TraitError +from traits.etsconfig.api import ETSConfig + + +try: + provisional_toolkit = ETSConfig.provisional_toolkit +except AttributeError: + from contextlib import contextmanager + + # for backward compatibility + @contextmanager + def provisional_toolkit(toolkit_name): + """ Perform an operation with toolkit provisionally set + + This sets the toolkit attribute of the ETSConfig object set to the + provided value. If the operation fails with an exception, the toolkit + is reset to nothing. + """ + if ETSConfig.toolkit: + raise AttributeError("ETSConfig toolkit is already set") + ETSConfig.toolkit = toolkit_name + try: + yield + except: + # reset the toolkit state + ETSConfig._toolkit = '' + raise + + +logger = logging.getLogger(__name__) + + +TOOLKIT_PRIORITIES = { + 'qt4': -2, + 'wx': -1, + 'null': float('inf') +} +default_priorities = lambda plugin: TOOLKIT_PRIORITIES.get(plugin.name, 0) + + +class Toolkit(HasTraits): + """ A basic toolkit implementation for use by specific toolkits. + + This implementation uses pathname mangling to find modules and objects in + those modules. If an object can't be found, the toolkit will return a + class that raises NotImplementedError when it is instantiated. + """ + + #: The name of the package (eg. pyface) + package = ReadOnly + + #: The name of the toolkit + toolkit = ReadOnly + + #: The packages to look in for implementations. + packages = List(Str) + + def __init__(self, package, toolkit, *packages, **traits): + super(Toolkit, self).__init__( + package=package, + toolkit=toolkit, + packages=list(packages), + **traits + ) + + def __call__(self, name): + """ Return the toolkit specific object with the given name. + + Parameters + ---------- + name : str + The name consists of the relative module path and the object name + separated by a colon. + """ + from importlib import import_module + + mname, oname = name.split(':') + if not mname.startswith('.'): + mname = '.' + mname + + for package in self.packages: + try: + module = import_module(mname, package) + except ImportError as exc: + # is the error while trying to import package mname or not? + if all(part not in exc.args[0] for part in mname.split('.') + if part): + # something else went wrong - let the exception be raised + raise + + # Ignore *ANY* errors unless a debug ENV variable is set. + if 'ETS_DEBUG' in os.environ: + # Attempt to only skip errors in importing the backend modules. + # The idea here is that this only happens when the last entry in + # the traceback's stack frame mentions the toolkit in question. + import traceback + frames = traceback.extract_tb(sys.exc_traceback) + filename, lineno, function, text = frames[-1] + if not package in filename: + raise + else: + obj = getattr(module, oname, None) + if obj is not None: + return obj + + toolkit = self.toolkit + + class Unimplemented(object): + """ An unimplemented toolkit object + + This is returned if an object isn't implemented by the selected + toolkit. It raises an exception if it is ever instantiated. + """ + + def __init__(self, *args, **kwargs): + msg = "the %s %s backend doesn't implement %s" + raise NotImplementedError(msg % (toolkit, package, name)) + + return Unimplemented + + +def import_toolkit(toolkit_name, entry_point='pyface.toolkits'): + """ Attempt to import an toolkit specified by an entry point. + + Parameters + ---------- + toolkit_name : str + The name of the toolkit we would like to load. + entry_point : str + The name of the entry point that holds our toolkits. + + Returns + ------- + toolkit_object : callable + A callable object that implements the Toolkit interface. + + Raises + ------ + RuntimeError + If no toolkit is found, or if the toolkit cannot be loaded for some + reason. + """ + plugins = list(pkg_resources.iter_entry_points(entry_point, toolkit_name)) + if len(plugins) == 0: + msg = 'No {} plugin found for toolkit {}' + msg = msg.format(entry_point, toolkit_name) + logger.debug(msg) + raise RuntimeError(msg) + elif len(plugins) > 1: + msg = ("multiple %r plugins found for toolkit %r: %s") + modules = ', '.join(plugin.module_name for plugin in plugins) + logger.warning(msg, entry_point, toolkit_name, modules) + + for plugin in plugins: + try: + toolkit_object = plugin.load() + return toolkit_object + except (ImportError, AttributeError) as exc: + msg = "Could not load plugin %r from %r" + logger.info(msg, plugin.name, plugin.module_name) + logger.debug(exc, exc_info=True) + + msg = 'No {} plugin could be loaded for {}' + msg = msg.format(entry_point, toolkit_name) + logger.info(msg) + raise RuntimeError(msg) + + +def find_toolkit(entry_point, toolkits=None, priorities=default_priorities): + """ Find a toolkit that works. + + If ETSConfig is set, then attempt to find a matching toolkit. Otherwise + try every plugin for the entry_point until one works. The ordering of the + plugins is supplied via the priorities function which should be suitable + for use as a sorting key function. If all else fails, explicitly try to + load the "null" toolkit backend. If that fails, give up. + + Parameters + ---------- + entry_point : str + The name of the entry point that holds our toolkits. + toolkits : collection of strings + Only consider toolkits which match the given strings, ignore other + ones. + priorities : callable + A callable function that returns an priority for each plugin. + + Returns + ------- + toolkit : Toolkit instance + A callable object that implements the Toolkit interface. + + Raises + ------ + TraitError + If no working toolkit is found. + RuntimeError + If no ETSConfig.toolkit is set but the toolkit cannot be loaded for + some reason. + """ + if ETSConfig.toolkit: + return import_toolkit(ETSConfig.toolkit, entry_point) + + entry_points = [ + plugin for plugin in pkg_resources.iter_entry_points(entry_point) + if toolkits is None or plugin.name in toolkits + ] + for plugin in sorted(entry_points, key=priorities): + try: + with ETSConfig.provisional_toolkit(plugin.name): + toolkit = plugin.load() + return toolkit + except (ImportError, AttributeError, RuntimeError) as exc: + msg = "Could not load %s plugin %r from %r" + logger.info(msg, entry_point, plugin.name, plugin.module_name) + logger.debug(exc, exc_info=True) + + # if all else fails, try to import the null toolkit. + with ETSConfig.provisional_toolkit('null'): + return import_toolkit('null', entry_point) + + raise TraitError("Could not import any {} toolkit.".format(entry_point)) diff -Nru python-pyface-4.5.2/pyface/beep.py python-pyface-6.1.2/pyface/beep.py --- python-pyface-4.5.2/pyface/beep.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/beep.py 2019-05-03 08:18:49.000000000 +0000 @@ -3,5 +3,7 @@ """Sound the system bell.""" # Import the toolkit-specific version -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object beep = toolkit_object('beep:beep') diff -Nru python-pyface-4.5.2/pyface/clipboard.py python-pyface-6.1.2/pyface/clipboard.py --- python-pyface-4.5.2/pyface/clipboard.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/clipboard.py 2019-05-03 08:18:49.000000000 +0000 @@ -16,7 +16,9 @@ """ # Import the toolkit specific version -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object Clipboard = toolkit_object('clipboard:Clipboard') # Create a singleton clipboard object for convenience diff -Nru python-pyface-4.5.2/pyface/confirmation_dialog.py python-pyface-6.1.2/pyface/confirmation_dialog.py --- python-pyface-4.5.2/pyface/confirmation_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/confirmation_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,14 +13,28 @@ #------------------------------------------------------------------------------ """ The implementation of a dialog that prompts the user for confirmation. """ +from __future__ import absolute_import # Local imports. -from constant import NO +from .constant import NO def confirm(parent, message, title=None, cancel=False, default=NO): - """ Convenience function to show a confirmation dialog. """ + """ Convenience method to show a confirmation dialog. + Parameters + ---------- + parent : toolkit widget or None + The parent control for the dialog. + message : str + The text of the message to display. + title : str + The text of the dialog title. + cancel : bool + ``True`` if the dialog should contain a Cancel button. + default : NO, YES or CANCEL + Which button should be the default button. + """ if title is None: title = "Confirmation" @@ -36,7 +50,7 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from .toolkit import toolkit_object ConfirmationDialog = toolkit_object('confirmation_dialog:ConfirmationDialog') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/dialog.py python-pyface-6.1.2/pyface/dialog.py --- python-pyface-4.5.2/pyface/dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,7 +15,9 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object Dialog = toolkit_object('dialog:Dialog') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/directory_dialog.py python-pyface-6.1.2/pyface/directory_dialog.py --- python-pyface-4.5.2/pyface/directory_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/directory_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -17,7 +17,9 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object DirectoryDialog = toolkit_object('directory_dialog:DirectoryDialog') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/dock/api.py python-pyface-6.1.2/pyface/dock/api.py --- python-pyface-4.5.2/pyface/dock/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/dock/api.py 2019-06-14 11:44:07.000000000 +0000 @@ -28,26 +28,18 @@ # Imports: #------------------------------------------------------------------------------- -from dock_window \ - import DockWindow, DockWindowHandler +from .dock_window import DockWindow, DockWindowHandler -from dock_sizer \ - import DockSizer, DockSection, DockRegion, DockControl, DockStyle, \ - DOCK_LEFT, DOCK_RIGHT, DOCK_TOP, DOCK_BOTTOM, SetStructureHandler, \ - add_feature, DockGroup +from .dock_sizer import DockSizer, DockSection, DockRegion, DockControl, \ + DockStyle, DOCK_LEFT, DOCK_RIGHT, DOCK_TOP, DOCK_BOTTOM, \ + SetStructureHandler, add_feature, DockGroup -from idockable \ - import IDockable +from .idockable import IDockable -from idock_ui_provider \ - import IDockUIProvider +from .idock_ui_provider import IDockUIProvider -from ifeature_tool \ - import IFeatureTool +from .ifeature_tool import IFeatureTool -from dock_window_shell \ - import DockWindowShell - -from dock_window_feature \ - import DockWindowFeature +from .dock_window_shell import DockWindowShell +from .dock_window_feature import DockWindowFeature diff -Nru python-pyface-4.5.2/pyface/dock/dock_sizer.py python-pyface-6.1.2/pyface/dock/dock_sizer.py --- python-pyface-4.5.2/pyface/dock/dock_sizer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/dock/dock_sizer.py 2019-06-14 11:44:07.000000000 +0000 @@ -26,35 +26,22 @@ # Imports: #------------------------------------------------------------------------------- +from __future__ import print_function import wx, sys -from traits.api \ - import HasPrivateTraits, Instance, Str, Int, List, Enum, Tuple, Any, \ - Range, Property, Callable, Constant, Event, Undefined, Bool, \ - cached_property - -from traitsui.dock_window_theme \ - import dock_window_theme - -from traitsui.wx.helper \ - import BufferDC +from traits.api import HasPrivateTraits, Instance, Str, Int, List, Enum, \ + Tuple, Any, Range, Property, Callable, Constant, Event, Undefined, Bool, \ + cached_property +from traitsui.dock_window_theme import dock_window_theme +from traitsui.wx.helper import BufferDC from pyface.api import SystemMetrics +from pyface.image_resource import ImageResource +from pyface.wx.drag_and_drop import PythonDropSource +from pyface.timer.api import do_later, do_after +from .idockable import IDockable +from .ifeature_tool import IFeatureTool -from pyface.image_resource \ - import ImageResource - -from pyface.wx.drag_and_drop \ - import PythonDropSource - -from pyface.timer.api \ - import do_later, do_after - -from idockable \ - import IDockable - -from ifeature_tool \ - import IFeatureTool # Define version dependent values: wx_26 = (wx.__version__[:3] == '2.6') @@ -193,7 +180,7 @@ global standard_font if standard_font is None: - standard_font = wx.SystemSettings_GetFont( wx.SYS_DEFAULT_GUI_FONT ) + standard_font = wx.SystemSettings.GetFont( wx.SYS_DEFAULT_GUI_FONT ) dc.SetFont( standard_font ) @@ -846,13 +833,13 @@ bdc.DrawRectangle(0, 0, dx, dy) # Draw the left, top, and right side of a rectange around the tab - pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) + pen = wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNSHADOW)) bdc.SetPen(pen) bdc.DrawLine(0,dy,0,0) #up bdc.DrawLine(0,0,dx,0) #right bdc.DrawLine(dx-1,0,dx-1,dy) #down - pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNHIGHLIGHT)) + pen = wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNHIGHLIGHT)) bdc.SetPen(pen) bdc.DrawLine(1,dy,1,1) bdc.DrawLine(1,1,dx-2,1) @@ -866,7 +853,7 @@ bdc.DrawRectangle(0, 3, dx, dy) # Draw the left, top, and right side of a rectange around the tab - pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) + pen = wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNSHADOW)) bdc.SetPen(pen) bdc.DrawLine(0,dy,0,3) bdc.DrawLine(0,3,dx-1,3) @@ -930,7 +917,7 @@ self.fill_bg_color( dc, x, y, dx, dy ) - pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNHILIGHT)) + pen = wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNHILIGHT)) dc.SetPen(pen) dc.DrawLine(x, y, x+dx, y) dc.DrawLine(x, y+2, x+dx, y+2) @@ -947,7 +934,7 @@ self.fill_bg_color( dc, x, y, dx, dy ) - pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNHILIGHT)) + pen = wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNHILIGHT)) dc.SetPen(pen) dc.DrawLine(x, y, x, y+dy) dc.DrawLine(x+2, y, x+2, y+dy) @@ -1235,7 +1222,7 @@ if self.style == 'horizontal': # Draw a line the same color as the system button shadow, which # should be a darkish color in the users color scheme - pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) + pen = wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNSHADOW)) dc.SetPen(pen) dc.DrawLine(x+idx+1,y+dy/2,x+dx-2,y+dy/2) @@ -1248,7 +1235,7 @@ else: # Draw a line the same color as the system button shadow, which # should be a darkish color in the users color scheme - pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) + pen = wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNSHADOW)) dc.SetPen(pen) dc.DrawLine(x+dx/2,y+idy+1,x+dx/2,y+dy-2) @@ -1826,14 +1813,14 @@ def dump ( self, indent ): """ Prints the contents of the control. """ - print ('%sControl( %08X, name = %s, id = %s,\n%s' + print(('%sControl( %08X, name = %s, id = %s,\n%s' 'style = %s, locked = %s,\n%s' 'closeable = %s, resizable = %s, visible = %s\n%s' 'width = %d, height = %d )' % ( ' ' * indent, id( self ), self.name, self.id, ' ' * (indent + 9), self.style, self.locked, ' ' * (indent + 9), self.closeable, self.resizable, self.visible, - ' ' * (indent + 9), self.width, self.height )) + ' ' * (indent + 9), self.width, self.height ))) #--------------------------------------------------------------------------- # Draws the contents of the control: @@ -2466,7 +2453,7 @@ def get_structure ( self ): """ Returns a copy of the region 'structure', minus the actual content. """ - return self.clone_traits( [ 'active', 'width', 'height' ] ).set( + return self.clone_traits( [ 'active', 'width', 'height' ] ).trait_set( contents = [ item.get_structure() for item in self.contents ] ) #--------------------------------------------------------------------------- @@ -2805,8 +2792,8 @@ def dump ( self, indent ): """ Prints the contents of the region. """ - print '%sRegion( %08X, active = %s, width = %d, height = %d )' % ( - ' ' * indent, id( self ), self.active, self.width, self.height ) + print('%sRegion( %08X, active = %s, width = %d, height = %d )' % ( + ' ' * indent, id( self ), self.active, self.width, self.height )) for item in self.contents: item.dump( indent + 3 ) @@ -2838,8 +2825,8 @@ active = self.active contents = self.contents - for i in (range( active, len( contents ) ) + - range( active - 1, -1, -1 )): + for i in (list(range(active, len(contents))) + + list(range(active - 1, -1, -1))): if contents[ i ].visible: self.active = i return @@ -2943,12 +2930,12 @@ # Draws a box around the frame containing the tab contents, starting # below the tab - pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) + pen = wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNSHADOW)) dc.SetPen(pen) dc.DrawRectangle(x, y+tab_height, dx, dy-tab_height) # draw highlight - pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNHIGHLIGHT)) + pen = wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNHIGHLIGHT)) dc.SetPen(pen) dc.DrawLine(x+1, y+tab_height+1, x+dx-1, y+tab_height+1) @@ -3435,7 +3422,7 @@ new_contents = [ new_region, region ] else: new_contents = [ region, new_region ] - contents[ i ] = DockSection( is_row = False ).set( + contents[ i ] = DockSection( is_row = False ).trait_set( contents = new_contents ) else: if new_region.parent is self: @@ -3450,7 +3437,7 @@ new_contents = [ new_region, region ] else: new_contents = [ region, new_region ] - contents[ i ] = DockSection( is_row = True ).set( + contents[ i ] = DockSection( is_row = True ).trait_set( contents = new_contents ) else: if new_region.parent is self: @@ -3497,7 +3484,7 @@ def get_structure ( self ): """ Returns a copy of the section 'structure', minus the actual content. """ - return self.clone_traits( [ 'is_row', 'width', 'height' ] ).set( + return self.clone_traits( [ 'is_row', 'width', 'height' ] ).trait_set( contents = [ item.get_structure() for item in self.contents ], splitters = [ item.get_structure() for item in self.splitters ] ) @@ -3565,8 +3552,8 @@ def dump ( self, indent = 0 ): """ Prints the contents of the section. """ - print '%sSection( %08X, is_row = %s, width = %d, height = %d )' % ( - ' ' * indent, id( self ), self.is_row, self.width, self.height ) + print('%sSection( %08X, is_row = %s, width = %d, height = %d )' % ( + ' ' * indent, id( self ), self.is_row, self.width, self.height )) for item in self.contents: item.dump( indent + 3 ) @@ -3738,8 +3725,8 @@ ((kind == DOCK_LEFT) or (kind == DOCK_RIGHT)))): if len( section.contents ) > 0: sizer._contents = section = DockSection( - is_row = not section.is_row ).set( - contents = [ section ] ) + is_row = not section.is_row ).trait_set( + contents = [ section ] ) if len( section.contents ) > 0: i = 0 if (kind == DOCK_RIGHT) or (kind == DOCK_BOTTOM): @@ -3896,7 +3883,7 @@ items.append( DockRegion( contents = [ item ] ) ) else: raise TypeError - return DockSection( is_row = is_row ).set( contents = items ) + return DockSection( is_row = is_row ).trait_set( contents = items ) #--------------------------------------------------------------------------- # Returns a copy of the layout 'structure', minus the actual content @@ -3954,7 +3941,7 @@ for control in section.get_controls( False ): mapped_control = map.get( control.id ) if mapped_control is not None: - control.set( **mapped_control.get( 'visible', 'locked', + control.trait_set( **mapped_control.get( 'visible', 'locked', 'closeable', 'resizable', 'width', 'height' ) ) if mapped_control.user_name: control.name = mapped_control.name @@ -4089,4 +4076,3 @@ parent = control.GetParent() return control - diff -Nru python-pyface-4.5.2/pyface/dock/dock_window_feature.py python-pyface-6.1.2/pyface/dock/dock_window_feature.py --- python-pyface-4.5.2/pyface/dock/dock_window_feature.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/dock/dock_window_feature.py 2019-07-20 11:46:59.000000000 +0000 @@ -31,29 +31,16 @@ # Imports: #------------------------------------------------------------------------------- -from weakref \ - import ref +from weakref import ref -from traits.api \ - import HasPrivateTraits, Instance, Int, Str, Bool, Property +from traits.api import HasPrivateTraits, Instance, Int, Str, Bool, Property +from traitsui.menu import Menu, Action -from traitsui.menu \ - import Menu, Action - -from pyface.timer.api \ - import do_later - -from pyface.image_resource \ - import ImageResource - -from dock_window \ - import DockWindow - -from dock_sizer \ - import DockControl, add_feature - -from ifeature_tool \ - import IFeatureTool +from pyface.timer.api import do_later +from pyface.image_resource import ImageResource +from .dock_window import DockWindow +from .dock_sizer import DockControl, add_feature +from .ifeature_tool import IFeatureTool #------------------------------------------------------------------------------- # 'DockWindowFeature' class: @@ -540,6 +527,7 @@ # specified DockControl (or None if the feature does not apply to it): #--------------------------------------------------------------------------- + @classmethod def feature_for ( cls, dock_control ): """ Returns a single new feature object or list of new feature objects for a specified DockControl. @@ -577,12 +565,11 @@ return None - feature_for = classmethod( feature_for ) - #--------------------------------------------------------------------------- # Returns a new feature instance for a specified DockControl: #--------------------------------------------------------------------------- + @classmethod def new_feature ( cls, dock_control ): """ Returns a new feature instance for a specified DockControl. @@ -611,13 +598,12 @@ """ return cls( dock_control = dock_control ) - new_feature = classmethod( new_feature ) - #--------------------------------------------------------------------------- # Returns whether or not the DockWindowFeature is a valid feature for a # specified DockControl: #--------------------------------------------------------------------------- + @classmethod def is_feature_for ( self, dock_control ): """ Returns whether this class is a valid feature for the application object corresponding to a specified DockControl. @@ -643,8 +629,6 @@ """ return True - is_feature_for = classmethod( is_feature_for ) - #-- Private Methods ------------------------------------------------------------ #--------------------------------------------------------------------------- @@ -655,11 +639,11 @@ """ Sets the feature's 'event' traits for a specified mouse 'event'. """ x, y = event.GetEventObject().GetScreenPosition() - self.set( x = event.GetX() + x, - y = event.GetY() + y, - shift_down = event.ShiftDown(), - control_down = event.ControlDown(), - alt_down = event.AltDown() ) + self.trait_set( x = event.GetX() + x, + y = event.GetY() + y, + shift_down = event.ShiftDown(), + control_down = event.ControlDown(), + alt_down = event.AltDown() ) #--------------------------------------------------------------------------- # Displays the quick drag menu for a specified drag object: @@ -744,6 +728,7 @@ # if the feature does not apply to the DockControl object): #--------------------------------------------------------------------------- + @classmethod def new_feature_for ( cls, dock_control ): """ Returns a feature object for use with the specified DockControl (or **None** if the feature does not apply to the DockControl object). @@ -759,12 +744,11 @@ return result - new_feature_for = classmethod( new_feature_for ) - #--------------------------------------------------------------------------- # Toggles the feature on/off: #--------------------------------------------------------------------------- + @classmethod def toggle_feature ( cls, event ): """ Toggles the feature on or off. """ @@ -787,8 +771,6 @@ if feature is not None: getattr( feature, method )() - toggle_feature = classmethod( toggle_feature ) - #-- Event Handlers ------------------------------------------------------------- #--------------------------------------------------------------------------- @@ -858,4 +840,3 @@ eval( action, globals(), { 'self': self } ) else: getattr( self, action )() - diff -Nru python-pyface-4.5.2/pyface/dock/dock_window.py python-pyface-6.1.2/pyface/dock/dock_window.py --- python-pyface-4.5.2/pyface/dock/dock_window.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/dock/dock_window.py 2019-06-14 11:44:07.000000000 +0000 @@ -62,15 +62,10 @@ from pyface.message_dialog \ import error as warning -from dock_sizer \ - import DockSizer, DockControl, DockRegion, DockStyle, DockSplitter, \ - no_dock_info, clear_window, features - -from idockable \ - import IDockable - -from idock_ui_provider \ - import IDockUIProvider +from .dock_sizer import DockSizer, DockControl, DockRegion, DockStyle, \ + DockSplitter, no_dock_info, clear_window, features +from .idockable import IDockable +from .idock_ui_provider import IDockUIProvider is_mac = (sys.platform == 'darwin') @@ -165,8 +160,9 @@ # If DockControl was closed, then reset it to point to the new # control: if close: - dock_control.set( control = control, - style = parent.owner.style ) + dock_control.trait_set( + control = control, + style = parent.owner.style) dockable.dockable_init_dockcontrol( dock_control ) return dock_control @@ -833,8 +829,8 @@ name = control_info.name.strip() if name != '': object.name = name - object.set( **control_info.get( 'user_name', - 'style', 'user_style' ) ) + object.trait_set(**control_info.get('user_name', 'style', + 'user_style')) self.update_layout() #--------------------------------------------------------------------------- @@ -897,7 +893,7 @@ """ layouts = self._get_layouts() if layouts is not None: - return layouts.keys() + return list(layouts.keys()) return [] diff -Nru python-pyface-4.5.2/pyface/dock/dock_window_shell.py python-pyface-6.1.2/pyface/dock/dock_window_shell.py --- python-pyface-4.5.2/pyface/dock/dock_window_shell.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/dock/dock_window_shell.py 2019-06-14 11:44:07.000000000 +0000 @@ -27,23 +27,14 @@ # Fixme: Hack to force 'image_slice' to be added via Category to Theme class: import traitsui.wx - -from traits.api \ - import HasPrivateTraits, Instance - -from traitsui.api \ - import View, Group +from traits.api import HasPrivateTraits, Instance +from traitsui.api import View, Group from pyface.api import SystemMetrics - -from pyface.image_resource \ - import ImageResource - -from dock_window \ - import DockWindow - -from dock_sizer \ - import DockSizer, DockSection, DockRegion, DockControl, DOCK_RIGHT +from pyface.image_resource import ImageResource +from .dock_window import DockWindow +from .dock_sizer import DockSizer, DockSection, DockRegion, DockControl, \ + DOCK_RIGHT #------------------------------------------------------------------------------- # Constants: @@ -89,9 +80,9 @@ wx.EVT_CLOSE( shell, self._on_close ) theme = dock_control.theme - self._dock_window = dw = DockWindow( shell, auto_close = True, - theme = theme ).set( - style = 'tab' ) + dw = DockWindow( shell, auto_close = True, theme = theme ) + dw.trait_set( style = 'tab' ) + self._dock_window = dw sizer = wx.BoxSizer( wx.VERTICAL ) sizer.Add( dw.control, 1, wx.EXPAND ) shell.SetSizer( sizer ) @@ -143,7 +134,7 @@ # If the DockControl was closed, then reset it to point to the new # control: if close: - dock_control.set( control = control, style = 'tab' ) + dock_control.trait_set( control = control, style = 'tab' ) else: # Create a DockControl to describe the new control: dock_control = DockControl( control = control, diff -Nru python-pyface-4.5.2/pyface/dock/feature_bar.py python-pyface-6.1.2/pyface/dock/feature_bar.py --- python-pyface-4.5.2/pyface/dock/feature_bar.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/dock/feature_bar.py 2019-06-14 11:44:07.000000000 +0000 @@ -27,17 +27,11 @@ import wx -from traits.api \ - import HasPrivateTraits, Instance, Bool, Event, Color +from traits.api import HasPrivateTraits, Instance, Bool, Event, Color -from pyface.wx.drag_and_drop \ - import PythonDropTarget, PythonDropSource - -from dock_sizer \ - import DockControl, FEATURE_EXTERNAL_DRAG - -from ifeature_tool \ - import IFeatureTool +from pyface.wx.drag_and_drop import PythonDropTarget, PythonDropSource +from .dock_sizer import DockControl, FEATURE_EXTERNAL_DRAG +from .ifeature_tool import IFeatureTool #------------------------------------------------------------------------------- # 'FeatureBar' class: @@ -350,7 +344,7 @@ else: # Handle a normal object being dropped: wx, wy = self.control.GetScreenPosition() - feature.set( x = wx + x, y = wy + y ) + feature.trait_set( x = wx + x, y = wy + y ) feature.drop( data ) return drag_result diff -Nru python-pyface-4.5.2/pyface/dock/feature_tool.py python-pyface-6.1.2/pyface/dock/feature_tool.py --- python-pyface-4.5.2/pyface/dock/feature_tool.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/dock/feature_tool.py 2019-06-14 11:44:07.000000000 +0000 @@ -24,11 +24,8 @@ # Imports: #------------------------------------------------------------------------------- -from dock_window_feature \ - import DockWindowFeature - -from pyface.image_resource \ - import ImageResource +from pyface.image_resource import ImageResource +from .dock_window_feature import DockWindowFeature #------------------------------------------------------------------------------- # 'FeatureTool' class: diff -Nru python-pyface-4.5.2/pyface/dock/idockable.py python-pyface-6.1.2/pyface/dock/idockable.py --- python-pyface-4.5.2/pyface/dock/idockable.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/dock/idockable.py 2019-05-03 08:18:49.000000000 +0000 @@ -59,7 +59,7 @@ def dockable_get_control ( self, parent ): """ Gets a control that can be docked into a DockWindow. """ - print "The 'IDockable.dockable_get_control' method must be overridden" + print("The 'IDockable.dockable_get_control' method must be overridden") panel = wx.Panel( parent, -1 ) panel.SetBackgroundColour( wx.RED ) return panel diff -Nru python-pyface-4.5.2/pyface/drop_handler.py python-pyface-6.1.2/pyface/drop_handler.py --- python-pyface-4.5.2/pyface/drop_handler.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/drop_handler.py 2019-05-03 08:18:49.000000000 +0000 @@ -7,11 +7,11 @@ """ ### BaseDropHandler interface ############################################# - # Returns True if the current drop handler can handle the given drag event - # occurring on the given target widget. + #: Returns True if the current drop handler can handle the given drag event + #: occurring on the given target widget. on_can_handle = Callable - # Performs drop action when drop event occurs on target widget. + #: Performs drop action when drop event occurs on target widget. on_handle = Callable ### IDropHandler interface ################################################ @@ -29,15 +29,16 @@ """ ### FileDropHandler interface ############################################# - # supported extensions + #: supported extensions extensions = List(Str) - # Called when file is opened. Takes single argument: path of file + #: Called when file is opened. Takes single argument: path of file open_file = Callable ### IDropHandler interface ################################################ def can_handle_drop(self, event, target): + """ Does the drop event contails file data with matching extensions """ if event.mimeData().hasUrls(): for url in event.mimeData().urls(): file_path = url.toLocalFile() @@ -46,5 +47,6 @@ return False def handle_drop(self, event, target): + """ Open the file using the supplied callback """ for url in event.mimeData().urls(): self.open_file(url.toLocalFile()) diff -Nru python-pyface-4.5.2/pyface/expandable_header.py python-pyface-6.1.2/pyface/expandable_header.py --- python-pyface-4.5.2/pyface/expandable_header.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/expandable_header.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,238 +6,12 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -""" A header for an entry in a collection of expandables. The header -provides a visual indicator of the current state, a text label, and a -'remove' button. """ -from __future__ import absolute_import - -# Major package imports. -import wx - -# Enthought library imports. -from traits.api import Instance, Event, Str, Bool - -# local imports -from .image_resource import ImageResource -from .widget import Widget -from .util.font_helper import new_font_like - - -class ExpandableHeader(Widget): - """ A header for an entry in a collection of expandables. The header - provides a visual indicator of the current state, a text label, and a - 'remove' button. """ - - # The title of the panel. - title = Str('Panel') - - # The carat image to show when the panel is collapsed. - collapsed_carat_image = Instance(ImageResource, ImageResource('carat_closed')) - # The carat image to show when the panel is expanded. - expanded_carat_image = Instance(ImageResource, ImageResource('carat_open')) - # The backing header image when the mouse is elsewhere - header_bar_image = Instance(ImageResource, - ImageResource('panel_gradient')) - # The backing header image when the mouse is over - header_mouseover_image = Instance(ImageResource, - ImageResource('panel_gradient_over')) - - # The carat image to show when the panel is expanded. - remove_image = Instance(ImageResource, ImageResource('close')) - - # Represents the current state of the button. True means pressed. - state = Bool(False) - - #### Events #### - - # The panel has been expanded or collapsed - panel_expanded = Event - - - _CARAT_X = 4 - _CARAT_Y = 2 - _TEXT_Y = 0 - _TEXT_X_OFFSET = 10 - - ########################################################################### - # 'object' interface. - ########################################################################### - - def __init__(self, parent, container, **traits): - """ Creates the panel. """ - - # Base class constructor. - super(ExpandableHeader, self).__init__(**traits) - - # Create the toolkit-specific control that represents the widget. - self.control = self._create_control(parent) - - self._container = container - return - - ########################################################################### - # Private interface. - ########################################################################### - - def _create_control(self, parent): - """ Create the toolkit-specific control that represents the widget. """ - - collapsed_carat = self.collapsed_carat_image.create_image() - self._collapsed_bmp = collapsed_carat.ConvertToBitmap() - self._carat_w = self._collapsed_bmp.GetWidth() - - expanded_carat = self.expanded_carat_image.create_image() - self._expanded_bmp = expanded_carat.ConvertToBitmap() - - header_bar = self.header_bar_image.create_image() - self._header_bmp = header_bar.ConvertToBitmap() - - header_bar_over = self.header_mouseover_image.create_image() - self._header_mouseover_bmp = header_bar_over.ConvertToBitmap() - - self._background_bmp = self._header_bmp - - close_image = self.remove_image.create_image() - self._remove_bmp = close_image.ConvertToBitmap() - - # create our panel and initialize it appropriately - sizer = wx.BoxSizer(wx.VERTICAL) - panel = wx.Panel(parent, -1, style=wx.CLIP_CHILDREN) - panel.SetSizer(sizer) - panel.SetAutoLayout(True) - - # needed on GTK systems for EVT_ERASE_BACKGROUND to work - panel.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) - - # create the remove button - remove = wx.BitmapButton(panel, -1, self._remove_bmp, style=0, - pos=(-1, 3)) - sizer.Add(remove, 0, wx.ALIGN_RIGHT, 5) - - # Create a suitable font. - self._font = new_font_like(wx.NORMAL_FONT, - point_size=wx.NORMAL_FONT.GetPointSize()- 1) - - height = self._get_preferred_height(parent, self.title, self._font) - panel.SetSize((-1, height)) - - wx.EVT_ERASE_BACKGROUND(panel, self._on_erase_background) - wx.EVT_ENTER_WINDOW(panel, self._on_enter_leave) - wx.EVT_LEAVE_WINDOW(panel, self._on_enter_leave) - wx.EVT_LEFT_DOWN(panel, self._on_down) - wx.EVT_RIGHT_DOWN(panel, self._on_down) - - wx.EVT_BUTTON(panel, remove.GetId(), self._on_remove) - - return panel - - def _get_preferred_height(self, parent, text, font): - """ Calculates the preferred height of the widget. """ - - dc = wx.MemoryDC() - - dc.SetFont(font) - text_w, text_h = dc.GetTextExtent(text) - text_h = text_h + self._TEXT_Y - - # add in width of buttons - carat_h = self._collapsed_bmp.GetHeight() + self._CARAT_Y - - return max(text_h, carat_h) - - def _draw_carat_button(self, dc): - """ Draws the button at the correct coordinates. """ - - if self.state: - bmp = self._expanded_bmp - else: - bmp = self._collapsed_bmp - - dc.DrawBitmap(bmp, self._CARAT_X, self._CARAT_Y, True) - - return - - def _tile_background_image(self, dc, width, height): - """ Tiles the background image. """ - - w = self._background_bmp.GetWidth() - h = self._background_bmp.GetHeight() - - x = 0 - while x < width: - y = 0 - while y < height: - dc.DrawBitmap(self._background_bmp, x, y) - - y = y + h - - x = x + w - - return - - def _draw_title(self, dc): - """ Draws the text label for the header. """ - dc.SetFont(self._font) - - # Render the text. - dc.DrawText(self.title, self._carat_w + self._TEXT_X_OFFSET, - self._TEXT_Y) - - def _draw(self, dc): - """ Draws the control. """ - - size = self.control.GetClientSize() - - # Tile the background image. - self._tile_background_image(dc, size.width, size.height) - - self._draw_title(dc) - - # Draw the carat button - self._draw_carat_button(dc) - - return - - ########################################################################### - # wx event handlers. - ########################################################################### - - def _on_erase_background(self, event): - """ Called when the background of the panel is erased. """ - - #print 'ImageButton._on_erase_background' - dc = event.GetDC() - self._draw(dc) - return - - def _on_enter_leave(self, event): - """ Called when button is pressed. """ - - #print 'ExpandableHeader._on_enter_leave' - if event.Entering(): - self._background_bmp = self._header_mouseover_bmp - else: - self._background_bmp = self._header_bmp - - self.control.Refresh() - event.Skip() - - def _on_down(self, event): - """ Called when button is pressed. """ - - #print 'ImageButton._on_down' - self.state = not self.state - self.control.Refresh() - # fire an event so any listeners can pick up the change - self.panel_expanded = self - event.Skip() +import logging - def _on_remove(self, event): - """ Called when remove button is pressed. """ +logger = logging.getLogger(__name__) +logger.warning( + 'DEPRECATED: pyface.expandable_header, use pyface.ui.wx.expandable_header instead. ' + 'Will be removed in Pyface 7.') - self._container.remove_panel(self.title) +from pyface.ui.wx.expandable_header import * diff -Nru python-pyface-4.5.2/pyface/expandable_panel.py python-pyface-6.1.2/pyface/expandable_panel.py --- python-pyface-4.5.2/pyface/expandable_panel.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/expandable_panel.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,154 +6,11 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -""" A Layered panel. """ -from __future__ import absolute_import - -# Major package imports. -import wx - -from traits.api import Instance - -# Local imports. -from .expandable_header import ExpandableHeader -from .image_resource import ImageResource -from .widget import Widget - - -class ExpandablePanel(Widget): - """ An expandable panel. """ - - # The default style. - STYLE = wx.CLIP_CHILDREN - - collapsed_image = Instance(ImageResource, ImageResource('mycarat1')) - expanded_image = Instance(ImageResource, ImageResource('mycarat2')) - - ########################################################################### - # 'object' interface. - ########################################################################### - - def __init__(self, parent, **traits): - """ Creates a new LayeredPanel. """ - - # Base class constructor. - super(ExpandablePanel, self).__init__(**traits) - - # Create the toolkit-specific control that represents the widget. - self.control = self._create_control(parent) - - # The layers in the panel. - # - # { str name : wx.Window layer } - self._layers = {} - self._headers = {} - - return - - ########################################################################### - # 'Expandale' interface. - ########################################################################### - - def add_panel(self, name, layer): - """ Adds a layer with the specified name. - - All layers are hidden when they are added. Use 'show_layer' to make a - layer visible. - - """ - - parent = self.control - sizer = self.control.GetSizer() - - # Add the heading text. - header = self._create_header(parent, text=name) - sizer.Add(header, 0, wx.EXPAND) - - # Add the layer to our sizer. - sizer.Add(layer, 1, wx.EXPAND) - # All layers are hidden when they are added. Use 'show_layer' to make - # a layer visible. - sizer.Show(layer, False) +# Note: The ExpandablePanel is currently wx-specific - # fixme: Should we warn if a layer is being overridden? - self._layers[name] = layer - - return layer - - def remove_panel(self, name): - """ Removes a layer and its header from the container.""" - - if not self._layers.has_key(name): - return - - sizer = self.control.GetSizer() - panel = self._layers[name] - header = self._headers[name] - sizer.Remove(panel) - panel.Destroy() - sizer.Remove(header) - header.Destroy() - - sizer.Layout() - - return - - ########################################################################### - # Private interface. - ########################################################################### - - def _create_control(self, parent): - """ Create the toolkit-specific control that represents the widget. """ - - panel = wx.Panel(parent, -1, style=self.STYLE) - sizer = wx.BoxSizer(wx.VERTICAL) - panel.SetSizer(sizer) - panel.SetAutoLayout(True) - - return panel - - def _create_header(self, parent, text): - """ Creates a panel header. """ - - sizer = wx.BoxSizer(wx.HORIZONTAL) - panel = wx.Panel(parent, -1, style=wx.CLIP_CHILDREN) - panel.SetSizer(sizer) - panel.SetAutoLayout(True) - - # Add the panel header. - heading = ExpandableHeader(panel, self, - title = text) - sizer.Add(heading.control, 1, wx.EXPAND) - - heading.on_trait_change(self._on_button, 'panel_expanded') - - # Resize the panel to match the sizer's minimum size. - sizer.Fit(panel) - - # hang onto it for when we destroy - self._headers[text] = panel - - return panel - - #### wx event handlers #################################################### - - def _on_button(self, event): - """ called when one of the expand/contract buttons is pressed. """ - - header = event - name = header.title - visible = header.state - - sizer = self.control.GetSizer() - sizer.Show(self._layers[name], visible) - sizer.Layout() +# Import the toolkit specific version. +from __future__ import absolute_import - # fixme: Errrr, maybe we can NOT do this! - w, h = self.control.GetSize() - self.control.SetSize((w+1, h+1)) - self.control.SetSize((w, h)) +from .toolkit import toolkit_object +ExpandablePanel = toolkit_object('expandable_panel:ExpandablePanel') diff -Nru python-pyface-4.5.2/pyface/fields/api.py python-pyface-6.1.2/pyface/fields/api.py --- python-pyface-4.5.2/pyface/fields/api.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/fields/api.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,20 @@ +# Copyright (c) 2019, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: + +from .i_combo_field import IComboField +from .i_field import IField +from .i_spin_field import ISpinField +from .i_text_field import ITextField + +from .combo_field import ComboField +from .spin_field import SpinField +from .text_field import TextField \ No newline at end of file diff -Nru python-pyface-4.5.2/pyface/fields/combo_field.py python-pyface-6.1.2/pyface/fields/combo_field.py --- python-pyface-4.5.2/pyface/fields/combo_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/fields/combo_field.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,18 @@ +# Copyright (c) 2019, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: + +""" The combo field widget. """ + +# Import the toolkit specific version. +from pyface.toolkit import toolkit_object + +ComboField = toolkit_object('fields.combo_field:ComboField') diff -Nru python-pyface-4.5.2/pyface/fields/i_combo_field.py python-pyface-6.1.2/pyface/fields/i_combo_field.py --- python-pyface-4.5.2/pyface/fields/i_combo_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/fields/i_combo_field.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,107 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2019, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" The text field interface. """ + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +from six import text_type + +from traits.api import Callable, HasTraits, Enum, List + +from pyface.fields.i_field import IField + + +class IComboField(IField): + """ The combo field interface. + + This is for comboboxes holding a list of values. + """ + + #: The current value of the combobox. + value = Enum(values='values') + + #: The list of available values for the combobox. + values = List + + #: Callable that converts a value to text plus an optional icon. + #: Should return either a uncode string or a tuple of image resource + #: and string. + formatter = Callable(text_type, allow_none=False) + + +class MComboField(HasTraits): + + #: The current text value of the combobox. + value = Enum(values='values') + + #: The list of available values for the combobox. + values = List(minlen=1) + + #: Callable that converts a value to text plus an optional icon. + #: Should return either a uncode string or a tuple of image resource + #: and string. + formatter = Callable(text_type, allow_none=False) + + # ------------------------------------------------------------------------ + # object interface + # ------------------------------------------------------------------------ + + def __init__(self, values, **traits): + value = traits.pop('value', values[0]) + traits['values'] = values + super(MComboField, self).__init__(**traits) + self.value = value + + # ------------------------------------------------------------------------ + # Private interface + # ------------------------------------------------------------------------ + + def _initialize_control(self): + super(MComboField, self)._initialize_control() + self._set_control_values(self.values) + self._set_control_value(self.value) + + def _add_event_listeners(self): + """ Set up toolkit-specific bindings for events """ + super(MComboField, self)._add_event_listeners() + self.on_trait_change(self._values_updated, 'values[],formatter', + dispatch='ui') + if self.control is not None: + self._observe_control_value() + + def _remove_event_listeners(self): + """ Remove toolkit-specific bindings for events """ + if self.control is not None: + self._observe_control_value(remove=True) + self.on_trait_change(self._values_updated, 'values[],formatter', + dispatch='ui', remove=True) + super(MComboField, self)._remove_event_listeners() + + # Toolkit control interface --------------------------------------------- + + def _get_control_text_values(self): + """ Toolkit specific method to get the control's text values. """ + raise NotImplementedError + + def _set_control_values(self, values): + """ Toolkit specific method to set the control's values. """ + raise NotImplementedError + + # Trait change handlers -------------------------------------------------- + + def _values_updated(self): + if self.control is not None: + self._set_control_values(self.values) diff -Nru python-pyface-4.5.2/pyface/fields/i_field.py python-pyface-6.1.2/pyface/fields/i_field.py --- python-pyface-4.5.2/pyface/fields/i_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/fields/i_field.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,175 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2017-19, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" The text field interface. """ + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +from traits.api import Any, HasTraits, Instance, Unicode + +from pyface.i_widget import IWidget + + +class IField(IWidget): + """ The field interface. + + A field is a widget that displays a value and (potentially) allows a user + to interact with it. + """ + + #: The value held by the field. + value = Any + + #: A tooltip for the field. + tooltip = Unicode + + #: An optional context menu for the field. + context_menu = Instance('pyface.action.menu_manager.MenuManager') + + def show_context_menu(self, x, y): + """ Create and show the context menu at a position. """ + + def _initialize_control(self, control): + """ Perform any toolkit-specific initialization for the control. """ + + +class MField(HasTraits): + """ The field mix-in. """ + + #: The value held by the field. + value = Any + + #: A tooltip for the field. + tooltip = Unicode + + #: An optional context menu for the field. + context_menu = Instance('pyface.action.menu_manager.MenuManager') + + # ------------------------------------------------------------------------ + # IWidget interface + # ------------------------------------------------------------------------ + + def _add_event_listeners(self): + """ Set up toolkit-specific bindings for events """ + super(MField, self)._add_event_listeners() + self.on_trait_change(self._value_updated, 'value', dispatch='ui') + self.on_trait_change(self._tooltip_updated, 'tooltip', dispatch='ui') + self.on_trait_change(self._context_menu_updated, 'context_menu', + dispatch='ui') + if self.control is not None and self.context_menu is not None: + self._observe_control_context_menu() + + def _remove_event_listeners(self): + """ Remove toolkit-specific bindings for events """ + if self.control is not None and self.context_menu is not None: + self._observe_control_context_menu(remove=True) + self.on_trait_change(self._value_updated, 'value', dispatch='ui', + remove=True) + self.on_trait_change(self._tooltip_updated, 'tooltip', dispatch='ui', + remove=True) + self.on_trait_change(self._context_menu_updated, 'context_menu', + dispatch='ui', remove=True) + super(MField, self)._remove_event_listeners() + + # ------------------------------------------------------------------------ + # Private interface + # ------------------------------------------------------------------------ + + def _create(self): + """ Creates the toolkit specific control. + + This method should create the control and assign it to the + :py:attr:``control`` trait. + """ + self.control = self._create_control(self.parent) + self._initialize_control() + self._add_event_listeners() + + self.show(self.visible) + self.enable(self.enabled) + + def _initialize_control(self): + """ Perform any toolkit-specific initialization for the control. """ + self._set_control_tooltip(self.tooltip) + + def _update_value(self, value): + """ Handle a change to the value from user interaction + + This is a method suitable for calling from a toolkit event handler. + """ + self.value = self._get_control_value() + + def _get_control(self): + """ If control is not passed directly, get it from the trait. """ + control = self.control + if control is None: + raise RuntimeError("Toolkit control does not exist.") + return control + + # Toolkit control interface --------------------------------------------- + + def _get_control_value(self): + """ Toolkit specific method to get the control's value. """ + raise NotImplementedError + + def _set_control_value(self, value): + """ Toolkit specific method to set the control's value. """ + raise NotImplementedError + + def _observe_control_value(self, remove=False): + """ Toolkit specific method to change the control value observer. """ + raise NotImplementedError + + def _get_control_tooltip(self): + """ Toolkit specific method to get the control's tooltip. """ + raise NotImplementedError + + def _set_control_tooltip(self, tooltip): + """ Toolkit specific method to set the control's tooltip. """ + raise NotImplementedError + + def _observe_control_context_menu(self, remove=False): + """ Toolkit specific method to change the control menu observer. + + This should use _handle_control_context_menu as the event handler. + """ + raise NotImplementedError + + def _handle_control_context_menu(self, event): + """ Handle a context menu event. + + This should call show_context_menu with appropriate position x and y + arguments. + + The function signature will likely vary from toolkit to toolkit. + """ + raise NotImplementedError + + # Trait change handlers ------------------------------------------------- + + def _value_updated(self, value): + if self.control is not None: + self._set_control_value(value) + + def _tooltip_updated(self, tooltip): + if self.control is not None: + self._set_control_tooltip(tooltip) + + def _context_menu_updated(self, old, new): + if self.control is not None: + if new is None: + self._observe_control_context_menu(remove=True) + if old is None: + self._observe_control_context_menu() diff -Nru python-pyface-4.5.2/pyface/fields/i_spin_field.py python-pyface-6.1.2/pyface/fields/i_spin_field.py --- python-pyface-4.5.2/pyface/fields/i_spin_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/fields/i_spin_field.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,138 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2017-19, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" The spin field interface. """ + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +from traits.api import HasTraits, Int, Property, Range, Tuple + +from pyface.fields.i_field import IField + + +class ISpinField(IField): + """ The spin field interface. + + This is for spinners holding integer values. + """ + + #: The current value of the spinner + value = Range(low='minimum', high='maximum') + + #: The bounds of the spinner + bounds = Tuple(Int, Int) + + #: The minimum value + minimum = Property(Int, depends_on='bounds') + + #: The maximum value + maximum = Property(Int, depends_on='bounds') + + +class MSpinField(HasTraits): + + #: The current value of the spinner + value = Range(low='minimum', high='maximum') + + #: The bounds for the spinner + bounds = Tuple(Int, Int) + + #: The minimum value for the spinner + minimum = Property(Int, depends_on='bounds') + + #: The maximum value for the spinner + maximum = Property(Int, depends_on='bounds') + + # ------------------------------------------------------------------------ + # object interface + # ------------------------------------------------------------------------ + + def __init__(self, **traits): + value = traits.pop('value', None) + if 'bounds' in traits: + traits['value'] = traits['bounds'][0] + super(MSpinField, self).__init__(**traits) + if value is not None: + self.value = value + + # ------------------------------------------------------------------------ + # Private interface + # ------------------------------------------------------------------------ + + def _initialize_control(self): + super(MSpinField, self)._initialize_control() + self._set_control_bounds(self.bounds) + self._set_control_value(self.value) + + def _add_event_listeners(self): + """ Set up toolkit-specific bindings for events """ + super(MSpinField, self)._add_event_listeners() + self.on_trait_change(self._bounds_updated, 'bounds', + dispatch='ui') + if self.control is not None: + self._observe_control_value() + + def _remove_event_listeners(self): + """ Remove toolkit-specific bindings for events """ + if self.control is not None: + self._observe_control_value(remove=True) + self.on_trait_change(self._bounds_updated, 'bounds', + dispatch='ui', remove=True) + super(MSpinField, self)._remove_event_listeners() + + # Toolkit control interface --------------------------------------------- + + def _get_control_bounds(self): + """ Toolkit specific method to get the control's bounds. """ + raise NotImplementedError() + + def _set_control_bounds(self, bounds): + """ Toolkit specific method to set the control's bounds. """ + raise NotImplementedError() + + # Trait property handlers ----------------------------------------------- + + def _get_minimum(self): + return self.bounds[0] + + def _set_minimum(self, value): + if value > self.maximum: + self.bounds = (value, value) + else: + self.bounds = (value, self.maximum) + if value > self.value: + self.value = value + + def _get_maximum(self): + return self.bounds[1] + + def _set_maximum(self, value): + if value < self.minimum: + self.bounds = (value, value) + else: + self.bounds = (self.minimum, value) + if value < self.value: + self.value = value + + # Trait defaults -------------------------------------------------------- + + def _value_default(self): + return self.bounds[0] + + # Trait change handlers -------------------------------------------------- + + def _bounds_updated(self): + if self.control is not None: + self._set_control_bounds(self.bounds) diff -Nru python-pyface-4.5.2/pyface/fields/i_text_field.py python-pyface-6.1.2/pyface/fields/i_text_field.py --- python-pyface-4.5.2/pyface/fields/i_text_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/fields/i_text_field.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,164 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2017-19, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" The text field interface. """ + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +from traits.api import Bool, Enum, HasTraits, Unicode + +from pyface.fields.i_field import IField + + +class ITextField(IField): + """ The text field interface. """ + + #: The value held by the field. + value = Unicode + + #: Should the text trait be updated on user edits, or when done editing. + update_text = Enum('auto', 'editing_finished') + + #: Placeholder text for an empty field. + placeholder = Unicode + + #: Display typed text, or one of several hidden "password" modes. + echo = Enum('normal', 'password') + + #: Whether or not the field is read-only. + read_only = Bool + + +class MTextField(HasTraits): + """ The text field mix-in. """ + + #: The value held by the field. + value = Unicode + + #: Should the value be updated on every keystroke, or when done editing. + update_text = Enum('auto', 'editing_finished') + + #: Placeholder text for an empty field. + placeholder = Unicode + + #: Display typed text, or one of several hidden "password" modes. + echo = Enum('normal', 'password') + + #: Whether or not the field is read-only. + read_only = Bool + + # ------------------------------------------------------------------------ + # Private interface + # ------------------------------------------------------------------------ + + def _initialize_control(self): + self._set_control_echo(self.echo) + self._set_control_value(self.value) + self._set_control_placeholder(self.placeholder) + self._set_control_read_only(self.read_only) + + super(MTextField, self)._initialize_control() + + def _add_event_listeners(self): + """ Set up toolkit-specific bindings for events """ + super(MTextField, self)._add_event_listeners() + self.on_trait_change(self._update_text_updated, 'update_text', + dispatch='ui') + self.on_trait_change(self._placeholder_updated, 'placeholder', + dispatch='ui') + self.on_trait_change(self._echo_updated, 'echo', dispatch='ui') + self.on_trait_change(self._read_only_updated, 'read_only', + dispatch='ui') + if self.control is not None: + if self.update_text == 'editing_finished': + self._observe_control_editing_finished() + else: + self._observe_control_value() + + def _remove_event_listeners(self): + """ Remove toolkit-specific bindings for events """ + if self.control is not None: + if self.update_text == 'editing_finished': + self._observe_control_editing_finished(remove=True) + else: + self._observe_control_value(remove=True) + self.on_trait_change(self._update_text_updated, 'update_text', + dispatch='ui', remove=True) + self.on_trait_change(self._placeholder_updated, 'placeholder', + dispatch='ui', remove=True) + self.on_trait_change(self._echo_updated, 'echo', dispatch='ui', + remove=True) + self.on_trait_change(self._read_only_updated, 'read_only', + dispatch='ui', remove=True) + super(MTextField, self)._remove_event_listeners() + + def _editing_finished(self): + if self.control is not None: + value = self._get_control_value() + self._update_value(value) + + # Toolkit control interface --------------------------------------------- + + def _get_control_placeholder(self): + """ Toolkit specific method to set the control's placeholder. """ + raise NotImplementedError + + def _set_control_placeholder(self, placeholder): + """ Toolkit specific method to set the control's placeholder. """ + raise NotImplementedError + + def _get_control_echo(self): + """ Toolkit specific method to get the control's echo. """ + raise NotImplementedError + + def _set_control_echo(self, echo): + """ Toolkit specific method to set the control's echo. """ + raise NotImplementedError + + def _get_control_read_only(self): + """ Toolkit specific method to get the control's read_only state. """ + raise NotImplementedError + + def _set_control_read_only(self, read_only): + """ Toolkit specific method to set the control's read_only state. """ + raise NotImplementedError + + def _observe_control_editing_finished(self, remove=False): + """ Change observation of whether editing is finished. """ + raise NotImplementedError + + # Trait change handlers -------------------------------------------------- + + def _placeholder_updated(self): + if self.control is not None: + self._set_control_placeholder(self.placeholder) + + def _echo_updated(self): + if self.control is not None: + self._set_control_echo(self.echo) + + def _read_only_updated(self): + if self.control is not None: + self._set_control_read_only(self.read_only) + + def _update_text_updated(self, new): + """ Change how we listen to for updates to text value. """ + if self.control is not None: + if new == 'editing_finished': + self._observe_control_value(remove=True) + self._observe_control_editing_finished() + else: + self._observe_control_editing_finished(remove=True) + self._observe_control_value() diff -Nru python-pyface-4.5.2/pyface/fields/spin_field.py python-pyface-6.1.2/pyface/fields/spin_field.py --- python-pyface-4.5.2/pyface/fields/spin_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/fields/spin_field.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,19 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2019, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" The spin field widget. """ + +# Import the toolkit specific version. +from pyface.toolkit import toolkit_object + +SpinField = toolkit_object('fields.spin_field:SpinField') diff -Nru python-pyface-4.5.2/pyface/fields/tests/field_mixin.py python-pyface-6.1.2/pyface/fields/tests/field_mixin.py --- python-pyface-4.5.2/pyface/fields/tests/field_mixin.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/fields/tests/field_mixin.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,68 @@ +# Copyright (c) 2019, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +from traits.testing.unittest_tools import UnittestTools + +from pyface.action.api import Action, MenuManager +from pyface.gui import GUI +from pyface.window import Window + + +class FieldMixin(UnittestTools): + """ Mixin which provides standard methods for all fields. """ + + def setUp(self): + self.gui = GUI() + + self.parent = Window() + self.parent._create() + self.addCleanup(self._destroy_parent) + self.gui.process_events() + + self.widget = self._create_widget() + + self.parent.open() + self.gui.process_events() + + def _create_widget(self): + raise NotImplementedError() + + def _create_widget_control(self): + self.widget._create() + self.addCleanup(self._destroy_widget) + self.widget.show(True) + self.gui.process_events() + + def _destroy_parent(self): + self.parent.destroy() + self.gui.process_events() + self.parent = None + + def _destroy_widget(self): + self.widget.destroy() + self.gui.process_events() + self.widget = None + + # Tests ------------------------------------------------------------------ + + def test_field_tooltip(self): + self._create_widget_control() + self.widget.tooltip = "New tooltip." + self.gui.process_events() + + self.assertEqual(self.widget._get_control_tooltip(), "New tooltip.") + + def test_field_menu(self): + self._create_widget_control() + self.widget.menu = MenuManager(Action(name='Test'), name='Test') + self.gui.process_events() diff -Nru python-pyface-4.5.2/pyface/fields/tests/test_combo_field.py python-pyface-6.1.2/pyface/fields/tests/test_combo_field.py --- python-pyface-4.5.2/pyface/fields/tests/test_combo_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/fields/tests/test_combo_field.py 2019-06-14 12:22:56.000000000 +0000 @@ -0,0 +1,111 @@ +# Copyright (c) 2019, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +import unittest + +from six import text_type + +from pyface.image_resource import ImageResource +from ..combo_field import ComboField +from .field_mixin import FieldMixin + + +class TestComboField(FieldMixin, unittest.TestCase): + + def _create_widget(self): + return ComboField( + parent=self.parent.control, + value='one', + values=['one', 'two', 'three', 'four'], + tooltip='Dummy', + ) + + # Tests ------------------------------------------------------------------ + + def test_combo_field(self): + self._create_widget_control() + + self.widget.value = 'two' + self.gui.process_events() + + self.assertEqual(self.widget._get_control_value(), 'two') + self.assertEqual(self.widget._get_control_text(), 'two') + + def test_combo_field_set(self): + self._create_widget_control() + + with self.assertTraitChanges(self.widget, 'value', count=1): + self.widget._set_control_value('two') + self.gui.process_events() + + self.assertEqual(self.widget.value, 'two') + + def test_combo_field_formatter(self): + self.widget.formatter = text_type + self.widget.values = [0, 1, 2, 3] + self._create_widget_control() + + self.widget.value = 2 + self.gui.process_events() + + self.assertEqual(self.widget._get_control_value(), 2) + self.assertEqual(self.widget._get_control_text(), '2') + + def test_combo_field_formatter_changed(self): + self.widget.values = [1, 2, 3, 4] + self.widget.value = 2 + self.widget.formatter = text_type + self._create_widget_control() + + self.widget.formatter = 'Number {}'.format + self.gui.process_events() + + self.assertEqual(self.widget._get_control_value(), 2) + self.assertEqual(self.widget._get_control_text(), 'Number 2') + + def test_combo_field_formatter_set(self): + self.widget.values = [1, 2, 3, 4] + self.widget.formatter = text_type + self._create_widget_control() + + with self.assertTraitChanges(self.widget, 'value', count=1): + self.widget._set_control_value(2) + self.gui.process_events() + + self.assertEqual(self.widget.value, 2) + + def test_combo_field_icon_formatter(self): + image = ImageResource('question') + self.widget.values = [1, 2, 3, 4] + self.widget.formatter = lambda x: (image, str(x)) + self._create_widget_control() + + self.widget.value = 2 + self.gui.process_events() + + self.assertEqual(self.widget._get_control_value(), 2) + self.assertEqual(self.widget._get_control_text(), '2') + + def test_combo_field_values(self): + self._create_widget_control() + + self.widget.values = ['four', 'five', 'one', 'six'] + self.gui.process_events() + + # XXX different results in Wx and Qt + # As best I can tell, difference is at the Traits level + # On Qt setting 'values' sets 'value' to "four" before combofield + # handler sees it. On Wx it remains as "one" at point of handler + # call. Possibly down to dictionary ordering or something + # similar. + self.assertIn(self.widget.value, {'one', 'four'}) diff -Nru python-pyface-4.5.2/pyface/fields/tests/test_spin_field.py python-pyface-6.1.2/pyface/fields/tests/test_spin_field.py --- python-pyface-4.5.2/pyface/fields/tests/test_spin_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/fields/tests/test_spin_field.py 2019-06-14 12:22:56.000000000 +0000 @@ -0,0 +1,57 @@ +# Copyright (c) 2019, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +import unittest + +from ..spin_field import SpinField +from .field_mixin import FieldMixin + + +class TestSpinField(FieldMixin, unittest.TestCase): + + def _create_widget(self): + return SpinField( + parent=self.parent.control, + value=1, + bounds=(0, 100), + tooltip='Dummy', + ) + + # Tests ------------------------------------------------------------------ + + def test_spin_field(self): + self._create_widget_control() + + self.widget.value = 5 + self.gui.process_events() + + self.assertEqual(self.widget._get_control_value(), 5) + + def test_spin_field_set(self): + self._create_widget_control() + + with self.assertTraitChanges(self.widget, 'value', count=1): + self.widget._set_control_value(5) + self.gui.process_events() + + self.assertEqual(self.widget.value, 5) + + def test_spin_field_bounds(self): + self._create_widget_control() + + self.widget.bounds = (10, 50) + self.gui.process_events() + + self.assertEqual(self.widget._get_control_bounds(), (10, 50)) + self.assertEqual(self.widget._get_control_value(), 10) + self.assertEqual(self.widget.value, 10) diff -Nru python-pyface-4.5.2/pyface/fields/tests/test_text_field.py python-pyface-6.1.2/pyface/fields/tests/test_text_field.py --- python-pyface-4.5.2/pyface/fields/tests/test_text_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/fields/tests/test_text_field.py 2019-06-14 12:22:56.000000000 +0000 @@ -0,0 +1,94 @@ +# Copyright (c) 2019, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +import unittest + +from pyface.toolkit import toolkit +from ..text_field import TextField +from .field_mixin import FieldMixin + + +is_wx = (toolkit.toolkit == 'wx') + + +class TestTextField(FieldMixin, unittest.TestCase): + + def _create_widget(self): + return TextField( + parent=self.parent.control, + value='test', + tooltip='Dummy', + ) + + # Tests ------------------------------------------------------------------ + + def test_text_field(self): + self._create_widget_control() + + self.widget.value = 'new value' + self.gui.process_events() + + self.assertEqual(self.widget._get_control_value(), 'new value') + + def test_text_field_set(self): + self._create_widget_control() + + with self.assertTraitChanges(self.widget, 'value', count=1): + self.widget._set_control_value('new value') + self.gui.process_events() + + self.assertEqual(self.widget.value, 'new value') + + def test_text_field_echo(self): + self.widget.echo = 'password' + self._create_widget_control() + + self.assertEqual(self.widget._get_control_echo(), 'password') + + @unittest.skipIf(is_wx, "Can't change password mode for wx after control " + "creation.") + def test_text_field_echo_change(self): + self._create_widget_control() + + self.widget.echo = 'password' + self.gui.process_events() + + self.assertEqual(self.widget._get_control_echo(), 'password') + + def test_text_field_placeholder(self): + self._create_widget_control() + + self.widget.placeholder = 'test' + self.gui.process_events() + + self.assertEqual(self.widget._get_control_placeholder(), 'test') + + def test_text_field_readonly(self): + self.widget.read_only = True + self._create_widget_control() + + self.gui.process_events() + + self.assertEqual(self.widget._get_control_read_only(), True) + + @unittest.skipIf(is_wx, "Can't change read_only mode for wx after control " + "creation.") + def test_text_field_readonly_change(self): + self._create_widget_control() + + self.widget.read_only = True + self.gui.process_events() + + self.assertEqual(self.widget._get_control_read_only(), True) + diff -Nru python-pyface-4.5.2/pyface/fields/text_field.py python-pyface-6.1.2/pyface/fields/text_field.py --- python-pyface-4.5.2/pyface/fields/text_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/fields/text_field.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,19 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2017, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" The text field widget. """ + +# Import the toolkit specific version. +from pyface.toolkit import toolkit_object + +TextField = toolkit_object('fields.text_field:TextField') diff -Nru python-pyface-4.5.2/pyface/file_dialog.py python-pyface-6.1.2/pyface/file_dialog.py --- python-pyface-4.5.2/pyface/file_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/file_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -16,7 +16,9 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object FileDialog = toolkit_object('file_dialog:FileDialog') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/grid/api.py python-pyface-6.1.2/pyface/grid/api.py --- python-pyface-4.5.2/pyface/grid/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/api.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.api import * diff -Nru python-pyface-4.5.2/pyface/grid/checkbox_image_renderer.py python-pyface-6.1.2/pyface/grid/checkbox_image_renderer.py --- python-pyface-4.5.2/pyface/grid/checkbox_image_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/checkbox_image_renderer.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.checkbox_image_renderer import * diff -Nru python-pyface-4.5.2/pyface/grid/checkbox_renderer.py python-pyface-6.1.2/pyface/grid/checkbox_renderer.py --- python-pyface-4.5.2/pyface/grid/checkbox_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/checkbox_renderer.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.checkbox_renderer import * diff -Nru python-pyface-4.5.2/pyface/grid/combobox_focus_handler.py python-pyface-6.1.2/pyface/grid/combobox_focus_handler.py --- python-pyface-4.5.2/pyface/grid/combobox_focus_handler.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/combobox_focus_handler.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.combobox_focus_handler import * diff -Nru python-pyface-4.5.2/pyface/grid/composite_grid_model.py python-pyface-6.1.2/pyface/grid/composite_grid_model.py --- python-pyface-4.5.2/pyface/grid/composite_grid_model.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/composite_grid_model.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.composite_grid_model import * diff -Nru python-pyface-4.5.2/pyface/grid/edit_image_renderer.py python-pyface-6.1.2/pyface/grid/edit_image_renderer.py --- python-pyface-4.5.2/pyface/grid/edit_image_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/edit_image_renderer.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.edit_image_renderer import * diff -Nru python-pyface-4.5.2/pyface/grid/edit_renderer.py python-pyface-6.1.2/pyface/grid/edit_renderer.py --- python-pyface-4.5.2/pyface/grid/edit_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/edit_renderer.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.edit_renderer import * diff -Nru python-pyface-4.5.2/pyface/grid/grid_cell_image_renderer.py python-pyface-6.1.2/pyface/grid/grid_cell_image_renderer.py --- python-pyface-4.5.2/pyface/grid/grid_cell_image_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/grid_cell_image_renderer.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.grid_cell_image_renderer import * diff -Nru python-pyface-4.5.2/pyface/grid/grid_cell_renderer.py python-pyface-6.1.2/pyface/grid/grid_cell_renderer.py --- python-pyface-4.5.2/pyface/grid/grid_cell_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/grid_cell_renderer.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.grid_cell_renderer import * diff -Nru python-pyface-4.5.2/pyface/grid/grid_model.py python-pyface-6.1.2/pyface/grid/grid_model.py --- python-pyface-4.5.2/pyface/grid/grid_model.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/grid_model.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.grid_model import * diff -Nru python-pyface-4.5.2/pyface/grid/grid.py python-pyface-6.1.2/pyface/grid/grid.py --- python-pyface-4.5.2/pyface/grid/grid.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/grid.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.grid import * diff -Nru python-pyface-4.5.2/pyface/grid/inverted_grid_model.py python-pyface-6.1.2/pyface/grid/inverted_grid_model.py --- python-pyface-4.5.2/pyface/grid/inverted_grid_model.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/inverted_grid_model.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.inverted_grid_model import * diff -Nru python-pyface-4.5.2/pyface/grid/mapped_grid_cell_image_renderer.py python-pyface-6.1.2/pyface/grid/mapped_grid_cell_image_renderer.py --- python-pyface-4.5.2/pyface/grid/mapped_grid_cell_image_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/mapped_grid_cell_image_renderer.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.mapped_grid_cell_image_renderer import * diff -Nru python-pyface-4.5.2/pyface/grid/simple_grid_model.py python-pyface-6.1.2/pyface/grid/simple_grid_model.py --- python-pyface-4.5.2/pyface/grid/simple_grid_model.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/simple_grid_model.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.simple_grid_model import * diff -Nru python-pyface-4.5.2/pyface/grid/trait_grid_cell_adapter.py python-pyface-6.1.2/pyface/grid/trait_grid_cell_adapter.py --- python-pyface-4.5.2/pyface/grid/trait_grid_cell_adapter.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/trait_grid_cell_adapter.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.trait_grid_cell_adapter import * diff -Nru python-pyface-4.5.2/pyface/grid/trait_grid_model.py python-pyface-6.1.2/pyface/grid/trait_grid_model.py --- python-pyface-4.5.2/pyface/grid/trait_grid_model.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/grid/trait_grid_model.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging -logging.warn('DEPRECATED: pyface.grid, ' - 'use pyface.ui.wx.grid instead.') + +logger = logging.getLogger(__name__) +logger.warning('DEPRECATED: pyface.grid, use pyface.ui.wx.grid instead.') from pyface.ui.wx.grid.trait_grid_model import * diff -Nru python-pyface-4.5.2/pyface/gui_application.py python-pyface-6.1.2/pyface/gui_application.py --- python-pyface-4.5.2/pyface/gui_application.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/gui_application.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,297 @@ +# Copyright (c) 2014-2017 by Enthought, Inc., Austin, TX +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +""" +This module defines a :py:class:`GUIApplication` subclass of +:py:class:`pyface.application.Application`. This adds cross-platform GUI +application support to the base class via :py:class:`pyface.application.GUI`. + +At a minimum this class expects to be provided with a factory that returns +:py:class:`pyface.i_window.IWindow` instances. For pure Pyface applications +this is most likely to be a subclass of +:py:class:`pyface.application_window.ApplicationWindow`. + +""" + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) +import logging + +from traits.api import ( + Bool, Callable, Instance, List, ReadOnly, Tuple, Undefined, Vetoable, + on_trait_change +) + +from .application import Application +from .i_dialog import IDialog +from .i_splash_screen import ISplashScreen +from .i_window import IWindow +from .ui_traits import Image + +logger = logging.getLogger(__name__) + + +def default_window_factory(application, **kwargs): + """ The default window factory returns an application window. + + This is almost never the right thing, but allows users to get off the + ground with the base class. + """ + from pyface.application_window import ApplicationWindow + return ApplicationWindow(**kwargs) + + +class GUIApplication(Application): + """ A basic Pyface GUI application. """ + + # 'GUIApplication' traits ------------------------------------------------- + + # Branding --------------------------------------------------------------- + + #: The splash screen for the application. No splash screen by default + splash_screen = Instance(ISplashScreen) + + #: The about dialog for the application. + about_dialog = Instance(IDialog) + + #: Icon for the application (used in window titlebars) + icon = Image + + #: Logo of the application (used in splash screens and about dialogs) + logo = Image + + # Window management ------------------------------------------------------ + + #: The window factory to use when creating a window for the application. + window_factory = Callable(default_window_factory) + + #: Default window size + window_size = Tuple((800, 600)) + + #: Currently active Window if any + active_window = Instance(IWindow) + + #: List of all open windows in the application + windows = List(Instance(IWindow)) + + #: The Pyface GUI instance for the application + gui = ReadOnly + + # Protected interface ---------------------------------------------------- + + #: Flag if the exiting of the application was explicitely requested by user + # An 'explicit' exit is when the 'exit' method is called. + # An 'implicit' exit is when the user closes the last open window. + _explicit_exit = Bool(False) + + # ------------------------------------------------------------------------- + # 'GUIApplication' interface + # ------------------------------------------------------------------------- + + # Window lifecycle methods ----------------------------------------------- + + def create_window(self, **kwargs): + """ Create a new application window. + + By default uses the :py:attr:`window_factory` to do this. Subclasses + can override if they want to do something different or additional. + + Parameters + ---------- + **kwargs : dict + Additional keyword arguments to pass to the window factory. + + Returns + ------- + window : IWindow instance or None + The new IWindow instance. + """ + window = self.window_factory(application=self, **kwargs) + + if window.size == (-1, -1): + window.size = self.window_size + if not window.title: + window.title = self.name + if self.icon: + window.icon = self.icon + + return window + + def add_window(self, window): + """ Add a new window to the windows we are tracking. """ + + # Keep a handle on all windows created so that non-active windows don't + # get garbage collected + self.windows.append(window) + + # Something might try to veto the opening of the window. + opened = window.open() + if opened: + window.activate() + + # Action handlers -------------------------------------------------------- + + def do_about(self): + """ Display the about dialog, if it exists. """ + if self.about_dialog is not None: + self.about_dialog.open() + + # ------------------------------------------------------------------------- + # 'Application' interface + # ------------------------------------------------------------------------- + + def start(self): + """ Start the application, setting up things that are required + + Subclasses should open at least one ApplicationWindow or subclass in + their start method, and should call the superclass start() method + before doing any work themselves. + """ + from pyface.gui import GUI + + ok = super(GUIApplication, self).start() + if ok: + # create the GUI so that the splash screen comes up first thing + if self.gui is Undefined: + self.gui = GUI(splash_screen=self.splash_screen) + + # create the initial windows to show + self._create_windows() + + return ok + + # ------------------------------------------------------------------------- + # 'GUIApplication' Private interface + # ------------------------------------------------------------------------- + + def _create_windows(self): + """ Create the initial windows to display. + + By default calls :py:meth:`create_window` once. Subclasses can + override this method. + """ + window = self.create_window() + self.add_window(window) + + # ------------------------------------------------------------------------- + # 'Application' private interface + # ------------------------------------------------------------------------- + + def _run(self): + """ Actual implementation of running the application: starting the GUI + event loop. + """ + # Fire a notification that the app is running. This is guaranteed to + # happen after all initialization has occurred and the event loop has + # started. A listener for this event is a good place to do things + # where you want the event loop running. + self.gui.invoke_later( + self._fire_application_event, 'application_initialized' + ) + + # start the GUI - script blocks here + self.gui.start_event_loop() + return True + + # Destruction methods ----------------------------------------------------- + + def _can_exit(self): + """ Check with each window to see if it can be closed + + The fires closing events for each window, and returns False if any + listener vetos. + """ + if not super(GUIApplication, self)._can_exit(): + return False + + for window in reversed(self.windows): + window.closing = event = Vetoable() + if event.veto: + return False + else: + return True + + def _prepare_exit(self): + """ Close each window """ + # ensure copy of list, as we modify original list while closing + for window in list(reversed(self.windows)): + window.destroy() + window.closed = window + + def _exit(self): + """ Shut down the event loop """ + self.gui.stop_event_loop() + + # Trait default handlers ------------------------------------------------ + + def _window_factory_default(self): + """ Default to ApplicationWindow + + This is almost never the right thing, but allows users to get off the + ground with the base class. + """ + from pyface.application_window import ApplicationWindow + return lambda application, **kwargs: ApplicationWindow(**kwargs) + + def _splash_screen_default(self): + """ Default SplashScreen """ + from pyface.splash_screen import SplashScreen + + dialog = SplashScreen() + if self.logo: + dialog.image = self.logo + return dialog + + def _about_dialog_default(self): + """ Default AboutDialog """ + from sys import version_info + if (version_info.major, version_info.minor) >= (3, 2): + from html import escape + else: + from cgi import escape + from pyface.about_dialog import AboutDialog + + additions = [ + u"

{}

".format(escape(self.name)), + u"Copyright © 2018 {}, all rights reserved".format( + escape(self.company), + ), + u"", + ] + additions += [escape(line) for line in self.description.split('\n\n')] + + dialog = AboutDialog( + title=u"About {}".format(self.name), + additions=additions, + ) + if self.logo: + dialog.image = self.logo + return dialog + + # Trait listeners -------------------------------------------------------- + + @on_trait_change('windows:activated') + def _on_activate_window(self, window, trait, old, new): + """ Listener that tracks currently active window. + """ + if window in self.windows: + self.active_window = window + + @on_trait_change('windows:deactivated') + def _on_deactivate_window(self, window, trait, old, new): + """ Listener that tracks currently active window. + """ + self.active_window = None + + @on_trait_change('windows:closed') + def _on_window_closed(self, window, trait, old, new): + """ Listener that ensures window handles are released when closed. + """ + if window in self.windows: + self.windows.remove(window) diff -Nru python-pyface-4.5.2/pyface/gui.py python-pyface-6.1.2/pyface/gui.py --- python-pyface-4.5.2/pyface/gui.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/gui.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,7 +15,9 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object GUI = toolkit_object('gui:GUI') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/heading_text.py python-pyface-6.1.2/pyface/heading_text.py --- python-pyface-4.5.2/pyface/heading_text.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/heading_text.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,7 +15,9 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object HeadingText = toolkit_object('heading_text:HeadingText') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/i_about_dialog.py python-pyface-6.1.2/pyface/i_about_dialog.py --- python-pyface-4.5.2/pyface/i_about_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_about_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,13 +13,12 @@ #------------------------------------------------------------------------------ """ The interface for a simple 'About' dialog. """ - # Enthought library imports. from traits.api import Instance, List, Unicode # Local imports. -from i_dialog import IDialog -from image_resource import ImageResource +from pyface.i_dialog import IDialog +from pyface.image_resource import ImageResource class IAboutDialog(IDialog): @@ -27,10 +26,10 @@ #### 'IAboutDialog' interface ############################################# - # Additional strings to be added to the dialog. + #: Additional strings to be added to the dialog. additions = List(Unicode) - # The image displayed in the dialog. + #: The image displayed in the dialog. image = Instance(ImageResource, ImageResource('about')) @@ -38,5 +37,3 @@ """ The mixin class that contains common code for toolkit specific implementations of the IAboutDialog interface. """ - -### EOF ####################################################################### diff -Nru python-pyface-4.5.2/pyface/i_application_window.py python-pyface-6.1.2/pyface/i_application_window.py --- python-pyface-4.5.2/pyface/i_application_window.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_application_window.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,14 +13,13 @@ #------------------------------------------------------------------------------ """ The interface of a top-level application window. """ - # Enthought library imports. from traits.api import Instance, List # Local imports. -from action.api import MenuBarManager, StatusBarManager, ToolBarManager -from image_resource import ImageResource -from i_window import IWindow +from pyface.action.api import MenuBarManager, StatusBarManager, ToolBarManager +from pyface.i_image_resource import IImageResource +from pyface.i_window import IWindow class IApplicationWindow(IWindow): @@ -29,26 +28,29 @@ The application window has support for a menu bar, tool bar and a status bar (all of which are optional). - Usage: Create a sub-class of this class and override the protected - '_create_contents' method. + Usage + ----- + + Create a sub-class of this class and override the + :py:meth:`._create_contents` method. """ #### 'IApplicationWindow' interface ####################################### - # The window icon. The default is toolkit specific. - icon = Instance(ImageResource) + #: The window icon. The default is toolkit specific. + icon = Instance(IImageResource) - # The menu bar manager (None iff there is no menu bar). + #: The menu bar manager (None iff there is no menu bar). menu_bar_manager = Instance(MenuBarManager) - # The status bar manager (None iff there is no status bar). + #: The status bar manager (None iff there is no status bar). status_bar_manager = Instance(StatusBarManager) - # The tool bar manager (None iff there is no tool bar). + #: The tool bar manager (None iff there is no tool bar). tool_bar_manager = Instance(ToolBarManager) - # If the underlying toolkit supports multiple toolbars, you can use this - # list instead of the single ToolBarManager instance above. + #: If the underlying toolkit supports multiple toolbars, you can use this + #: list instead of the single ToolBarManager instance above. tool_bar_managers = List(ToolBarManager) ########################################################################### @@ -58,31 +60,52 @@ def _create_contents(self, parent): """ Create and return the window's contents. - parent is the parent control. + Parameters + ---------- + parent : toolkit control + The window's toolkit control to be used as the parent for + widgets in the contents. + + Returns + ------- + control : toolkit control + A control to be used for contents of the window. """ def _create_menu_bar(self, parent): """ Creates the menu bar (if required). - parent is the parent control. + Parameters + ---------- + parent : toolkit control + The window's toolkit control. """ def _create_status_bar(self, parent): """ Creates the status bar (if required). - parent is the parent control. + Parameters + ---------- + parent : toolkit control + The window's toolkit control. """ def _create_tool_bar(self, parent): """ Creates the tool bar (if required). - parent is the parent control. + Parameters + ---------- + parent : toolkit control + The window's toolkit control. """ def _create_trim_widgets(self, parent): """ Creates the 'trim' widgets (the widgets around the window). - parent is the parent control. + Parameters + ---------- + parent : toolkit control + The window's toolkit control. """ def _set_window_icon(self): @@ -91,7 +114,7 @@ class MApplicationWindow(object): """ The mixin class that contains common code for toolkit specific - implementations of the IApplicationWindow interface. + implementations of the :py:class:`IApplicationWindow` interface. Implements: destroy(), _create_trim_widgets() """ @@ -102,10 +125,10 @@ def destroy(self): """ Destroy the control if it exists. """ - + if self.menu_bar_manager is not None: self.menu_bar_manager.destroy() - + if self.tool_bar_manager is not None: self.tool_bar_manager.destroy() for tool_bar_manager in self.tool_bar_managers: @@ -118,14 +141,16 @@ ########################################################################### def _create_trim_widgets(self, parent): - """ Creates the 'trim' widgets (the widgets around the window). """ + """ Creates the 'trim' widgets (the widgets around the window). + + Parameters + ---------- + parent : toolkit control + The window's toolkit control. + """ # All of these are optional. self._set_window_icon() self._create_menu_bar(parent) self._create_tool_bar(parent) self._create_status_bar(parent) - - return - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/i_clipboard.py python-pyface-6.1.2/pyface/i_clipboard.py --- python-pyface-4.5.2/pyface/i_clipboard.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_clipboard.py 2019-05-03 08:18:49.000000000 +0000 @@ -14,29 +14,49 @@ """ The interface for manipulating the toolkit clipboard. """ +try: + from collections.abc import Sequence +except ImportError: # Python 3.8 deprecation + from collections import Sequence # ETS imports from traits.api import HasStrictTraits, Interface, Property -from traitsui.ui_traits import SequenceTypes +import six class IClipboard(Interface): """ The interface for manipulating the toolkit clipboard. """ - data_type = Property # The type of data in the clipboard (string) - data = Property # Arbitrary Python data - has_data = Property # Arbitrary Python data is available - - object_type = Property # Name of the class of object in the clipboard - object_data = Property # Python object data - has_object_data = Property # Python object data is available + #: The type of data in the clipboard (string) + data_type = Property - text_data = Property # Text data - has_text_data = Property # Text data is available + #: Arbitrary Python data stored in the clipboard + data = Property - file_data = Property # File name data - has_file_data = Property # File name data is available + #: Arbitrary Python data is available in the clipboard + has_data = Property + + #: Name of the class of object in the clipboard + object_type = Property + + #: Python object data + object_data = Property + + #: Python object data is available + has_object_data = Property + + #: Text data + text_data = Property + + #: Text data is available + has_text_data = Property + + #: File name data + file_data = Property + + #: File name data is available + has_file_data = Property class BaseClipboard(HasStrictTraits): @@ -44,19 +64,35 @@ implementations of IClipboard. """ - data_type = Property # The type of data in the clipboard (string) - data = Property # Arbitrary Python data - has_data = Property # Arbitrary Python data is available - - object_type = Property # Name of the class of object in the clipboard - object_data = Property # Python object data - has_object_data = Property # Python object data is available + #: The type of data in the clipboard (string) + data_type = Property + + #: Arbitrary Python data stored in the clipboard + data = Property + + #: Arbitrary Python data is available in the clipboard + has_data = Property + + #: Name of the class of object in the clipboard + object_type = Property + + #: Python object data + object_data = Property + + #: Python object data is available + has_object_data = Property + + #: Text data + text_data = Property + + #: Text data is available + has_text_data = Property - text_data = Property # Text data - has_text_data = Property # Text data is available + #: File name data + file_data = Property - file_data = Property # File name data - has_file_data = Property # File name data is available + #: File name data is available + has_file_data = Property def _get_data(self): if self.has_text_data: @@ -68,9 +104,9 @@ return None def _set_data(self, data): - if isinstance(data, basestring): + if isinstance(data, six.string_types): self.text_data = data - elif type(data) in SequenceTypes: + elif isinstance(data, Sequence): self.file_data = data else: self.object_data = data diff -Nru python-pyface-4.5.2/pyface/i_confirmation_dialog.py python-pyface-6.1.2/pyface/i_confirmation_dialog.py --- python-pyface-4.5.2/pyface/i_confirmation_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_confirmation_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -18,9 +18,9 @@ from traits.api import Bool, Enum, Instance, Unicode # Local imports. -from constant import CANCEL, NO, YES -from i_dialog import IDialog -from image_resource import ImageResource +from pyface.constant import CANCEL, NO, YES +from pyface.i_dialog import IDialog +from pyface.i_image_resource import IImageResource class IConfirmationDialog(IDialog): @@ -28,29 +28,29 @@ #### 'IConfirmationDialog' interface ###################################### - # Should the cancel button be displayed? + #: Should the cancel button be displayed? cancel = Bool(False) - # The default button. + #: The default button. default = Enum(NO, YES, CANCEL) - # The image displayed with the message. The default is toolkit specific. - image = Instance(ImageResource) + #: The image displayed with the message. The default is toolkit specific. + image = Instance(IImageResource) - # The message displayed in the body of the dialog (use the inherited - # 'title' trait to set the title of the dialog itself). + #: The message displayed in the body of the dialog (use the inherited + #: 'title' trait to set the title of the dialog itself). message = Unicode - # Some informative text to display below the main message + #: Some informative text to display below the main message informative = Unicode - # Some additional details that can be exposed by the user + #: Some additional details that can be exposed by the user detail = Unicode - # The label for the 'no' button. The default is toolkit specific. + #: The label for the 'no' button. The default is toolkit specific. no_label = Unicode - # The label for the 'yes' button. The default is toolkit specific. + #: The label for the 'yes' button. The default is toolkit specific. yes_label = Unicode @@ -58,5 +58,3 @@ """ The mixin class that contains common code for toolkit specific implementations of the IConfirmationDialog interface. """ - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/i_dialog.py python-pyface-6.1.2/pyface/i_dialog.py --- python-pyface-4.5.2/pyface/i_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -18,8 +18,8 @@ from traits.api import Bool, Enum, Int, Str, Unicode # Local imports. -from constant import OK -from i_window import IWindow +from pyface.constant import OK +from pyface.i_window import IWindow class IDialog(IWindow): @@ -34,27 +34,27 @@ #### 'IDialog' interface ################################################## - # The label for the 'cancel' button. The default is toolkit specific. + #: The label for the 'cancel' button. The default is toolkit specific. cancel_label = Unicode - # The context sensitive help Id (the 'Help' button is only shown iff this - # is set). + #: The context sensitive help Id (the 'Help' button is only shown iff this + #: is set). help_id = Str - # The label for the 'help' button. The default is toolkit specific. + #: The label for the 'help' button. The default is toolkit specific. help_label = Unicode - # The label for the 'ok' button. The default is toolkit specific. + #: The label for the 'ok' button. The default is toolkit specific. ok_label = Unicode - # Is the dialog resizeable? + #: Is the dialog resizeable? resizeable = Bool(True) - # The return code after the window is closed to indicate whether the dialog - # was closed via 'Ok' or 'Cancel'). + #: The return code after the window is closed to indicate whether the dialog + #: was closed via 'Ok' or 'Cancel'). return_code = Int(OK) - # The dialog style (is it modal or not). + #: The dialog style (is it modal or not). # FIXME v3: It doesn't seem possible to use non-modal dialogs. (How do you # get access to the buttons?) style = Enum('modal', 'nonmodal') @@ -70,7 +70,12 @@ dialog closed afterwards. The 'return_code' trait is updated according to the button the user pressed and this value is also returned. - If the dialog is non-modal 'OK' is returned. + If the dialog is non-modal the return_code trait is set to 'OK'. + + Returns + ------- + return_code : OK or CANCEL + The value of the ``return_code`` trait. """ ########################################################################### @@ -80,23 +85,57 @@ def _create_buttons(self, parent): """ Create and return the buttons. - parent is the parent control. + Parameters + ---------- + parent : toolkit control + The dialog's toolkit control to be used as the parent for + buttons. + + Returns + ------- + buttons : toolkit control + A control containing the dialog's buttons. + """ def _create_contents(self, parent): - """ Create the dialog contents. + """ Create and return the dialog's contents. - parent is the parent control. + Parameters + ---------- + parent : toolkit control + The window's toolkit control to be used as the parent for + widgets in the contents. + + Returns + ------- + control : toolkit control + A control to be used for contents of the window. """ def _create_dialog_area(self, parent): - """ Create and return the main content of the dialog. + """ Create and return the main content of the dialog's window. - parent is the parent control. + Parameters + ---------- + parent : toolkit control + A toolkit control to be used as the parent for widgets in the + contents. + + Returns + ------- + control : toolkit control + A control to be used for main contents of the dialog. """ def _show_modal(self): - """ Opens the dialog as a modal dialog and returns the return code. """ + """ Opens the dialog as a modal dialog. + + Returns + ------- + return_code : OK or CANCEL + The return code from the user's interactions. + """ class MDialog(object): @@ -112,8 +151,19 @@ ########################################################################### def open(self): - """ Opens the dialog. """ + """ Opens the dialog. + + If the dialog is modal then the dialog's event loop is entered and the + dialog closed afterwards. The 'return_code' trait is updated according + to the button the user pressed and this value is also returned. + If the dialog is non-modal the return_code trait is set to 'OK'. + + Returns + ------- + return_code : OK or CANCEL + The value of the ``return_code`` trait. + """ if self.control is None: self._create() @@ -147,5 +197,3 @@ # We don't bother for dialogs. pass - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/i_directory_dialog.py python-pyface-6.1.2/pyface/i_directory_dialog.py --- python-pyface-4.5.2/pyface/i_directory_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_directory_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -19,7 +19,7 @@ from traits.api import Bool, Unicode # Local imports. -from i_dialog import IDialog +from pyface.i_dialog import IDialog class IDirectoryDialog(IDialog): @@ -29,20 +29,20 @@ #### 'IDirectoryDialog' interface ######################################### - # The default path. The default (ie. the default default path) is toolkit - # specific. + #: The default path. The default (ie. the default default path) is toolkit + #: specific. # FIXME v3: The default should be the current directory. (It seems wx is # the problem, although the file dialog does the right thing.) default_path = Unicode - # The message to display in the dialog. The default is toolkit specific. + #: The message to display in the dialog. The default is toolkit specific. message = Unicode - # True iff the dialog should include a button that allows the user to - # create a new directory. + #: True iff the dialog should include a button that allows the user to + #: create a new directory. new_directory = Bool(True) - # The path of the chosen directory. + #: The path of the chosen directory. path = Unicode @@ -50,5 +50,3 @@ """ The mixin class that contains common code for toolkit specific implementations of the IDirectoryDialog interface. """ - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/i_drop_handler.py python-pyface-6.1.2/pyface/i_drop_handler.py --- python-pyface-4.5.2/pyface/i_drop_handler.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_drop_handler.py 2019-05-03 08:18:49.000000000 +0000 @@ -7,10 +7,32 @@ """ def can_handle_drop(self, event, target): - """ Returns True if the current drop handler can handle the given drag - event occurring on the given target widget. + """ Whether or not a drag event can be handled + + This is used to give feedback to the user about whether a drop is + possible via the shape of the cursor or similar indicators. + + Parameters + ---------- + event : drag event + A drag event with information about the object being dragged. + target : toolkit widget + The widget that would be dropped on. + + Returns + ------- + can_drop : bool + True if the current drop handler can handle the given drag + event occurring on the given target widget. """ def handle_drop(self, event, target): """ Performs drop action when drop event occurs on target widget. + + Parameters + ---------- + event : drop event + A drop event with information about the object being dropped. + target : toolkit widget + The widget that would be dropped on """ diff -Nru python-pyface-4.5.2/pyface/i_file_dialog.py python-pyface-6.1.2/pyface/i_file_dialog.py --- python-pyface-4.5.2/pyface/i_file_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_file_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -21,7 +21,8 @@ from traits.api import Enum, Unicode, Int # Local imports. -from i_dialog import IDialog +from pyface.i_dialog import IDialog +import six class IFileDialog(IDialog): @@ -30,33 +31,33 @@ #### 'IFileDialog' interface ############################################## - # The 'action' that the user is peforming on the directory. + #: The 'action' that the user is peforming on the directory. action = Enum('open', 'save as') - # The default directory. + #: The default directory. default_directory = Unicode - # The default filename. + #: The default filename. default_filename = Unicode - # The default path (directory and filename) of the chosen file. This is - # only used when the *default_directory* and *default_filename* are not set - # and is equivalent to setting both. + #: The default path (directory and filename) of the chosen file. This is + #: only used when the *default_directory* and *default_filename* are not set + #: and is equivalent to setting both. default_path = Unicode - # The directory containing the chosen file. + #: The directory containing the chosen file. directory = Unicode - # The name of the chosen file. + #: The name of the chosen file. filename = Unicode - # The path (directory and filename) of the chosen file. + #: The path (directory and filename) of the chosen file. path = Unicode - # The wildcard used to restrict the set of files. + #: The wildcard used to restrict the set of files. wildcard = Unicode - # The index of the selected wildcard. + #: The index of the selected wildcard. wildcard_index = Int(0) @@ -75,36 +76,41 @@ # the format to be portable between toolkits - so stick with PyQt # supporting the wx format or invent a data structure. - # A file dialog wildcard for Python files. + #: A file dialog wildcard for Python files. WILDCARD_PY = "Python files (*.py)|*.py|" - # A file dialog wildcard for text files. + #: A file dialog wildcard for text files. WILDCARD_TXT = "Text files (*.txt)|*.txt|" - # A file dialog wildcard for all files. + #: A file dialog wildcard for all files. if sys.platform == 'win32': WILDCARD_ALL = "All files (*.*)|*.*|" else: WILDCARD_ALL = "All files (*)|*" - # A file dialog wildcard for Zip archives. + #: A file dialog wildcard for Zip archives. WILDCARD_ZIP = "Zip files (*.zip)|*.zip|" ########################################################################### # 'MFileDialog' *CLASS* interface. ########################################################################### + @classmethod def create_wildcard(cls, description, extension): - """ Creates a wildcard for a given extension. """ + """ Creates a wildcard for a given extension. - if isinstance(extension, basestring): + Parameters + ---------- + description : str + A human-readable description of the pattern. + extenstion : list + The wildcard patterns for the extension. + """ + + if isinstance(extension, six.string_types): pattern = extension else: pattern = ';'.join(extension) return "%s (%s)|%s|" % (description, pattern, pattern) - - create_wildcard = classmethod(create_wildcard) - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/i_gui.py python-pyface-6.1.2/pyface/i_gui.py --- python-pyface-4.5.2/pyface/i_gui.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_gui.py 2019-05-03 08:18:49.000000000 +0000 @@ -32,16 +32,16 @@ #### 'GUI' interface ###################################################### - # Is the GUI busy (i.e. should the busy cursor, often an hourglass, be - # displayed)? + #: Is the GUI busy (i.e. should the busy cursor, often an hourglass, be + #: displayed)? busy = Bool(False) - # Has the GUI's event loop been started? + #: Has the GUI's event loop been started? started = Bool(False) - # A directory on the local file system that we can read and write to at - # will. This is used to persist layout information etc. Note that - # individual toolkits will have their own directory. + #: A directory on the local file system that we can read and write to at + #: will. This is used to persist layout information etc. Note that + #: individual toolkits will have their own directory. state_location = Unicode ########################################################################### @@ -49,16 +49,24 @@ ########################################################################### def __init__(self, splash_screen=None): - """ Initialise a new GUI. splash_screen is an optional splash screen - that will be displayed until the event loop is started. + """ Initialise a new GUI. + + Parameters + ---------- + splash_screen : ISplashScreen instance or None + An optional splash screen that will be displayed until the event + loop is started. """ ########################################################################### # 'GUI' class interface. ########################################################################### + @staticmethod def allow_interrupt(): - """ Override the SIGINT handler to ensure the process can be + """ Override SIGINT to prevent swallowing KeyboardInterrupt + + Override the SIGINT handler to ensure the process can be interrupted. This prevents GUI toolkits from swallowing KeyboardInterrupt exceptions. @@ -66,42 +74,83 @@ run interactively. """ - allow_interrupt = staticmethod(allow_interrupt) - + @classmethod def invoke_after(cls, millisecs, callable, *args, **kw): - """ Call a callable after a specific delay in the main GUI thread. """ + """ Call a callable after a specific delay in the main GUI thread. - invoke_after = classmethod(invoke_after) + Parameters + ---------- + millisecs : float + Delay in milliseconds + callable : callable + Callable to be called after the delay + args, kwargs : + Arguments and keyword arguments to be used when calling. + """ + @classmethod def invoke_later(cls, callable, *args, **kw): - """ Call a callable in the main GUI thread. """ + """ Call a callable in the main GUI thread. - invoke_later = classmethod(invoke_later) + Parameters + ---------- + callable : callable + Callable to be called after the delay + args, kwargs : + Arguments and keyword arguments to be used when calling. + """ + @classmethod def set_trait_after(cls, millisecs, obj, trait_name, new): - """ Sets a trait after a specific delay in the main GUI thread. """ + """ Sets a trait after a specific delay in the main GUI thread. - set_trait_after = classmethod(set_trait_after) + Parameters + ---------- + millisecs : float + Delay in milliseconds + obj : HasTraits instance + Object on which the trait is to be set + trait_name : str + The name of the trait to set + new : any + The value to set. + """ + @classmethod def set_trait_later(cls, obj, trait_name, new): - """ Sets a trait in the main GUI thread. """ + """ Sets a trait in the main GUI thread. - set_trait_later = classmethod(set_trait_later) + Parameters + ---------- + obj : HasTraits instance + Object on which the trait is to be set + trait_name : str + The name of the trait to set + new : any + The value to set. + """ + @staticmethod def process_events(allow_user_events=True): - """ Process any pending GUI events. If allow_user_events is False then - user generated events are not processed. - """ + """ Process any pending GUI events. - process_events = staticmethod(process_events) + Parameters + ---------- + allow_user_events : bool + If allow_user_events is ``False`` then user generated events are not + processed. + """ + @staticmethod def set_busy(busy=True): - """Specify if the GUI is busy. If `True` is passed, the - cursor is set to a 'busy' cursor. Passing `False` will reset - the cursor to the default. - """ + """Specify if the GUI is busy. - set_busy = staticmethod(set_busy) + Parameters + ---------- + busy : bool + If ``True`` is passed, the cursor is set to a 'busy' cursor. + Passing ``False`` will reset the cursor to the default. + """ ########################################################################### # 'GUI' interface. @@ -121,16 +170,20 @@ Implements: _default_state_location() """ + @staticmethod def allow_interrupt(): - """ Override the SIGINT handler to ensure the process can be + """ Override SIGINT to prevent swallowing KeyboardInterrupt + + Override the SIGINT handler to ensure the process can be interrupted. This prevents GUI toolkits from swallowing KeyboardInterrupt exceptions. + + Warning: do not call this method if you intend your application to be + run interactively. """ import signal signal.signal(signal.SIGINT, signal.SIG_DFL) - allow_interrupt = staticmethod(allow_interrupt) - def _default_state_location(self): """ Return the default state location. """ diff -Nru python-pyface-4.5.2/pyface/i_heading_text.py python-pyface-6.1.2/pyface/i_heading_text.py --- python-pyface-4.5.2/pyface/i_heading_text.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_heading_text.py 2019-05-03 08:18:49.000000000 +0000 @@ -18,7 +18,7 @@ from traits.api import Instance, Int, Interface, Unicode # Local imports. -from image_resource import ImageResource +from pyface.i_image_resource import IImageResource class IHeadingText(Interface): @@ -26,22 +26,20 @@ #### 'IHeadingText' interface ############################################# - # Heading level. + #: Heading level. # # fixme: Currently we ignore anything but one, but in future we could # have different visualizations based on the level. level = Int(1) - # The heading text. + #: The heading text. text = Unicode('Default') - # The background image. - image = Instance(ImageResource) + #: The background image. + image = Instance(IImageResource) class MHeadingText(object): """ The mixin class that contains common code for toolkit specific implementations of the IHeadingText interface. """ - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/i_image_cache.py python-pyface-6.1.2/pyface/i_image_cache.py --- python-pyface-4.5.2/pyface/i_image_cache.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_image_cache.py 2019-05-03 08:18:49.000000000 +0000 @@ -26,25 +26,55 @@ ########################################################################### def __init__(self, width, height): - """ Creates a new image cache for images of the given size. """ + """ Creates a new image cache for images of the given size. + + Parameters + ---------- + width : int + The width of the images in pixels + height : int + The height of the images in pixels + """ ########################################################################### # 'ImageCache' interface. ########################################################################### def get_image(self, filename): - """ Returns the specified image. """ + """ Returns the scaled image specified. + + Parameters + ---------- + filename : str + The name of the file containing the image. + + Returns + ------- + scaled : toolkit image + The image referred to in the file, scaled to the cache's width + and height. + """ # FIXME v3: The need to distinguish between bitmaps and images is toolkit # specific so, strictly speaking, the conversion to a bitmap should be done # wherever the toolkit actually needs it. def get_bitmap(self, filename): - """ Returns the specified image as a bitmap. """ + """ Returns the scaled image specified as a bitmap. + + Parameters + ---------- + filename : str + The name of the file containing the image. + + Returns + ------- + scaled : toolkit bitmap + The image referred to in the file, scaled to the cache's width + and height, as a bitmap. + """ class MImageCache(object): """ The mixin class that contains common code for toolkit specific implementations of the IImageCache interface. """ - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/i_image_resource.py python-pyface-6.1.2/pyface/i_image_resource.py --- python-pyface-4.5.2/pyface/i_image_resource.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_image_resource.py 2019-05-03 08:18:49.000000000 +0000 @@ -10,12 +10,15 @@ #------------------------------------------------------------------------------ """ The interface for an image resource. """ - -import operator +try: + from collections.abc import Sequence +except ImportError: # Python 3.8 deprecation + from collections import Sequence from pyface.resource_manager import resource_manager from pyface.resource.resource_path import resource_module, resource_path from traits.api import Interface, List, Unicode +import six class IImageResource(Interface): @@ -27,14 +30,14 @@ #### 'ImageResource' interface ############################################ - # The absolute path to the image. + #: The absolute path to the image. absolute_path = Unicode - # The name of the image. + #: The name of the image. name = Unicode - # A list of directories, classes or instances that will be used to search - # for the image (see the resource manager for more details). + #: A list of directories, classes or instances that will be used to search + #: for the image (see the resource manager for more details). search_path = List ########################################################################### @@ -49,16 +52,71 @@ ########################################################################### def create_image(self, size=None): - """ Creates a toolkit specific image for this resource. """ + """ Creates a toolkit specific image for this resource. + + Parameters + ---------- + size : (int, int) or None + The desired size as a width, height tuple, or None if wanting + default image size. + + Returns + ------- + image : toolkit image + The toolkit image corresponding to the resource and the specified + size. + """ # FIXME v3: The need to distinguish between bitmaps and images is toolkit # specific so, strictly speaking, the conversion to a bitmap should be done # wherever the toolkit actually needs it. def create_bitmap(self, size=None): - """ Creates a toolkit specific bitmap for this resource. """ + """ Creates a toolkit specific bitmap for this resource. + + Parameters + ---------- + size : (int, int) or None + The desired size as a width, height tuple, or None if wanting + default image size. + + Returns + ------- + image : toolkit image + The toolkit image corresponding to the resource and the specified + size as a bitmap. + """ def create_icon(self, size=None): - """ Creates a toolkit-specific icon for this resource. """ + """ Creates a toolkit-specific icon for this resource. + + Parameters + ---------- + size : (int, int) or None + The desired size as a width, height tuple, or None if wanting + default image size. + + Returns + ------- + image : toolkit image + The toolkit image corresponding to the resource and the specified + size as an icon. + """ + + @classmethod + def image_size(cls, image): + """ Get the size of a toolkit image + + Parameters + ---------- + image : toolkit image + A toolkit image to compute the size of. + + Returns + ------- + size : tuple + The (width, height) tuple giving the size of the image. + """ + class MImageResource(object): @@ -70,7 +128,7 @@ #### Private interface #################################################### - # The image-not-found image. Note that it is not a trait. + #: The image-not-found image. Note that it is not a trait. _image_not_found = None ########################################################################### @@ -80,7 +138,9 @@ def __init__(self, name, search_path=None): self.name = name - if search_path is not None and operator.isSequenceType(search_path): + if isinstance(search_path, six.string_types): + _path = [search_path] + elif isinstance(search_path, Sequence): _path = search_path elif search_path is not None: _path = [search_path] @@ -93,8 +153,20 @@ ########################################################################### def create_image(self, size=None): - """ Creates a toolkit specific image for this resource. """ + """ Creates a toolkit specific image for this resource. + Parameters + ---------- + size : (int, int) or None + The desired size as a width, height tuple, or None if wanting + default image size. + + Returns + ------- + image : toolkit image + The toolkit image corresponding to the resource and the specified + size. + """ ref = self._get_ref(size) if ref is not None: image = ref.load() @@ -109,7 +181,19 @@ ########################################################################### def _get_ref(self, size=None): - """ Return the resource manager reference to the image. """ + """ Return the resource manager reference to the image. + + Parameters + ---------- + size : (int, int) or None + The desired size as a width, height tuple, or None if wanting + default image size. + + Returns + ------- + ref : ImageReference instance + The reference to the requested image. + """ if self._ref is None: self._ref = resource_manager.locate_image(self.name, @@ -118,7 +202,13 @@ return self._ref def _get_image_not_found_image(self): - """ Returns the 'image not found' image. """ + """ Returns the 'image not found' image. + + Returns + ------- + image : toolkit image + The 'not found' toolkit image. + """ not_found = self._get_image_not_found() @@ -130,8 +220,15 @@ return image + @classmethod def _get_image_not_found(cls): - """ Returns the 'image not found' image resource. """ + """ Returns the 'image not found' image resource. + + Returns + ------- + not_found : ImageResource instance + An image resource for the the 'not found' image. + """ if cls._image_not_found is None: from pyface.image_resource import ImageResource @@ -139,7 +236,3 @@ cls._image_not_found = ImageResource('image_not_found') return cls._image_not_found - - _get_image_not_found = classmethod(_get_image_not_found) - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/image/image.py python-pyface-6.1.2/pyface/image/image.py --- python-pyface-4.5.2/pyface/image/image.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/image/image.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,1298 @@ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# +# Thanks for using Enthought open source! +# +# Author: David C. Morrill +# Date: 11/03/2007 + +""" Defines the ImageLibrary object used to manage Pyface image libraries. +""" + +import sys +from os import (environ, listdir, remove, stat, makedirs, rename, access, + R_OK, W_OK, X_OK) +from os.path import (join, isdir, isfile, splitext, abspath, dirname, + basename, exists) +from stat import ST_MTIME +from platform import system +from zipfile import is_zipfile, ZipFile, ZIP_DEFLATED +import datetime +import time +from six.moves._thread import allocate_lock +from threading import Thread + +from traits.api import (HasPrivateTraits, Property, Str, Int, List, Dict, + File, Instance, Bool, Undefined, TraitError, Float, + Any, cached_property) +from traits.trait_base import get_resource_path, traits_home + +from pyface.api import ImageResource +from pyface.resource_manager import resource_manager +from pyface.resource.resource_reference import (ImageReference, + ResourceReference) +from pyface.ui_traits import HasMargin, HasBorder, Alignment + +#--------------------------------------------------------------------------- +# Constants: +#--------------------------------------------------------------------------- + +# Standard image file extensions: +ImageFileExts = ( '.png', '.gif', '.jpg', 'jpeg' ) + +# The image_cache root directory: +image_cache_path = join( traits_home(), 'image_cache' ) + +# Names of files that should not be copied when ceating a new library copy: +dont_copy_list = ( 'image_volume.py', 'image_info.py', 'license.txt' ) + +#-- Code Generation Templates ---------------------------------------------- + +# Template for creating an ImageVolumeInfo object: +ImageVolumeInfoCodeTemplate = \ +""" ImageVolumeInfo( + description=%(description)s, + copyright=%(copyright)s, + license=%(license)s, + image_names=%(image_names)s + )""" + +# Template for creating an ImageVolumeInfo license text: +ImageVolumeInfoTextTemplate = \ +"""Description: + %s + +Copyright: + %s + +License: + %s + +Applicable Images: +%s""" + +# Template for creating an ImageVolume object: +ImageVolumeTemplate = \ +"""from pyface.image.image import ImageVolume, ImageVolumeInfo + +volume = ImageVolume( + category=%(category)s, + keywords=%(keywords)s, + aliases=%(aliases)s, + time_stamp=%(time_stamp)s, + info=[ +%(info)s + ] +)""" + +# Template for creating an ImageVolume 'images' list: +ImageVolumeImagesTemplate = \ +"""from pyface.image.image import ImageInfo +from pyface.ui_traits import Margin, Border + +images = [ +%s +]""" + +# Template for creating an ImageInfo object: +ImageInfoTemplate = \ +""" ImageInfo( + name=%(name)s, + image_name=%(image_name)s, + description=%(description)s, + category=%(category)s, + keywords=%(keywords)s, + width=%(width)d, + height=%(height)d, + border=Border(%(bleft)d, %(bright)d, %(btop)d, %(bbottom)d), + content=Margin(%(cleft)d, %(cright)d, %(ctop)d, %(cbottom)d), + label=Margin(%(lleft)d, %(lright)d, %(ltop)d, %(lbottom)d), + alignment=%(alignment)s + )""" + + +def read_file ( file_name ): + """ Returns the contents of the specified *file_name*. + """ + with open(file_name, 'rb') as fh: + return fh.read() + + +def write_file ( file_name, data ): + """ Writes the specified data to the specified file. + """ + with open( file_name, 'wb' ) as fh: + fh.write( data ) + + +def get_python_value ( source, name ): + """ Returns the value of a Python symbol loaded from a specified source + code string. + """ + temp = {} + exec(source.replace( b'\r', b'' ), globals(), temp) + return temp[ name ] + + +def time_stamp_for(time): + """ Returns a specified time as a text string. + """ + return datetime.datetime.utcfromtimestamp(time).strftime('%Y%m%d%H%M%S') + + +def add_object_prefix ( dict, object, prefix ): + """ Adds all traits from a specified object to a dictionary with a specified + name prefix. + """ + for name, value in object.trait_get().items(): + dict[ prefix + name ] = value + + +def split_image_name ( image_name ): + """ Splits a specified **image_name** into its constituent volume and file + names and returns a tuple of the form: ( volume_name, file_name ). + """ + col = image_name.find( ':' ) + volume_name = image_name[ 1: col ] + file_name = image_name[ col + 1: ] + if file_name.find( '.' ) < 0: + file_name += '.png' + + return ( volume_name, file_name ) + + +def join_image_name ( volume_name, file_name ): + """ Joins a specified **volume_name** and **file_name** into an image name, + and return the resulting image name. + """ + root, ext = splitext( file_name ) + if (ext == '.png') and (root.find( '.' ) < 0): + file_name = root + + return '@%s:%s' % ( volume_name, file_name ) + + +class FastZipFile ( HasPrivateTraits ): + """ Provides fast access to zip files by keeping the underlying zip file + open across multiple uses. + """ + + #: The path to the zip file: + path = File + + #: The open zip file object (if None, the file is closed): + zf = Property + + #: The time stamp of when the zip file was most recently accessed: + time_stamp = Float + + #: The lock used to manage access to the 'zf' trait between the two threads: + access = Any + + #-- Public Methods --------------------------------------------------------- + + def namelist ( self ): + """ Returns the names of all files in the top-level zip file directory. + """ + self.access.acquire() + try: + return self.zf.namelist() + finally: + self.access.release() + + def read ( self, file_name ): + """ Returns the contents of the specified **file_name** from the zip + file. + """ + self.access.acquire() + try: + return self.zf.read( file_name ) + finally: + self.access.release() + + def close ( self ): + """ Temporarily closes the zip file (usually while the zip file is being + replaced by a different version). + """ + self.access.acquire() + try: + if self._zf is not None: + self._zf.close() + self._zf = None + finally: + self.access.release() + + #-- Default Value Implementations ------------------------------------------ + + def _access_default ( self ): + return allocate_lock() + + #-- Property Implementations ----------------------------------------------- + + def _get_zf ( self ): + # Restart the time-out: + self.time_stamp = time.time() + + if self._zf is None: + self._zf = ZipFile( self.path, 'r' ) + if self._running is None: + Thread( target = self._process ).start() + self._running = True + + return self._zf + + #-- Private Methods -------------------------------------------------------- + + def _process ( self ): + """ Waits until the zip file has not been accessed for a while, then + closes the file and exits. + """ + while True: + time.sleep( 1 ) + self.access.acquire() + if time.time() > (self.time_stamp + 2.0): + if self._zf is not None: + self._zf.close() + self._zf = None + + self._running = None + self.access.release() + break + + self.access.release() + +#------------------------------------------------------------------------------- +# 'ImageInfo' class: +#------------------------------------------------------------------------------- + +class ImageInfo ( HasPrivateTraits ): + """ Defines a class that contains information about a specific Traits UI + image. + """ + + #: The volume this image belongs to: + volume = Instance( 'ImageVolume' ) + + #: The user friendly name of the image: + name = Str + + #: The full image name (e.g. '@standard:floppy'): + image_name = Str + + #: A description of the image: + description = Str + + #: The category that the image belongs to: + category = Str( 'General' ) + + #: A list of keywords used to describe/categorize the image: + keywords = List( Str ) + + #: The image width (in pixels): + width = Int + + #: The image height (in pixels): + height = Int + + #: The border inset: + border = HasBorder + + #: The margin to use around the content: + content = HasMargin + + #: The margin to use around the label: + label = HasMargin + + #: The alignment to use for the label: + alignment = Alignment + + #: The copyright that applies to this image: + copyright = Property + + #: The license that applies to this image: + license = Property + + #: A read-only string containing the Python code needed to construct this + #: ImageInfo object: + image_info_code = Property + + #-- Default Value Implementations ------------------------------------------ + + def _name_default ( self ): + return split_image_name( self.image_name )[1] + + def _width_default ( self ): + if self.volume is None: + return 0 + + image = self.volume.image_resource( self.image_name ) + if image is None: + self.height = 0 + return 0 + + width, self.height = image.image_size(image.create_image()) + + return width + + def _height_default ( self ): + if self.volume is None: + return 0 + + image = self.volume.image_resource( self.image_name ) + if image is None: + self.width = 0 + return 0 + + self.width, height = image.image_size(image.create_image()) + + return height + + #-- Property Implementations ----------------------------------------------- + + def _get_image_info_code ( self ): + data = dict((name, repr(value)) + for name, value in self.trait_get( + 'name', 'image_name', 'description', 'category', + 'keywords', 'alignment' + ).items()) + data.update(self.trait_get('width', 'height')) + sides = ['left', 'right', 'top', 'bottom'] + data.update(('b'+name, getattr(self.border, name)) for name in sides) + data.update(('c'+name, getattr(self.content, name)) for name in sides) + data.update(('l'+name, getattr(self.label, name)) for name in sides) + return (ImageInfoTemplate % data) + + def _get_copyright ( self ): + return self._volume_info( 'copyright' ) + + def _get_license ( self ): + return self._volume_info( 'license' ) + + #-- Private Methods -------------------------------------------------------- + + def _volume_info ( self, name ): + """ Returns the VolumeInfo object that applies to this image. + """ + info = self.volume.volume_info( self.image_name ) + if info is not None: + return getattr( info, name, 'Unknown' ) + + return 'Unknown' + +#------------------------------------------------------------------------------- +# 'ImageVolumeInfo' class: +#------------------------------------------------------------------------------- + +class ImageVolumeInfo ( HasPrivateTraits ): + + #: A general description of the images: + description = Str( 'No volume description specified.' ) + + #: The copyright that applies to the images: + copyright = Str( 'No copyright information specified.' ) + + #: The license that applies to the images: + license = Str( 'No license information specified.' ) + + #: The list of image names within the volume the information applies to. + #: Note that an empty list means that the information applies to all images + #: in the volume: + image_names = List( Str ) + + #: A read-only string containing the Python code needed to construct this + #: ImageVolumeInfo object: + image_volume_info_code = Property + + #: A read-only string containing the text describing the volume info: + image_volume_info_text = Property + + #-- Property Implementations ----------------------------------------------- + + @cached_property + def _get_image_volume_info_code ( self ): + data = dict((name, repr(getattr(self, name))) + for name in ['description', 'copyright', 'license', + 'image_names']) + + return (ImageVolumeInfoCodeTemplate % data) + + @cached_property + def _get_image_volume_info_text ( self ): + description = self.description.replace( '\n', '\n ' ) + license = self.license.replace( '\n', '\n ' ).strip() + image_names = self.image_names + image_names.sort() + if len( image_names ) == 0: + image_names = [ 'All' ] + images = '\n'.join( [ ' - ' + image_name + for image_name in image_names ] ) + + return (ImageVolumeInfoTextTemplate % ( description, self.copyright, + license, images )) + + #-- Public Methods --------------------------------------------------------- + + def clone ( self ): + """ Returns a copy of the ImageVolumeInfo object. + """ + return self.clone(['description', 'copyright', 'license']) + +#------------------------------------------------------------------------------- +# 'ImageVolume' class: +#------------------------------------------------------------------------------- + +class ImageVolume ( HasPrivateTraits ): + + #: The canonical name of this volume: + name = Str + + #: The list of volume descriptors that apply to this volume: + info = List( ImageVolumeInfo ) + + #: The category that the volume belongs to: + category = Str( 'General' ) + + #: A list of keywords used to describe the volume: + keywords = List( Str ) + + #: The list of aliases for this volume: + aliases = List( Str ) + + #: The path of the file that defined this volume: + path = File + + #: Is the path a zip file? + is_zip_file = Bool( True ) + + #: The FastZipFile object used to access the underlying zip file: + zip_file = Instance( FastZipFile ) + + #: The list of images available in the volume: + images = List( ImageInfo ) + + #: A dictionary mapping image names to ImageInfo objects: + catalog = Property( depends_on = 'images' ) + + #: The time stamp of when the image library was last modified: + time_stamp = Str + + #: A read-only string containing the Python code needed to construct this + #: ImageVolume object: + image_volume_code = Property + + #: A read-only string containing the Python code needed to construct the + #: 'images' list for this ImageVolume object: + images_code = Property + + #: A read-only string containing the text describing the contents of the + #: volume (description, copyright, license information, and the images they + #: apply to): + license_text = Property + + #-- Public Methods --------------------------------------------------------- + + def update ( self ): + """ Updates the contents of the image volume from the underlying + image store, and saves the results. + """ + # Unlink all our current images: + for image in self.images: + image.volume = None + + # Make sure the images are up to date by deleting any current value: + self.reset_traits(['images']) + + # Save the new image volume information: + self.save() + + def save ( self ): + """ Saves the contents of the image volume using the current contents + of the **ImageVolume**. + """ + path = self.path + + if not self.is_zip_file: + # Make sure the directory is writable: + if not access( path, R_OK | W_OK | X_OK ): + return False + + # Make sure the directory and zip file are writable: + elif ((not access( dirname( path ), R_OK | W_OK | X_OK )) or + (exists( path ) and (not access( path, W_OK )))): + return False + + # Pre-compute the images code, because it can require a long time + # to load all of the images so that we can determine their size, and we + # don't want that time to interfere with the time stamp of the image + # volume: + images_code = self.images_code + + if not self.is_zip_file: + # We need to time stamp when this volume info was generated, but + # it needs to be the same or newer then the time stamp of the file + # it is in. So we use the current time plus a 'fudge factor' to + # allow for some slop in when the OS actually time stamps the file: + self.time_stamp = time_stamp_for( time.time() + 5.0 ) + + # Write the volume manifest source code to a file: + write_file( join( path, 'image_volume.py' ), + self.image_volume_code ) + + # Write the image info source code to a file: + write_file( join( path, 'image_info.py' ), images_code ) + + # Write a separate license file for human consumption: + write_file( join( path, 'license.txt' ), self.license_text ) + + return True + + # Create a temporary name for the new .zip file: + file_name = path + '.###' + + # Create the new zip file: + new_zf = ZipFile( file_name, 'w', ZIP_DEFLATED ) + + try: + # Get the current zip file: + cur_zf = self.zip_file + + # Copy all of the image files from the current zip file to the new + # zip file: + for name in cur_zf.namelist(): + if name not in dont_copy_list: + new_zf.writestr( name, cur_zf.read( name ) ) + + # Temporarily close the current zip file while we replace it with + # the new version: + cur_zf.close() + + # We need to time stamp when this volume info was generated, but + # it needs to be the same or newer then the time stamp of the file + # it is in. So we use the current time plus a 'fudge factor' to + # allow for some slop in when the OS actually time stamps the file: + self.time_stamp = time_stamp_for( time.time() + 10.0 ) + + # Write the volume manifest source code to the zip file: + new_zf.writestr( 'image_volume.py', self.image_volume_code ) + + # Write the image info source code to the zip file: + new_zf.writestr( 'image_info.py', images_code ) + + # Write a separate license file for human consumption: + new_zf.writestr( 'license.txt', self.license_text ) + + # Done creating the new zip file: + new_zf.close() + new_zf = None + + # Rename the original file to a temporary name, so we can give the + # new file the original name. Note that unlocking the original zip + # file after the previous close sometimes seems to take a while, + # which is why we repeatedly try the rename until it either succeeds + # or takes so long that it must have failed for another reason: + temp_name = path + '.$$$' + for i in range( 50 ): + try: + rename( path, temp_name ) + break + except Exception: + time.sleep( 0.1 ) + + try: + rename( file_name, path ) + file_name = temp_name + except: + rename( temp_name, path ) + raise + finally: + if new_zf is not None: + new_zf.close() + + remove( file_name ) + + return True + + def image_resource ( self, image_name ): + """ Returns the ImageResource object for the specified **image_name**. + """ + # Get the name of the image file: + volume_name, file_name = split_image_name( image_name ) + + if self.is_zip_file: + # See if we already have the image file cached in the file system: + cache_file = self._check_cache( file_name ) + if cache_file is None: + # If not cached, then create a zip file reference: + ref = ZipFileReference( + resource_factory = resource_manager.resource_factory, + zip_file = self.zip_file, + path = self.path, + volume_name = self.name, + file_name = file_name ) + else: + # Otherwise, create a cache file reference: + ref = ImageReference( resource_manager.resource_factory, + filename = cache_file ) + else: + # Otherwise, create a normal file reference: + ref = ImageReference( resource_manager.resource_factory, + filename = join( self.path, file_name ) ) + + # Create the ImageResource object using the reference (note that the + # ImageResource class will not allow us to specify the reference in the + # constructor): + resource = ImageResource( file_name ) + resource._ref = ref + + # Return the ImageResource: + return resource + + def image_data ( self, image_name ): + """ Returns the image data (i.e. file contents) for the specified image + name. + """ + volume_name, file_name = split_image_name( image_name ) + + if self.is_zip_file: + return self.zip_file.read( file_name ) + else: + return read_file( join( self.path, file_name ) ) + + def volume_info ( self, image_name ): + """ Returns the ImageVolumeInfo object that corresponds to the + image specified by **image_name**. + """ + for info in self.info: + if ((len( info.image_names ) == 0) or + (image_name in info.image_names)): + return info + + raise ValueError('Volume info for image name {} not found.'.format( + repr(info))) + + #-- Default Value Implementations ------------------------------------------ + + def _info_default ( self ): + return [ ImageVolumeInfo() ] + + def _images_default ( self ): + return self._load_image_info() + + #-- Property Implementations ----------------------------------------------- + + @cached_property + def _get_catalog ( self ): + return dict((image.image_name, image) for image in self.images) + + def _get_image_volume_code ( self ): + data = dict((name, repr(value)) + for name, value in self.trait_get( + 'description', 'category', 'keywords', 'aliases', + 'time_stamp' + ).items()) + data['info'] = ',\n'.join(info.image_volume_info_code + for info in self.info) + return (ImageVolumeTemplate % data) + + def _get_images_code ( self ): + images = ',\n'.join(info.image_info_code for info in self.images) + + return (ImageVolumeImagesTemplate % images) + + def _get_license_text ( self ): + return (('\n\n%s\n' % ('-' * 79)).join( [ info.image_volume_info_text + for info in self.info ] )) + + #-- Private Methods -------------------------------------------------------- + + def _load_image_info ( self ): + """ Returns the list of ImageInfo objects for the images in the volume. + """ + # If there is no current path, then return a default list of images: + if self.path == '': + return [] + + time_stamp = time_stamp_for( stat( self.path )[ ST_MTIME ] ) + volume_name = self.name + old_images = [] + cur_images = [] + + if self.is_zip_file: + zf = self.zip_file + + # Get the names of all top-level entries in the zip file: + names = zf.namelist() + + # Check to see if there is an image info manifest file: + if 'image_info.py' in names: + # Load the manifest code and extract the images list: + old_images = get_python_value( zf.read( 'image_info.py' ), + 'images' ) + + # Check to see if our time stamp is up to data with the file: + if self.time_stamp < time_stamp: + + # If not, create an ImageInfo object for all image files + # contained in the .zip file: + for name in names: + root, ext = splitext( name ) + if ext in ImageFileExts: + cur_images.append( ImageInfo( + name = root, + image_name = join_image_name( volume_name, name ) ) ) + + else: + image_info_path = join( self.path, 'image_info.py' ) + if exists( image_info_path ): + # Load the manifest code and extract the images list: + old_images = get_python_value( read_file( image_info_path ), + 'images' ) + + # Check to see if our time stamp is up to data with the file: + if self.time_stamp < time_stamp: + + # If not, create an ImageInfo object for each image file + # contained in the path: + for name in listdir( self.path ): + root, ext = splitext( name ) + if ext in ImageFileExts: + cur_images.append( ImageInfo( + name = root, + image_name = join_image_name( volume_name, name ) ) ) + + # Merge the old and current images into a single up to date list: + if len( cur_images ) == 0: + images = old_images + else: + cur_image_set = dict( [ ( image.image_name, image ) + for image in cur_images ] ) + for old_image in old_images: + cur_image = cur_image_set.get( old_image.image_name ) + if cur_image is not None: + cur_image_set[ old_image.image_name ] = old_image + cur_image.volume = self + old_image.width = cur_image.width + old_image.height = cur_image.height + cur_image.volume = None + + images = list(cur_image_set.values()) + + # Set the new time stamp of the volume: + self.time_stamp = time_stamp + + # Return the resulting sorted list as the default value: + images.sort( key = lambda item: item.image_name ) + + # Make sure all images reference this volume: + for image in images: + image.volume = self + + return images + + def _check_cache ( self, file_name ): + """ Checks to see if the specified zip file name has been saved in the + image cache. If it has, it returns the fully-qualified cache file + name to use; otherwise it returns None. + """ + cache_file = join( image_cache_path, self.name, file_name ) + if (exists( cache_file ) and + (time_stamp_for( stat( cache_file )[ ST_MTIME ] ) > + self.time_stamp)): + return cache_file + + return None + +#------------------------------------------------------------------------------- +# 'ZipFileReference' class: +#------------------------------------------------------------------------------- + +class ZipFileReference ( ResourceReference ): + + #: The zip file to read; + zip_file = Instance( FastZipFile ) + + #: The volume name: + volume_name = Str + + #: The file within the zip file: + file_name = Str + + #: The name of the cached image file: + cache_file = File + + #-- The 'ResourceReference' API -------------------------------------------- + + #: The file name of the image (in this case, the cache file name): + filename = Property + + #-- ResourceReference Interface Implementation ----------------------------- + + def load ( self ): + """ Loads the resource. + """ + # Check if the cache file has already been created: + cache_file = self.cache_file + if cache_file == '': + # Extract the data from the zip file: + data = self.zip_file.read( self.file_name ) + + # Try to create an image from the data, without writing it to a + # file first: + image = self.resource_factory.image_from_data( data, Undefined ) + if image is not None: + return image + + # Make sure the correct image cache directory exists: + cache_dir = join( image_cache_path, self.volume_name ) + if not exists( cache_dir ): + makedirs( cache_dir ) + + # Write the image data to the cache file: + cache_file = join( cache_dir, self.file_name ) + with open(cache_file, 'wb') as fh: + fh.write( data ) + + # Save the cache file name in case we are called again: + self.cache_file = cache_file + + # Release our reference to the zip file object: + self.zip_file = None + + # Return the image data from the image cache file: + return self.resource_factory.image_from_file( cache_file ) + + #-- Property Implementations ----------------------------------------------- + + def _get_filename ( self ): + if self.cache_file == '': + self.load() + + return self.cache_file + +#------------------------------------------------------------------------------- +# 'ImageLibrary' class: +#------------------------------------------------------------------------------- + +class ImageLibrary ( HasPrivateTraits ): + """ Manages Traits UI image libraries. + """ + + #: The list of available image volumes in the library: + volumes = List( ImageVolume ) + + #: The volume dictionary (the keys are volume names, and the values are the + #: corresponding ImageVolume objects): + catalog = Dict( Str, ImageVolume ) + + #: The list of available images in the library: + images = Property( List, depends_on = 'volumes.images' ) + + #-- Private Traits --------------------------------------------------------- + + #: Mapping from a 'virtual' library name to a 'real' library name: + aliases = Dict + + #-- Public methods --------------------------------------------------------- + + def image_info ( self, image_name ): + """ Returns the ImageInfo object corresponding to a specified + **image_name**. + """ + volume = self.find_volume( image_name ) + if volume is not None: + return volume.catalog.get( image_name ) + + return None + + def image_resource ( self, image_name ): + """ Returns an ImageResource object for the specified image name. + """ + # If no volume was specified, use the standard volume: + if image_name.find( ':' ) < 0: + image_name = '@images:%s' % image_name[1:] + + # Find the correct volume, possible resolving any aliases used: + volume = self.find_volume( image_name ) + + # Find the image within the volume and return its ImageResource object: + if volume is not None: + return volume.image_resource( image_name ) + + # Otherwise, the volume was not found: + return None + + def find_volume ( self, image_name ): + """ Returns the ImageVolume object corresponding to the specified + **image_name** or None if the volume cannot be found. + """ + # Extract the volume name from the image name: + volume_name, file_name = split_image_name( image_name ) + + # Find the correct volume, possibly resolving any aliases used: + catalog = self.catalog + aliases = self.aliases + while volume_name not in catalog: + volume_name = aliases.get( volume_name ) + if volume_name is None: + return None + + return catalog[ volume_name ] + + def add_volume ( self, file_name = None ): + """ If **file_name** is a file, it adds an image volume specified by + **file_name** to the image library. If **file_name** is a + directory, it adds all image libraries contained in the directory + to the image library. If **file_name** is omitted, all image + libraries located in the *images* directory contained in the same + directory as the caller are added. + """ + # If no file name was specified, derive a path from the caller's + # source code location: + if file_name is None: + file_name = join( get_resource_path( 2 ), 'images' ) + + if isfile( file_name ): + # Load an image volume from the specified file: + volume = self._add_volume( file_name ) + if volume is None: + raise TraitError( "'%s' is not a valid image volume." % + file_name ) + + if volume.name in self.catalog: + self._duplicate_volume( volume.name ) + + self.catalog[ volume.name ] = volume + self.volumes.append( volume ) + + elif isdir( file_name ): + # Load all image volumes from the specified path: + catalog = self.catalog + volumes = self._add_path( file_name ) + for volume in volumes: + if volume.name in catalog: + self._duplicate_volume( volume.name ) + + catalog[ volume.name ] = volume + + self.volumes.extend( volumes ) + else: + # Handle an unrecognized argument: + raise TraitError( "The add method argument must be None or a file " + "or directory path, but '%s' was specified." % file_name ) + + def add_path ( self, volume_name, path = None ): + """ Adds the directory specified by **path** as a *virtual* volume + called **volume_name**. All image files contained within path + define the contents of the volume. If **path** is None, the + *images* contained in the 'images' subdirectory of the same + directory as the caller are is used as the path for the *virtual* + volume.. + """ + # Make sure we don't already have a volume with that name: + if volume_name in self.catalog: + raise TraitError( ("The volume name '%s' is already in the image " + "library.") % volume_name ) + + # If no path specified, derive one from the caller's source code + # location: + if path is None: + path = join( get_resource_path( 2 ), 'images' ) + + # Make sure that the specified path is a directory: + if not isdir( path ): + raise TraitError( "The image volume path '%s' does not exist." % + path ) + + # Create the ImageVolume to describe the path's contents: + image_volume_path = join( path, 'image_volume.py' ) + if exists( image_volume_path ): + volume = get_python_value( read_file( image_volume_path ), + 'volume' ) + else: + volume = ImageVolume() + + # Set up the rest of the volume information: + volume.trait_set( name = volume_name, + path = path, + is_zip_file = False ) + + # Try to bring the volume information up to date if necessary: + if volume.time_stamp < time_stamp_for( stat( path )[ ST_MTIME ] ): + # Note that the save could fail if the volume is read-only, but + # that's OK, because we're only trying to do the save in case + # a developer had added or deleted some image files, which would + # require write access to the volume: + volume.save() + + # Add the new volume to the library: + self.catalog[ volume_name ] = volume + self.volumes.append( volume ) + + def extract ( self, file_name, image_names ): + """ Builds a new image volume called **file_name** from the list of + image names specified by **image_names**. Each image name should be + of the form: '@volume:name'. + """ + # Get the volume name and file extension: + volume_name, ext = splitext( basename( file_name ) ) + + # If no extension specified, add the '.zip' file extension: + if ext == '': + file_name += '.zip' + + # Create the ImageVolume object to describe the new volume: + volume = ImageVolume( name = volume_name ) + + # Make sure the zip file does not already exists: + if exists( file_name ): + raise TraitError( "The '%s' file already exists." % file_name ) + + # Create the zip file: + zf = ZipFile( file_name, 'w', ZIP_DEFLATED ) + + # Add each of the specified images to it and the ImageVolume: + error = True + aliases = set() + keywords = set() + images = [] + info = {} + try: + for image_name in set( image_names ): + # Verify the image name is legal: + if (image_name[:1] != '@') or (image_name.find( ':' ) < 0): + raise TraitError( ("The image name specified by '%s' is " + "not of the form: @volume:name.") % image_name ) + + # Get the reference volume and image file names: + image_volume_name, image_file_name = \ + split_image_name( image_name ) + + # Get the volume for the image name: + image_volume = self.find_volume( image_name ) + if image_volume is None: + raise TraitError( ("Could not find the image volume " + "specified by '%s'.") % image_name ) + + # Get the image info: + image_info = image_volume.catalog.get( image_name ) + if image_info is None: + raise TraitError( ("Could not find the image specified by " + "'%s'.") % image_name ) + + # Add the image info to the list of images: + images.append( image_info ) + + # Add the image file to the zip file: + zf.writestr( image_file_name, + image_volume.image_data( image_name ) ) + + # Add the volume alias needed by the image (if any): + if image_volume_name != volume_name: + if image_volume_name not in aliases: + aliases.add( image_volume_name ) + + # Add the volume keywords as well: + for keyword in image_volume.keywords: + keywords.add( keyword ) + + # Add the volume info for the image: + volume_info = image_volume.volume_info( image_name ) + vinfo = info.get( image_volume_name ) + if vinfo is None: + info[ image_volume_name ] = vinfo = volume_info.clone() + + vinfo.image_names.append( image_name ) + + # Create the list of images for the volume: + images.sort( key = lambda item: item.image_name ) + volume.images = images + + # Create the list of aliases for the volume: + volume.aliases = list( aliases ) + + # Create the list of keywords for the volume: + volume.keywords = list( keywords ) + + # Create the final volume info list for the volume: + volume.info = list(info.values()) + + # Write the volume manifest source code to the zip file: + zf.writestr( 'image_volume.py', volume.image_volume_code ) + + # Write the image info source code to the zip file: + zf.writestr( 'image_info.py', volume.images_code ) + + # Write a separate licenses file for human consumption: + zf.writestr( 'license.txt', volume.license_text ) + + # Indicate no errors occurred: + error = False + finally: + zf.close() + if error: + remove( file_name ) + + #-- Default Value Implementations ------------------------------------------ + + def _volumes_default ( self ): + result = [] + + # Check for and add the 'application' image library: + app_library = join( dirname( abspath( sys.argv[0] ) ), 'library' ) + if isdir( app_library ): + result.extend( self._add_path( app_library ) ) + + # Get all volumes in the standard Traits UI image library directory: + result.extend( + self._add_path( join( get_resource_path( 1 ), 'library' ) ) ) + + # Check to see if there is an environment variable specifying a list + # of paths containing image libraries: + paths = environ.get( 'TRAITS_IMAGES' ) + if paths is not None: + # Determine the correct OS path separator to use: + separator = ';' + if system() != 'Windows': + separator = ':' + + # Add all image volumes found in each path in the environment + # variable: + for path in paths.split( separator ): + result.extend( self._add_path( path ) ) + + # Return the list of default volumes found: + return result + + def _catalog_default ( self ): + return dict( [ ( volume.name, volume ) for volume in self.volumes ] ) + + #-- Property Implementations ----------------------------------------------- + + @cached_property + def _get_images ( self ): + return self._get_images_list() + + #-- Private Methods -------------------------------------------------------- + + def _get_images_list ( self ): + """ Returns the list of all library images. + """ + # Merge the list of images from each volume: + images = [] + for volume in self.volumes: + images.extend( volume.images ) + + # Sort the result: + images.sort( key = lambda image: image.image_name ) + + # Return the images list: + return images + + def _add_path ( self, path ): + """ Returns a list of ImageVolume objects, one for each image library + located in the specified **path**. + """ + result = [] + + # Make sure the path is a directory: + if isdir( path ): + + # Find each zip file in the directory: + for base in listdir( path ): + if splitext( base )[1] == '.zip': + + # Try to create a volume from the zip file and add it to + # the result: + volume = self._add_volume( join( path, base ) ) + if volume is not None: + result.append( volume ) + + # Return the list of volumes found: + return result + + def _add_volume ( self, path ): + """ Returns an ImageVolume object for the image library specified by + **path**. If **path** does not specify a valid ImageVolume, None is + returned. + """ + path = abspath( path ) + + # Make sure the path is a valid zip file: + if is_zipfile( path ): + + # Create a fast zip file for reading: + zf = FastZipFile( path = path ) + + # Extract the volume name from the path: + volume_name = splitext( basename( path ) )[0] + + # Get the names of all top-level entries in the zip file: + names = zf.namelist() + + # Check to see if there is a manifest file: + if 'image_volume.py' in names: + # Load the manifest code and extract the volume object: + volume = get_python_value( zf.read( 'image_volume.py' ), + 'volume' ) + + # Set the volume name: + volume.name = volume_name + + # Try to add all of the external volume references as + # aliases for this volume: + self._add_aliases( volume ) + + # Set the path to this volume: + volume.path = path + + # Save the reference to the zip file object we are using: + volume.zip_file = zf + + else: + # Create a new volume from the zip file: + volume = ImageVolume( name = volume_name, + path = path, + zip_file = zf ) + + # If this volume is not up to date, update it: + if volume.time_stamp < time_stamp_for( stat( path )[ ST_MTIME ] ): + # Note that the save could fail if the volume is read-only, but + # that's OK, because we're only trying to do the save in case + # a developer had added or deleted some image files, which would + # require write access to the volume: + volume.save() + + # Return the volume: + return volume + + # Indicate no volume was found: + return None + + def _add_aliases ( self, volume ): + """ Try to add all of the external volume references as aliases for + this volume. + """ + aliases = self.aliases + volume_name = volume.name + for vname in volume.aliases: + if ((vname in aliases) and + (volume_name != aliases[ vname ])): + raise TraitError( ("Image library error: " + "Attempt to alias '%s' to '%s' when it is " + "already aliased to '%s'") % + ( vname, volume_name, aliases[ volume_name ] ) ) + aliases[ vname ] = volume_name + + def _duplicate_volume ( self, volume_name ): + """ Raises a duplicate volume name error. + """ + raise TraitError( ("Attempted to add an image volume called '%s' when " + "a volume with that name is already defined.") % volume_name ) + +# Create the singleton image object: +ImageLibrary = ImageLibrary() diff -Nru python-pyface-4.5.2/pyface/image/__init__.py python-pyface-6.1.2/pyface/image/__init__.py --- python-pyface-4.5.2/pyface/image/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/image/__init__.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,2 @@ +# Copyright (c) 2007 by Enthought, Inc. +# All rights reserved. Binary files /tmp/tmpeOISu5/RSokF2bCTe/python-pyface-4.5.2/pyface/image/library/icons.zip and /tmp/tmpeOISu5/LYlXeN4e5T/python-pyface-6.1.2/pyface/image/library/icons.zip differ diff -Nru python-pyface-4.5.2/pyface/image/library/image_LICENSE.txt python-pyface-6.1.2/pyface/image/library/image_LICENSE.txt --- python-pyface-4.5.2/pyface/image/library/image_LICENSE.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/image/library/image_LICENSE.txt 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,14 @@ +The icons are mostly derived work from other icons. As such they are +licensed accordingly to the original license: + +Project License File +---------------------------------------------------------------------------- +Enthought BSD 3-Clause LICENSE.txt + +Unless stated in this file, icons are the work of Enthought, and are +released under a 3 clause BSD license. + +Files and orginal authors: +---------------------------------------------------------------------------- +pyface/image/library: + std.zip | Enthought Binary files /tmp/tmpeOISu5/RSokF2bCTe/python-pyface-4.5.2/pyface/image/library/std.zip and /tmp/tmpeOISu5/LYlXeN4e5T/python-pyface-6.1.2/pyface/image/library/std.zip differ diff -Nru python-pyface-4.5.2/pyface/image_button.py python-pyface-6.1.2/pyface/image_button.py --- python-pyface-4.5.2/pyface/image_button.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/image_button.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,265 +1,17 @@ -#------------------------------------------------------------------------------ +# Copyright (c) 2017, Enthought, Inc. +# All rights reserved. # -# Copyright (c) 2005, Enthought, Inc. -# All rights reserved. -# -# This software is provided without warranty under the terms of the BSD -# license included in enthought/LICENSE.txt and may be redistributed only -# under the conditions described in the aforementioned license. The license -# is also available online at http://www.enthought.com/licenses/BSD.txt -# Thanks for using Enthought open source! -# -# Author: David C. Morrill -# -# Description: Image and text-based pyface button/toolbar/radio button control. -# -#------------------------------------------------------------------------------ -""" An image and text-based control that can be used as a normal, radio or - toolbar button. -""" -from __future__ import absolute_import - -import wx -from numpy import array, fromstring, reshape, ravel, dtype - -from traits.api import Str, Range, Enum, Instance, Event, false - -from .widget import Widget -from .image_resource import ImageResource - -#------------------------------------------------------------------------------- -# Constants: -#------------------------------------------------------------------------------- - -# Text color used when a button is disabled: -DisabledTextColor = wx.Colour( 128, 128, 128 ) - -#------------------------------------------------------------------------------- -# 'ImageButton' class: -#------------------------------------------------------------------------------- - -class ImageButton ( Widget ): - """ An image and text-based control that can be used as a normal, radio or - toolbar button. - """ - - # Pens used to draw the 'selection' marker: - _selectedPenDark = wx.Pen( - wx.SystemSettings_GetColour( wx.SYS_COLOUR_3DSHADOW ), 1, wx.SOLID - ) - - _selectedPenLight = wx.Pen( - wx.SystemSettings_GetColour( wx.SYS_COLOUR_3DHIGHLIGHT ), 1, wx.SOLID - ) - - #--------------------------------------------------------------------------- - # Trait definitions: - #--------------------------------------------------------------------------- - - # The image: - image = Instance( ImageResource, allow_none = True ) - - # The (optional) label: - label = Str - - # Extra padding to add to both the left and right sides: - width_padding = Range( 0, 31, 7 ) - - # Extra padding to add to both the top and bottom sides: - height_padding = Range( 0, 31, 5 ) - - # Presentation style: - style = Enum( 'button', 'radio', 'toolbar', 'checkbox' ) - - # Orientation of the text relative to the image: - orientation = Enum( 'vertical', 'horizontal' ) - - # Is the control selected ('radio' or 'checkbox' style)? - selected = false - - # Fired when a 'button' or 'toolbar' style control is clicked: - clicked = Event - - #--------------------------------------------------------------------------- - # Initializes the object: - #--------------------------------------------------------------------------- - - def __init__ ( self, parent, **traits ): - """ Creates a new image control. - """ - self._image = None - - super( ImageButton, self ).__init__( **traits ) - - # Calculate the size of the button: - idx = idy = tdx = tdy = 0 - if self._image is not None: - idx = self._image.GetWidth() - idy = self._image.GetHeight() - - if self.label != '': - dc = wx.ScreenDC() - dc.SetFont( wx.NORMAL_FONT ) - tdx, tdy = dc.GetTextExtent( self.label ) - - wp2 = self.width_padding + 2 - hp2 = self.height_padding + 2 - if self.orientation == 'horizontal': - self._ix = wp2 - spacing = (idx > 0) * (tdx > 0) * 4 - self._tx = self._ix + idx + spacing - dx = idx + tdx + spacing - dy = max( idy, tdy ) - self._iy = hp2 + ((dy - idy) / 2) - self._ty = hp2 + ((dy - tdy) / 2) - else: - self._iy = hp2 - spacing = (idy > 0) * (tdy > 0) * 2 - self._ty = self._iy + idy + spacing - dx = max( idx, tdx ) - dy = idy + tdy + spacing - self._ix = wp2 + ((dx - idx) / 2) - self._tx = wp2 + ((dx - tdx) / 2) - - # Create the toolkit-specific control: - self._dx = dx + wp2 + wp2 - self._dy = dy + hp2 + hp2 - self.control = wx.Window( parent, -1, - size = wx.Size( self._dx, self._dy ) ) - self.control._owner = self - self._mouse_over = self._button_down = False - - # Set up mouse event handlers: - wx.EVT_ENTER_WINDOW( self.control, self._on_enter_window ) - wx.EVT_LEAVE_WINDOW( self.control, self._on_leave_window ) - wx.EVT_LEFT_DOWN( self.control, self._on_left_down ) - wx.EVT_LEFT_UP( self.control, self._on_left_up ) - wx.EVT_PAINT( self.control, self._on_paint ) - - #--------------------------------------------------------------------------- - # Handles the 'image' trait being changed: - #--------------------------------------------------------------------------- - - def _image_changed ( self, image ): - self._image = self._mono_image = None - if image is not None: - self._img = image.create_image() - self._image = self._img.ConvertToBitmap() - - if self.control is not None: - self.control.Refresh() - - #--------------------------------------------------------------------------- - # Handles the 'selected' trait being changed: - #--------------------------------------------------------------------------- - - def _selected_changed ( self, selected ): - """ Handles the 'selected' trait being changed. - """ - if selected and (self.style == 'radio'): - for control in self.control.GetParent().GetChildren(): - owner = getattr( control, '_owner', None ) - if (isinstance( owner, ImageButton ) and owner.selected and - (owner is not self)): - owner.selected = False - break - - self.control.Refresh() - -#-- wx event handlers ---------------------------------------------------------- - - def _on_enter_window ( self, event ): - """ Called when the mouse enters the widget. """ - - if self.style != 'button': - self._mouse_over = True - self.control.Refresh() - - def _on_leave_window ( self, event ): - """ Called when the mouse leaves the widget. """ - - if self._mouse_over: - self._mouse_over = False - self.control.Refresh() - - def _on_left_down ( self, event ): - """ Called when the left mouse button goes down on the widget. """ - self._button_down = True - self.control.CaptureMouse() - self.control.Refresh() - - def _on_left_up ( self, event ): - """ Called when the left mouse button goes up on the widget. """ - control = self.control - control.ReleaseMouse() - self._button_down = False - wdx, wdy = control.GetClientSizeTuple() - x, y = event.GetX(), event.GetY() - control.Refresh() - if (0 <= x < wdx) and (0 <= y < wdy): - if self.style == 'radio': - self.selected = True - elif self.style == 'checkbox': - self.selected = not self.selected - else: - self.clicked = True - - def _on_paint ( self, event ): - """ Called when the widget needs repainting. - """ - wdc = wx.PaintDC( self.control ) - wdx, wdy = self.control.GetClientSizeTuple() - ox = (wdx - self._dx) / 2 - oy = (wdy - self._dy) / 2 - - disabled = (not self.control.IsEnabled()) - if self._image is not None: - image = self._image - if disabled: - if self._mono_image is None: - img = self._img - data = reshape(fromstring(img.GetData(), dtype('uint8')), - (-1, 3)) * array([[ 0.297, 0.589, 0.114 ]]) - g = data[ :, 0 ] + data[ :, 1 ] + data[ :, 2 ] - data[ :, 0 ] = data[ :, 1 ] = data[ :, 2 ] = g - img.SetData(ravel(data.astype(dtype('uint8'))).tostring()) - img.SetMaskColour(0, 0, 0) - self._mono_image = img.ConvertToBitmap() - self._img = None - image = self._mono_image - wdc.DrawBitmap( image, ox + self._ix, oy + self._iy, True ) - - if self.label != '': - if disabled: - wdc.SetTextForeground( DisabledTextColor ) - wdc.SetFont( wx.NORMAL_FONT ) - wdc.DrawText( self.label, ox + self._tx, oy + self._ty ) - - pens = [ self._selectedPenLight, self._selectedPenDark ] - bd = self._button_down - style = self.style - is_rc = (style in ( 'radio', 'checkbox' )) - if bd or (style == 'button') or (is_rc and self.selected): - if is_rc: - bd = 1 - bd - wdc.SetBrush( wx.TRANSPARENT_BRUSH ) - wdc.SetPen( pens[ bd ] ) - wdc.DrawLine( 1, 1, wdx - 1, 1 ) - wdc.DrawLine( 1, 1, 1, wdy - 1 ) - wdc.DrawLine( 2, 2, wdx - 2, 2 ) - wdc.DrawLine( 2, 2, 2, wdy - 2 ) - wdc.SetPen( pens[ 1 - bd ] ) - wdc.DrawLine( wdx - 2, 2, wdx - 2, wdy - 1 ) - wdc.DrawLine( 2, wdy - 2, wdx - 2, wdy - 2 ) - wdc.DrawLine( wdx - 3, 3, wdx - 3, wdy - 2 ) - wdc.DrawLine( 3, wdy - 3, wdx - 3, wdy - 3 ) - - elif self._mouse_over and (not self.selected): - wdc.SetBrush( wx.TRANSPARENT_BRUSH ) - wdc.SetPen( pens[ bd ] ) - wdc.DrawLine( 0, 0, wdx, 0 ) - wdc.DrawLine( 0, 1, 0, wdy ) - wdc.SetPen( pens[ 1 - bd ] ) - wdc.DrawLine( wdx - 1, 1, wdx - 1, wdy ) - wdc.DrawLine( 1, wdy - 1, wdx - 1, wdy - 1 ) +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + +import logging + +logger = logging.getLogger(__name__) +logger.warning( + 'DEPRECATED: pyface.image_button, use pyface.ui.wx.image_button instead. ' + 'Will be removed in Pyface 7.') +from pyface.ui.wx.image_button import * diff -Nru python-pyface-4.5.2/pyface/image_cache.py python-pyface-6.1.2/pyface/image_cache.py --- python-pyface-4.5.2/pyface/image_cache.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/image_cache.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,9 +13,10 @@ #------------------------------------------------------------------------------ """ The implementation of an image cache. """ +from __future__ import absolute_import # Import the toolkit specific version. -from toolkit import toolkit_object +from .toolkit import toolkit_object ImageCache = toolkit_object('image_cache:ImageCache') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/image_list.py python-pyface-6.1.2/pyface/image_list.py --- python-pyface-4.5.2/pyface/image_list.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/image_list.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,98 +6,12 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -""" A cached image list. """ -from __future__ import absolute_import - -# Major package imports. -import wx - -# Local imports -from .image_resource import ImageResource - - -# fixme: rename to 'CachedImageList'?!? -class ImageList(wx.ImageList): - """ A cached image list. """ - - def __init__(self, width, height): - """ Creates a new cached image list. """ - - # Base-class constructor. - wx.ImageList.__init__(self, width, height) - - self._width = width - self._height = height - - # Cache of the indexes of the images in the list! - self._cache = {} # {filename : index} - - return - - ########################################################################### - # 'ImageList' interface. - ########################################################################### - - def GetIndex(self, filename): - """ Returns the index of the specified image. - - The image will be loaded and added to the image list if it is not - already there. - - """ - - # Try the cache first. - index = self._cache.get(filename) - if index is None: - # Were we passed an image resource? - if isinstance(filename, ImageResource): - # Create an image. - image = filename.create_image(size=(self._width, self._height)) - - # If the filename is a string then it is the filename of some kind - # of image (e.g 'foo.gif', 'image/foo.png' etc). - elif isinstance(filename, basestring): - # Load the image from the file. - image = wx.Image(filename, wx.BITMAP_TYPE_ANY) - - # Otherwise the filename is *actually* an icon (in our case, - # probably related to a MIME type). - else: - # Create a bitmap from the icon. - bmp = wx.EmptyBitmap(self._width, self._height) - bmp.CopyFromIcon(filename) - - # Turn it into an image so that we can scale it. - image = wx.ImageFromBitmap(bmp) - - # We force all images in the cache to be the same size. - self._scale(image) - - # We also force them to be bitmaps! - bmp = image.ConvertToBitmap() - - # Add the bitmap to the actual list... - index = self.Add(bmp) - - # ... and update the cache. - self._cache[filename] = index - - return index - - ########################################################################### - # Private interface. - ########################################################################### - - def _scale(self, image): - """ Scales the specified image (if necessary). """ - if image.GetWidth() != self._width or image.GetHeight()!= self._height: - image.Rescale(self._width, self._height) +import logging - return image +logger = logging.getLogger(__name__) +logger.warning( + 'DEPRECATED: pyface.image_list, use pyface.ui.wx.image_list instead. ' + 'Will be removed in Pyface 7.') -#### EOF ###################################################################### +from pyface.ui.wx.image_list import * diff -Nru python-pyface-4.5.2/pyface/image_resource.py python-pyface-6.1.2/pyface/image_resource.py --- python-pyface-4.5.2/pyface/image_resource.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/image_resource.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,7 +15,9 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object ImageResource = toolkit_object('image_resource:ImageResource') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/image_widget.py python-pyface-6.1.2/pyface/image_widget.py --- python-pyface-4.5.2/pyface/image_widget.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/image_widget.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,235 +6,11 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -""" A clickable/draggable widget containing an image. """ -from __future__ import absolute_import - -# Major package imports. -import wx - -# Enthought library imports. -from traits.api import Any, Bool, Event - -# Locak imports. -from .widget import Widget - - -class ImageWidget(Widget): - """ A clickable/draggable widget containing an image. """ - - #### 'ImageWidget' interface ############################################## - - # The bitmap. - bitmap = Any - - # Is the widget selected? - selected = Bool(False) - - #### Events #### - - # A key was pressed while the tree is in focus. - key_pressed = Event - - # A node has been activated (ie. double-clicked). - node_activated = Event - - # A drag operation was started on a node. - node_begin_drag = Event - - # A (non-leaf) node has been collapsed. - node_collapsed = Event - - # A (non-leaf) node has been expanded. - node_expanded = Event - - # A left-click occurred on a node. - node_left_clicked = Event - - # A right-click occurred on a node. - node_right_clicked = Event - - #### Private interface #################################################### - - _selected = Any - - ########################################################################### - # 'object' interface. - ########################################################################### - - def __init__ (self, parent, **traits): - """ Creates a new widget. """ - - # Base class constructors. - super(ImageWidget, self).__init__(**traits) - - # Add some padding around the image. - size = (self.bitmap.GetWidth() + 10, self.bitmap.GetHeight() + 10) - - # Create the toolkit-specific control. - self.control = wx.Window(parent, -1, size=size) - self.control.__tag__ = 'hack' - - self._mouse_over = False - self._button_down = False - - # Set up mouse event handlers: - wx.EVT_ENTER_WINDOW(self.control, self._on_enter_window) - wx.EVT_LEAVE_WINDOW(self.control, self._on_leave_window) - wx.EVT_LEFT_DCLICK(self.control, self._on_left_dclick) - wx.EVT_LEFT_DOWN(self.control, self._on_left_down) - wx.EVT_LEFT_UP(self.control, self._on_left_up) - wx.EVT_PAINT(self.control, self._on_paint) - - # Pens used to draw the 'selection' marker: - # ZZZ: Make these class instances when moved to the wx toolkit code. - self._selectedPenDark = wx.Pen( - wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DSHADOW), 1, wx.SOLID - ) - - self._selectedPenLight = wx.Pen( - wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DHIGHLIGHT), 1, wx.SOLID - ) - - return - - ########################################################################### - # Private interface. - ########################################################################### - - #### Trait event handlers ################################################# - - def _bitmap_changed(self, bitmap): - """ Called when the widget's bitmap is changed. """ - - if self.control is not None: - self.control.Refresh() - return +# Note: The ImageWidget is currently wx-specific - def _selected_changed(self, selected): - """ Called when the selected state of the widget is changed. """ - - if selected: - for control in self.GetParent().GetChildren(): - if hasattr(control, '__tag__'): - if control.Selected(): - control.Selected(False) - break - - self.Refresh() - - return - - #### wx event handlers #################################################### - - def _on_enter_window(self, event): - """ Called when the mouse enters the widget. """ - - if self._selected is not None: - self._mouse_over = True - self.Refresh() - - return - - def _on_leave_window(self, event): - """ Called when the mouse leaves the widget. """ - - if self._mouse_over: - self._mouse_over = False - self.Refresh() - - return - - def _on_left_dclick(self, event): - """ Called when the left mouse button is double-clicked. """ - - #print 'left dclick' - - event.Skip() - - return - - def _on_left_down ( self, event = None ): - """ Called when the left mouse button goes down on the widget. """ - - #print 'left down' - - if self._selected is not None: - self.CaptureMouse() - self._button_down = True - self.Refresh() - - event.Skip() - - return - - def _on_left_up ( self, event = None ): - """ Called when the left mouse button goes up on the widget. """ - - #print 'left up' - - need_refresh = self._button_down - if need_refresh: - self.ReleaseMouse() - self._button_down = False - - if self._selected is not None: - wdx, wdy = self.GetClientSizeTuple() - x = event.GetX() - y = event.GetY() - if (0 <= x < wdx) and (0 <= y < wdy): - if self._selected != -1: - self.Selected( True ) - elif need_refresh: - self.Refresh() - - return - - if need_refresh: - self.Refresh() - - event.Skip() - - return - - def _on_paint ( self, event = None ): - """ Called when the widget needs repainting. """ - - wdc = wx.PaintDC( self.control ) - wdx, wdy = self.control.GetClientSizeTuple() - bitmap = self.bitmap - bdx = bitmap.GetWidth() - bdy = bitmap.GetHeight() - wdc.DrawBitmap( bitmap, (wdx - bdx) / 2, (wdy - bdy) / 2, True ) - - pens = [ self._selectedPenLight, self._selectedPenDark ] - bd = self._button_down - if self._mouse_over: - wdc.SetBrush( wx.TRANSPARENT_BRUSH ) - wdc.SetPen( pens[ bd ] ) - wdc.DrawLine( 0, 0, wdx, 0 ) - wdc.DrawLine( 0, 1, 0, wdy ) - wdc.SetPen( pens[ 1 - bd ] ) - wdc.DrawLine( wdx - 1, 1, wdx - 1, wdy ) - wdc.DrawLine( 1, wdy - 1, wdx - 1, wdy - 1 ) - - if self._selected == True: - wdc.SetBrush( wx.TRANSPARENT_BRUSH ) - wdc.SetPen( pens[ bd ] ) - wdc.DrawLine( 1, 1, wdx - 1, 1 ) - wdc.DrawLine( 1, 1, 1, wdy - 1 ) - wdc.DrawLine( 2, 2, wdx - 2, 2 ) - wdc.DrawLine( 2, 2, 2, wdy - 2 ) - wdc.SetPen( pens[ 1 - bd ] ) - wdc.DrawLine( wdx - 2, 2, wdx - 2, wdy - 1 ) - wdc.DrawLine( 2, wdy - 2, wdx - 2, wdy - 2 ) - wdc.DrawLine( wdx - 3, 3, wdx - 3, wdy - 2 ) - wdc.DrawLine( 3, wdy - 3, wdx - 3, wdy - 3 ) - - return +# Import the toolkit specific version. +from __future__ import absolute_import -#### EOF ###################################################################### +from .toolkit import toolkit_object +ImageWidget = toolkit_object('image_widget:ImageWidget') diff -Nru python-pyface-4.5.2/pyface/i_message_dialog.py python-pyface-6.1.2/pyface/i_message_dialog.py --- python-pyface-4.5.2/pyface/i_message_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_message_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -18,7 +18,7 @@ from traits.api import Enum, Unicode # Local imports. -from i_dialog import IDialog +from pyface.i_dialog import IDialog class IMessageDialog(IDialog): @@ -26,16 +26,16 @@ #### 'IMessageDialog' interface ########################################### - # The message to display in the dialog. + #: The message to display in the dialog. message = Unicode - # More information about the message to be displayed. + #: More information about the message to be displayed. informative = Unicode - # More detail about the message to be displayed in the dialog. + #: More detail about the message to be displayed in the dialog. detail = Unicode - # The severity of the message. + #: The severity of the message. severity = Enum('information', 'warning', 'error') @@ -43,5 +43,3 @@ """ The mixin class that contains common code for toolkit specific implementations of the IMessageDialog interface. """ - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/__init__.py python-pyface-6.1.2/pyface/__init__.py --- python-pyface-4.5.2/pyface/__init__.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/__init__.py 2019-05-03 08:18:49.000000000 +0000 @@ -20,6 +20,11 @@ except ImportError: __version__ = 'not-built' -__requires__ = [ - 'pygments', 'traits', -] + +__requires__ = ['traits'] +__extras_require__ = { + 'wx': ['wxpython>=2.8.10', 'numpy'], + 'pyqt': ['pyqt>=4.10', 'pygments'], + 'pyqt5': ['pyqt>=5', 'pygments'], + 'pyside': ['pyside>=1.2', 'pygments'], +} diff -Nru python-pyface-4.5.2/pyface/i_progress_dialog.py python-pyface-6.1.2/pyface/i_progress_dialog.py --- python-pyface-4.5.2/pyface/i_progress_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_progress_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -17,7 +17,7 @@ from traits.api import Any, Bool, Int, Str # Local imports. -from i_dialog import IDialog +from pyface.i_dialog import IDialog class IProgressDialog(IDialog): @@ -25,17 +25,29 @@ """ #### 'IProgressDialog' interface ################################## - title = Str + + #: The message to display in the dialog message = Str + + #: The minimum progress value min = Int + + #: The maximum progress value max = Int + + #: The margin around the progress bar margin = Int(5) + + #: Whether the operation can be cancelled can_cancel = Bool(False) + + #: Whether to show progress times show_time = Bool(False) - show_percent = Bool(False) + #: Whether to show progress percent + show_percent = Bool(False) - # Label for the 'cancel' button + #: Label for the 'cancel' button cancel_button_label = Str ########################################################################### @@ -43,10 +55,24 @@ ########################################################################### def update(self, value): + """ Update the progress bar to the desired value + + If the value is >= the maximum and the progress bar is not contained + in another panel the parent window will be closed. + + Parameters + ---------- + value : + The progress value to set. """ - updates the progress bar to the desired value. If the value is >= - the maximum and the progress bar is not contained in another panel - the parent window will be closed + + def change_message(self, message): + """ Change the displayed message in the progress dialog + + Parameters + ---------- + message : str or unicode + The new message to display. """ @@ -58,18 +84,36 @@ Implements: update() """ + #: The progress bar toolkit object + # XXX why not the control? progress_bar = Any ########################################################################### + # 'IWindow' interface. + ########################################################################### + + def open(self): + """ Open the dialog """ + if self.max < self.min: + msg = "Dialog min ({}) is greater than dialog max ({})." + raise AttributeError(msg.format(self.min, self.max)) + + super(MProgressDialog, self).open() + + ########################################################################### # 'IProgressDialog' interface. ########################################################################### def update(self, value): - """ - updates the progress bar to the desired value. If the value is >= - the maximum and the progress bar is not contained in another panel - the parent window will be closed + """ Update the progress bar to the desired value + If the value is >= the maximum and the progress bar is not contained + in another panel the parent window will be closed. + + Parameters + ---------- + value : + The progress value to set. """ if self.progress_bar is not None: @@ -77,3 +121,14 @@ if value >= self.max: self.close() + + def change_message(self, message): + """ Change the displayed message in the progress dialog + + Parameters + ---------- + message : str or unicode + The new message to display. + + """ + self.message = message diff -Nru python-pyface-4.5.2/pyface/i_python_editor.py python-pyface-6.1.2/pyface/i_python_editor.py --- python-pyface-4.5.2/pyface/i_python_editor.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_python_editor.py 2019-05-03 08:18:49.000000000 +0000 @@ -18,7 +18,7 @@ from traits.api import Bool, Event, Interface, Unicode # Local imports. -from key_pressed_event import KeyPressedEvent +from pyface.key_pressed_event import KeyPressedEvent class IPythonEditor(Interface): @@ -26,21 +26,21 @@ #### 'IPythonEditor' interface ############################################ - # Has the file in the editor been modified? + #: Has the file in the editor been modified? dirty = Bool(False) - # The pathname of the file being edited. + #: The pathname of the file being edited. path = Unicode - # Should line numbers be shown in the margin? + #: Should line numbers be shown in the margin? show_line_numbers = Bool(True) #### Events #### - # The contents of the editor has changed. + #: The contents of the editor has changed. changed = Event - # A key has been pressed. + #: A key has been pressed. key_pressed = Event(KeyPressedEvent) ########################################################################### @@ -48,10 +48,22 @@ ########################################################################### def load(self, path=None): - """ Loads the contents of the editor. """ + """ Loads the contents of the editor. + + Parameters + ---------- + path : str or None + The path to the file to load. + """ def save(self, path=None): - """ Saves the contents of the editor. """ + """ Saves the contents of the editor. + + Parameters + ---------- + path : str or None + The path to the file to save. + """ # FIXME v3: This is very dependent on the underlying implementation. def set_style(self, n, fore, back): @@ -60,7 +72,13 @@ """ def select_line(self, lineno): - """ Selects the specified line. """ + """ Selects the specified line. + + Parameters + ---------- + lineno : int + The line number to select. + """ class MPythonEditor(object): @@ -75,7 +93,3 @@ if self.control is not None: self.load() - - return - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/i_python_shell.py python-pyface-6.1.2/pyface/i_python_shell.py --- python-pyface-4.5.2/pyface/i_python_shell.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_python_shell.py 2019-05-03 08:18:49.000000000 +0000 @@ -17,8 +17,8 @@ from traits.api import Event # Local imports. -from key_pressed_event import KeyPressedEvent -from i_widget import IWidget +from pyface.key_pressed_event import KeyPressedEvent +from pyface.i_widget import IWidget class IPythonShell(IWidget): @@ -26,10 +26,10 @@ #### 'IPythonShell' interface ############################################# - # A command has been executed. + #: A command has been executed. command_executed = Event - # A key has been pressed. + #: A key has been pressed. key_pressed = Event(KeyPressedEvent) ########################################################################### @@ -37,23 +37,69 @@ ########################################################################### def interpreter(self): - """ Returns the code.InteractiveInterpreter instance. """ + """ Get the shell's interpreter + + Returns + ------- + interpreter : InteractiveInterpreter instance + Returns the InteractiveInterpreter instance. + """ def bind(self, name, value): - """ Binds a name to a value in the interpreter's namespace. """ + """ Binds a name to a value in the interpreter's namespace. + + Parameters + ---------- + name : str + The python idetifier to bind the value to. + value : any + The python object to be bound into the interpreter's namespace. + """ def execute_command(self, command, hidden=True): """ Execute a command in the interpreter. - If 'hidden' is True then nothing is shown in the shell - not even - a blank line. + Parameters + ---------- + command : str + A Python command to execute. + hidden : bool + If 'hidden' is True then nothing is shown in the shell - not even + a blank line. """ def execute_file(self, path, hidden=True): """ Execute a file in the interpeter. - If 'hidden' is True then nothing is shown in the shell - not even - a blank line. + Parameters + ---------- + path : str + The path to the Python file to execute. + hidden : bool + If 'hidden' is True then nothing is shown in the shell - not even + a blank line. + """ + + def get_history(self): + """ Return the current command history and index. + + Returns + ------- + history : list of str + The list of commands in the new history. + history_index : int from 0 to len(history) + The current item in the command history navigation. + """ + + def set_history(self, history, history_index): + """ Replace the current command history and index with new ones. + + Parameters + ---------- + history : list of str + The list of commands in the new history. + history_index : int + The current item in the command history navigation. """ @@ -69,8 +115,15 @@ ########################################################################### def bind(self, name, value): - """ Binds a name to a value in the interpreter's namespace. """ + """ Binds a name to a value in the interpreter's namespace. + Parameters + ---------- + name : str + The python idetifier to bind the value to. + value : any + The python object to be bound into the interpreter's namespace. + """ self.interpreter().locals[name] = value ########################################################################### @@ -81,5 +134,3 @@ """ Called when a command has been executed in the shell. """ self.command_executed = self - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ipython_widget.py python-pyface-6.1.2/pyface/ipython_widget.py --- python-pyface-4.5.2/pyface/ipython_widget.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ipython_widget.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,16 +13,17 @@ #------------------------------------------------------------------------------ """ The implementation of an IPython shell. """ +from __future__ import absolute_import # Import the toolkit specific version. try: import IPython.frontend except ImportError: - raise ImportError, ''' + raise ImportError(''' ________________________________________________________________________________ Could not load the Wx frontend for ipython. -You need to have ipython >= 0.9 installed to use the ipython widget.''' +You need to have ipython >= 0.9 installed to use the ipython widget.''') -from toolkit import toolkit_object +from .toolkit import toolkit_object IPythonWidget= toolkit_object('ipython_widget:IPythonWidget') diff -Nru python-pyface-4.5.2/pyface/i_single_choice_dialog.py python-pyface-6.1.2/pyface/i_single_choice_dialog.py --- python-pyface-4.5.2/pyface/i_single_choice_dialog.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_single_choice_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,61 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2016, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" The interface for a dialog that prompts for a choice from a list. """ + + +# Enthought library imports. +from traits.api import Any, List, Str + +# Local imports. +from pyface.i_dialog import IDialog + + +class ISingleChoiceDialog(IDialog): + """ The interface for a dialog that prompts for a choice from a list. """ + + #### 'ISingleChoiceDialog' interface ###################################### + + #: List of objects to choose from. + choices = List(Any) + + #: The object chosen, if any. + choice = Any + + #: An optional attribute to use for the name of each object in the dialog. + name_attribute = Str + + #: The message to display to the user. + message = Str + + +class MSingleChoiceDialog(object): + """ The mixin class that contains common code for toolkit specific + implementations of the IConfirmationDialog interface. + """ + + def _choice_strings(self): + """ Returns the list of strings to display in the dialog. """ + choices = self.choices + if self.name_attribute != '': + # choices is a list of objects with this attribute + choices = [getattr(obj, self.name_attribute) for obj in choices] + + choices = [str(obj) for obj in choices] + + if len(choices) == 0: + raise ValueError("SingleChoiceDialog requires at least 1 choice.") + elif len(choices) != len(set(choices)): + raise ValueError("Dialog choices {} contain repeated string value." + % choices) + return choices diff -Nru python-pyface-4.5.2/pyface/i_splash_screen.py python-pyface-6.1.2/pyface/i_splash_screen.py --- python-pyface-4.5.2/pyface/i_splash_screen.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_splash_screen.py 2019-05-03 08:18:49.000000000 +0000 @@ -21,9 +21,9 @@ from traits.api import Any, Bool, Instance, Int, Tuple, Unicode # Local imports. -from image_resource import ImageResource -from splash_screen_log_handler import SplashScreenLogHandler -from i_window import IWindow +from pyface.image_resource import ImageResource +from pyface.splash_screen_log_handler import SplashScreenLogHandler +from pyface.i_window import IWindow class ISplashScreen(IWindow): @@ -31,33 +31,33 @@ #### 'ISplashScreen' interface ############################################ - # The image to display on the splash screen. + #: The image to display on the splash screen. image = Instance(ImageResource, ImageResource('splash')) - # If log messages are to be displayed then this is the logging level. See - # the Python documentation for the 'logging' module for more details. + #: If log messages are to be displayed then this is the logging level. See + #: the Python documentation for the 'logging' module for more details. log_level = Int(logging.DEBUG) - # Should the splash screen display log messages in the splash text? + #: Should the splash screen display log messages in the splash text? show_log_messages = Bool(True) - # Optional text to display on top of the splash image. + #: Optional text to display on top of the splash image. text = Unicode - # The text color. + #: The text color. # FIXME v3: When TraitsUI supports PyQt then change this to 'Color', # (unless that needs the toolkit to be selected too soon, in which case it # may need to stay as Any - or Str?) #text_color = WxColor('black') text_color = Any - # The text font. + #: The text font. # FIXME v3: When TraitsUI supports PyQt then change this back to # 'Font(None)' with the actual default being toolkit specific. #text_font = Font(None) text_font = Any - # The x, y location where the text will be drawn. + #: The x, y location where the text will be drawn. # FIXME v3: Remove this. text_location = Tuple(5, 5) @@ -95,5 +95,3 @@ logger.removeHandler(self._log_handler) super(MSplashScreen, self).close() - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/i_split_widget.py python-pyface-6.1.2/pyface/i_split_widget.py --- python-pyface-4.5.2/pyface/i_split_widget.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_split_widget.py 2019-05-03 08:18:49.000000000 +0000 @@ -27,20 +27,20 @@ #### 'ISplitWidget' interface ############################################# - # The direction in which the widget is split. + #: The direction in which the widget is split. # - # Splitting vertically means there will be a left hand panel and a right - # hand panel, splitting horizontally means there will be a top panel and - # a bottom panel. + #: Splitting vertically means there will be a left hand panel and a right + #: hand panel, splitting horizontally means there will be a top panel and + #: a bottom panel. direction = Enum('vertical', 'vertical', 'horizontal') - # The ratio of the size of the left/top pane to the right/bottom pane. + #: The ratio of the size of the left/top pane to the right/bottom pane. ratio = Float(0.5) - # An optional callable that provides the left hand/top panel. + #: An optional callable that provides the left hand/top panel. lhs = Callable - # An optional callable that provides the right hand/bottom panel. + #: An optional callable that provides the right hand/bottom panel. rhs = Callable ########################################################################### @@ -48,18 +48,49 @@ ########################################################################### def _create_splitter(self, parent): - """ Create the toolkit-specific control that represents the widget. """ + """ Create the toolkit-specific control that represents the widget. + + Parameters + ---------- + parent : toolkit control + The toolkit control that contains the splitter. + + Returns + ------- + splitter : toolkit control + The toolkit control for the splitter. + """ def _create_lhs(self, parent): - """ Creates the left hand/top panel depending on the direction. """ + """ Creates the left hand/top panel depending on the direction. + + Parameters + ---------- + parent : toolkit control + The splitter's toolkit control. + + Returns + ------- + lhs : toolkit control + The toolkit control for the lhs. + """ def _create_rhs(self, parent): - """ Creates the right hand/bottom panel depending on the direction. """ + """ Creates the right hand/bottom panel depending on the direction. + + Parameters + ---------- + parent : toolkit control + The splitter's toolkit control. + + Returns + ------- + rhs : toolkit control + The toolkit control for the rhs. + """ class MSplitWidget(object): """ The mixin class that contains common code for toolkit specific implementations of the ISplitWidget interface. """ - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/i_system_metrics.py python-pyface-6.1.2/pyface/i_system_metrics.py --- python-pyface-4.5.2/pyface/i_system_metrics.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_system_metrics.py 2019-05-03 08:18:49.000000000 +0000 @@ -23,14 +23,14 @@ #### 'ISystemMetrics' interface ########################################### - # The width of the screen in pixels. + #: The width of the screen in pixels. screen_width = Int - # The height of the screen in pixels. + #: The height of the screen in pixels. screen_height = Int - # Background color of a standard dialog window as a tuple of RGB values - # between 0.0 and 1.0. + #: Background color of a standard dialog window as a tuple of RGB values + #: between 0.0 and 1.0. # FIXME v3: Why isn't this a traits colour? dialog_background_color = Tuple @@ -39,5 +39,3 @@ """ The mixin class that contains common code for toolkit specific implementations of the ISystemMetrics interface. """ - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/i_widget.py python-pyface-6.1.2/pyface/i_widget.py --- python-pyface-4.5.2/pyface/i_widget.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_widget.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,7 +15,7 @@ # Enthought library imports. -from traits.api import Any, Interface +from traits.api import Any, Bool, HasTraits, Interface class IWidget(Interface): @@ -24,49 +24,114 @@ Pyface widgets delegate to a toolkit specific control. """ - #### 'IWidget' interface ################################################## - - # The toolkit specific control that represents the widget. + #: The toolkit specific control that represents the widget. control = Any - # The control's optional parent control. + #: The control's optional parent control. parent = Any - ########################################################################### + #: Whether or not the control is visible + visible = Bool(True) + + #: Whether or not the control is enabled + enabled = Bool(True) + + # ------------------------------------------------------------------------ # 'IWidget' interface. - ########################################################################### + # ------------------------------------------------------------------------ + + def show(self, visible): + """ Show or hide the widget. + + Parameter + --------- + visible : bool + Visible should be ``True`` if the widget should be shown. + """ + + def enable(self, enabled): + """ Enable or disable the widget. + + Parameter + --------- + enabled : bool + The enabled state to set the widget to. + """ def destroy(self): """ Destroy the control if it exists. """ - ########################################################################### + # ------------------------------------------------------------------------ # Protected 'IWidget' interface. - ########################################################################### + # ------------------------------------------------------------------------ def _create(self): - """ Creates the toolkit specific control. """ + """ Creates the toolkit specific control. + + This method should create the control and assign it to the + :py:attr:``control`` trait. + """ def _create_control(self, parent): - """ Create and return the toolkit specific control that represents the - widget. + """ Create toolkit specific control that represents the widget. + + Parameters + ---------- + parent : toolkit control + The toolkit control to be used as the parent for the widget's + control. + + Returns + ------- + control : toolkit control + A control for the widget. """ + def _add_event_listeners(self): + """ Set up toolkit-specific bindings for events """ + + def _remove_event_listeners(self): + """ Remove toolkit-specific bindings for events """ + class MWidget(object): """ The mixin class that contains common code for toolkit specific implementations of the IWidget interface. - - Implements: _create() """ - ########################################################################### + # ------------------------------------------------------------------------ # Protected 'IWidget' interface. - ########################################################################### + # ------------------------------------------------------------------------ def _create(self): + """ Creates the toolkit specific control. + + This method should create the control and assign it to the + :py:attr:``control`` trait. + """ self.control = self._create_control(self.parent) + self._add_event_listeners() def _create_control(self, parent): + """ Create toolkit specific control that represents the widget. + + Parameters + ---------- + parent : toolkit control + The toolkit control to be used as the parent for the widget's + control. + + Returns + ------- + control : toolkit control + A control for the widget. + """ raise NotImplementedError -#### EOF ###################################################################### + def _add_event_listeners(self): + """ Set up toolkit-specific bindings for events """ + pass + + def _remove_event_listeners(self): + """ Remove toolkit-specific bindings for events """ + pass diff -Nru python-pyface-4.5.2/pyface/i_window.py python-pyface-6.1.2/pyface/i_window.py --- python-pyface-4.5.2/pyface/i_window.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/i_window.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2005-18, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -10,17 +9,15 @@ # # Author: Enthought, Inc. # Description: -#------------------------------------------------------------------------------ """ The abstract interface for all pyface top-level windows. """ - # Enthought library imports. -from traits.api import Event, Tuple, Unicode +from traits.api import Event, Tuple, Unicode, Vetoable, VetoableEvent # Local imports. -from constant import NO -from key_pressed_event import KeyPressedEvent -from i_widget import IWidget +from pyface.constant import NO +from pyface.key_pressed_event import KeyPressedEvent +from pyface.i_widget import IWidget class IWindow(IWidget): @@ -30,97 +27,146 @@ (ie. its 'control' trait will be None until it is opened). """ - #### 'IWindow' interface ################################################## + # 'IWindow' interface ----------------------------------------------------- - # The position of the window. + #: The position of the window. position = Tuple - # The size of the window. + #: The size of the window. size = Tuple - # The window title. + #: The window title. title = Unicode - #### Events ##### + # Window Events ---------------------------------------------------------- + + #: The window has been opened. + opened = Event + + #: The window is about to open. + opening = VetoableEvent - # The window has been activated. + #: The window has been activated. activated = Event - # The window has been closed. - closed = Event + #: The window has been closed. + closed = Event - # The window is about to be closed. - closing = Event + #: The window is about to be closed. + closing = VetoableEvent - # The window has been deactivated. + #: The window has been deactivated. deactivated = Event - # A key was pressed while the window had focus. + #: A key was pressed while the window had focus. # FIXME v3: This smells of a hack. What's so special about key presses? # FIXME v3: Unicode key_pressed = Event(KeyPressedEvent) - # The window has been opened. - opened = Event - - # The window is about to open. - opening = Event - - ########################################################################### + # ------------------------------------------------------------------------- # 'IWindow' interface. - ########################################################################### + # ------------------------------------------------------------------------- def open(self): - """ Opens the window. """ + """ Opens the window. + + This fires the :py:attr:`closing` vetoable event, giving listeners the + opportunity to veto the opening of the window. - def close(self): - """ Closes the window. """ + If the window is opened, the :py:attr:`opened` event will be fired + with the IWindow instance as the event value. - def activate(self): - """ Activates the window. """ + Returns + ------- + opened : bool + Whether or not the window was opened. + """ - def show(self, visible): - """ Show or hide the window. + def close(self, force=False): + """ Closes the window. - visible is set if the window should be shown. + This fires the :py:attr:`closing` vetoable event, giving listeners the + opportunity to veto the closing of the window. If :py:obj:`force` is + :py:obj:`True` then the window will close no matter what. + + If the window is closed, the closed event will be fired with the window + object as the event value. + + Parameters + ---------- + force : bool + Whether the window should close despite vetos. + + Returns + ------- + closed : bool + Whether or not the window is closed. """ def confirm(self, message, title=None, cancel=False, default=NO): """ Convenience method to show a confirmation dialog. - message is the text of the message to display. - title is the text of the window title. - cancel is set if the dialog should contain a Cancel button. - default is the default button. + Parameters + ---------- + message : str + The text of the message to display. + title : str + The text of the dialog title. + cancel : bool + ``True`` if the dialog should contain a Cancel button. + default : NO, YES or CANCEL + Which button should be the default button. """ - def information(self, message, title='Information'): + def information( + self, message, title='Information', detail='', informative='' + ): """ Convenience method to show an information message dialog. - message is the text of the message to display. - title is the text of the window title. + Parameters + ---------- + message : str + The text of the message to display. + title : str + The text of the dialog title. + detail : str + Further details about the message. + informative : str + Explanatory text to display along with the message. + """ - def warning(self, message, title='Warning'): + def warning(self, message, title='Warning', detail='', informative=''): """ Convenience method to show a warning message dialog. - message is the text of the message to display. - title is the text of the window title. + Parameters + ---------- + message : str + The text of the message to display. + title : str + The text of the dialog title. + detail : str + Further details about the message. + informative : str + Explanatory text to display along with the message. + """ - def error(self, message, title='Error'): + def error(self, message, title='Error', detail='', informative=''): """ Convenience method to show an error message dialog. - message is the text of the message to display. - title is the text of the window title. - """ - - ########################################################################### - # Protected 'IWindow' interface. - ########################################################################### + Parameters + ---------- + message : str + The text of the message to display. + title : str + The text of the dialog title. + detail : str + Further details about the message. + informative : str + Explanatory text to display along with the message. - def _add_event_listeners(self): - """ Adds any event listeners required by the window. """ + """ class MWindow(object): @@ -131,78 +177,136 @@ Reimplements: _create() """ - ########################################################################### + # ------------------------------------------------------------------------- # 'IWindow' interface. - ########################################################################### + # ------------------------------------------------------------------------- def open(self): - """ Opens the window. """ - - # Trait notification. - self.opening = self - - if self.control is None: - self._create() + """ Opens the window. - self.show(True) + This fires the :py:attr:`closing` vetoable event, giving listeners the + opportunity to veto the opening of the window. - # Trait notification. - self.opened = self - - return - - def close(self): - """ Closes the window. """ + If the window is opened, the :py:attr:`opened` event will be fired + with the IWindow instance as the event value. + Returns + ------- + opened : bool + Whether or not the window was opened. + """ + self.opening = event = Vetoable() + if not event.veto: + # Create the control, if necessary. + if self.control is None: + self._create() + + self.show(True) + self.opened = self + + return self.control is not None and not event.veto + + def close(self, force=False): + """ Closes the window. + + This fires the :py:attr:`closing` vetoable event, giving listeners the + opportunity to veto the closing of the window. If :py:obj:`force` is + :py:obj:`True` then the window will close no matter what. + + If the window is closed, the closed event will be fired with the window + object as the event value. + + Parameters + ---------- + force : bool + Whether the window should close despite vetos. + + Returns + ------- + closed : bool + Whether or not the window is closed. + """ if self.control is not None: - # Trait notification. - self.closing = self + self.closing = event = Vetoable() + if force or not event.veto: + self.destroy() + self.closed = self - # Cleanup the toolkit-specific control. - self.destroy() - - # Trait notification. - self.closed = self - - return + return self.control is None def confirm(self, message, title=None, cancel=False, default=NO): - """ Convenience method to show a confirmation dialog. """ + """ Convenience method to show a confirmation dialog. - from confirmation_dialog import confirm + Parameters + ---------- + message : str + The text of the message to display. + title : str + The text of the dialog title. + cancel : bool + ``True`` if the dialog should contain a Cancel button. + default : NO, YES or CANCEL + Which button should be the default button. + """ + from .confirmation_dialog import confirm return confirm(self.control, message, title, cancel, default) - def information(self, message, title='Information'): - """ Convenience method to show an information message dialog. """ - - from message_dialog import information + def information( + self, message, title='Information', detail='', informative='' + ): + """ Convenience method to show an information message dialog. - return information(self.control, message, title) + Parameters + ---------- + message : str + The text of the message to display. + title : str + The text of the dialog title. + detail : str + Further details about the message. + informative : str + Explanatory text to display along with the message. - def warning(self, message, title='Warning'): - """ Convenience method to show a warning message dialog. """ + """ + from .message_dialog import information - from message_dialog import warning + information(self.control, message, title, detail, informative) - return warning(self.control, message, title) + def warning(self, message, title='Warning', detail='', informative=''): + """ Convenience method to show a warning message dialog. - def error(self, message, title='Error'): - """ Convenience method to show an error message dialog. """ + Parameters + ---------- + message : str + The text of the message to display. + title : str + The text of the dialog title. + detail : str + Further details about the message. + informative : str + Explanatory text to display along with the message. - from message_dialog import error + """ + from .message_dialog import warning - return error(self.control, message, title) + warning(self.control, message, title, detail, informative) - ########################################################################### - # Protected 'IWidget' interface. - ########################################################################### + def error(self, message, title='Error', detail='', informative=''): + """ Convenience method to show an error message dialog. - def _create(self): - """ Creates the window's widget hierarchy. """ + Parameters + ---------- + message : str + The text of the message to display. + title : str + The text of the dialog title. + detail : str + Further details about the message. + informative : str + Explanatory text to display along with the message. - # Create the toolkit-specific control. - super(MWindow, self)._create() + """ + from .message_dialog import error - # Wire up event any event listeners required by the window. - self._add_event_listeners() + error(self.control, message, title, detail, informative) diff -Nru python-pyface-4.5.2/pyface/key_pressed_event.py python-pyface-6.1.2/pyface/key_pressed_event.py --- python-pyface-4.5.2/pyface/key_pressed_event.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/key_pressed_event.py 2019-05-03 08:18:49.000000000 +0000 @@ -10,19 +10,19 @@ #### 'KeyPressedEvent' interface ########################################## - # Is the alt key down? + #: Is the alt key down? alt_down = Bool - # Is the control key down? + #: Is the control key down? control_down = Bool - # Is the shift key down? + #: Is the shift key down? shift_down = Bool - # The keycode. + #: The keycode. key_code = Int - # The original toolkit specific event. + #: The original toolkit specific event. event = Any #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/layered_panel.py python-pyface-6.1.2/pyface/layered_panel.py --- python-pyface-4.5.2/pyface/layered_panel.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/layered_panel.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,173 +6,11 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -""" A Layered panel. """ -from __future__ import absolute_import - -# Major package imports. -import wx -from wx.lib.scrolledpanel import ScrolledPanel - -# Enthought library imports. -from traits.api import Any, Str, Int - -# Local imports. -from .widget import Widget - - -class LayeredPanel(Widget): - """ A Layered panel. - - A layered panel contains one or more named layers, with only one layer - visible at any one time (think of a 'tab' control minus the tabs!). Each - layer is a toolkit-specific control. - - """ - - # The default style. - STYLE = wx.CLIP_CHILDREN - - #### "Layered Panel' interface ############################################ - - # The toolkit-specific control of the currently displayed layer. - current_layer = Any - - # The name of the currently displayed layer. - current_layer_name = Str - - # The minimum for the panel, which is the maximum of the minimum - # sizes of the layers - min_width = Int(0) - min_height = Int(0) - - ########################################################################### - # 'object' interface. - ########################################################################### - - def __init__(self, parent, **traits): - """ Creates a new LayeredPanel. """ - - # Base class constructor. - super(LayeredPanel, self).__init__(**traits) - - # Create the toolkit-specific control that represents the widget. - self.control = self._create_control(parent) - - # The layers in the panel. - # - # { str name : wx.Window layer } - self._layers = {} - - return - - ########################################################################### - # 'LayeredPanel' interface. - ########################################################################### - - def add_layer(self, name, layer): - """ Adds a layer with the specified name. - - All layers are hidden when they are added. Use 'show_layer' to make a - layer visible. - - """ - # Add the layer to our sizer. - sizer = self.control.GetSizer() - sizer.Add(layer, 1, wx.EXPAND) +# Note: The MultiToolbarWindow is currently wx-specific - # All layers are hidden when they are added. Use 'show_layer' to make - # a layer visible. - sizer.Show(layer, False) - - # fixme: Should we warn if a layer is being overridden? - self._layers[name] = layer - - # fixme: The minimum size stuff that was added for linux broke the - # sizing on Windows (at least for the preference dialog). The - # preference dialog now sets the minimum width and height to -1 so - # that this layout code doesn't get executed. - if self.min_width != -1 or self.min_height != -1: - if layer.GetSizer() is None: - return layer - - min_size = layer.GetSizer().CalcMin() - needs_layout = False - if min_size.GetWidth() > self.min_width: - self.min_width = min_size.GetWidth() - needs_layout = True - if min_size.GetHeight() > self.min_height: - self.min_height = min_size.GetHeight() - needs_layout = True - - if needs_layout: - # Reset our size hints and relayout - self.control.SetSizeHints(self.min_width, self.min_height) - self.control.GetSizer().Layout() - - # fixme: Force our parent to reset it's size hints to its - # minimum - parent = self.control.GetParent() - parent.GetSizer().SetSizeHints(parent) - parent.GetSizer().Layout() - - return layer - - def show_layer(self, name): - """ Shows the layer with the specified name. """ - - # Hide the current layer (if one is displayed). - if self.current_layer is not None: - self._hide_layer(self.current_layer) - - # Show the specified layer. - layer = self._show_layer(name, self._layers[name]) - - return layer - - def has_layer(self, name): - """ Does the panel contain a layer with the specified name? """ - - return self._layers.has_key(name) - - ########################################################################### - # Private interface. - ########################################################################### - - def _create_control(self, parent): - """ Create the toolkit-specific control that represents the widget. """ - - panel = ScrolledPanel(parent, -1, style=self.STYLE) - sizer = wx.BoxSizer(wx.VERTICAL) - panel.SetSizer(sizer) - panel.SetAutoLayout(True) - panel.SetupScrolling() - - return panel - - def _hide_layer(self, layer): - """ Hides the specified layer. """ - - sizer = self.control.GetSizer() - sizer.Show(layer, False) - sizer.Layout() - - return - - def _show_layer(self, name, layer): - """ Shows the specified layer. """ - - sizer = self.control.GetSizer() - sizer.Show(layer, True) - sizer.Layout() - - self.current_layer = layer - self.current_layer_name = name - - return layer +# Import the toolkit specific version. +from __future__ import absolute_import -#### EOF ###################################################################### +from .toolkit import toolkit_object +LayeredPanel = toolkit_object('layered_panel:LayeredPanel') diff -Nru python-pyface-4.5.2/pyface/list_box_model.py python-pyface-6.1.2/pyface/list_box_model.py --- python-pyface-4.5.2/pyface/list_box_model.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/list_box_model.py 2019-05-03 08:18:49.000000000 +0000 @@ -8,34 +8,40 @@ class ListModelEvent(object): """ Information about list model changes. """ - def __init__(self): - """ Creates a new list model event. """ - - return class ListBoxModel(HasTraits): """ The model for list boxes. """ #### Events #### - # Fired when the contents of the list have changed. + #: Fired when the contents of the list have changed. list_changed = Event def get_item_count(self): - """ Returns the number of items in the list. """ + """ Get the number of items in the list. + Returns + ------- + item_count : int + The number of items in the list. + """ raise NotImplementedError def get_item_at(self, index): - """ Returns the item at the specified index. """ + """ Returns the item at the specified index. + Parameters + ---------- + index : int + The index to return the value of. + + Returns + ------- + label, item : str, any + The user-visible string and model data of the item. + """ raise NotImplementedError def fire_list_changed(self): """ Invoke this method when the list has changed. """ - self.list_changed = ListModelEvent() - - return - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/list_box.py python-pyface-6.1.2/pyface/list_box.py --- python-pyface-4.5.2/pyface/list_box.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/list_box.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,145 +1,16 @@ -""" A simple list box widget with a model-view architecture. """ -from __future__ import absolute_import - -# Major package imports. -import wx - -# Enthought library imports. -from traits.api import Event, Instance, Int - -# Local imports. -from .list_box_model import ListBoxModel -from .widget import Widget - - -class ListBox(Widget): - """ A simple list box widget with a model-view architecture. """ - - # The model that provides the data for the list box. - model = Instance(ListBoxModel) - - # The objects currently selected in the list. - selection = Int(-1) - - # Events. - - # An item has been activated. - item_activated = Event - - # Default style. - STYLE = wx.LB_SINGLE | wx.LB_HSCROLL | wx.LB_NEEDED_SB - - - def __init__(self, parent, **traits): - """ Creates a new list box. """ - - # Base-class constructors. - super(ListBox, self).__init__(**traits) - - # Create the widget! - self._create_control(parent) - - # Listen for changes to the model. - self.model.on_trait_change(self._on_model_changed, "list_changed") - - return - - def dispose(self): - self.model.on_trait_change(self._on_model_changed, "list_changed", - remove = True) - self.model.dispose() - return - - ########################################################################### - # 'ListBox' interface. - ########################################################################### - - def refresh(self): - """ Refreshes the list box. """ - - # For now we just clear out the entire list. - self.control.Clear() - - # Populate the list. - self._populate() - - return - - ########################################################################### - # wx event handlers. - ########################################################################### - - def _on_item_selected(self, event): - """ Called when an item in the list is selected. """ +# Copyright (c) 2017, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! - listbox = event.GetEventObject() +# Note: The ListBox is currently wx-specific - self.selection = listbox.GetSelection() - - return - - def _on_item_activated(self, event): - """ Called when an item in the list is activated. """ - - listbox = event.GetEventObject() - index = listbox.GetSelection() - - # Trait event notification. - self.item_activated = index - - return - - ########################################################################### - # Trait handlers. - ########################################################################### - - #### Static ############################################################### - - def _selection_changed(self, index): - """ Called when the selected item is changed. """ - - if index != -1: - self.control.SetSelection(index) - - return - - #### Dynamic ############################################################## - - def _on_model_changed(self, event): - """ Called when the model has changed. """ - - # For now we just clear out the entire list. - self.refresh() - - return - - ########################################################################### - # Private interface. - ########################################################################### - - def _create_control(self, parent): - """ Creates the widget. """ - - self.control = wx.ListBox(parent, -1, style = self.STYLE) - - # Wire it up! - wx.EVT_LISTBOX(self.control, self.control.GetId(), - self._on_item_selected) - wx.EVT_LISTBOX_DCLICK(self.control, self.control.GetId(), - self._on_item_activated) - - # Populate the list. - self._populate() - - return - - def _populate(self): - """ Populates the list box. """ - - for index in range(self.model.get_item_count()): - label, item = self.model.get_item_at(index) - self.control.Append(label, item) - - return +# Import the toolkit specific version. +from __future__ import absolute_import -#### EOF ###################################################################### +from .toolkit import toolkit_object +ListBox = toolkit_object('list_box:ListBox') diff -Nru python-pyface-4.5.2/pyface/mdi_application_window.py python-pyface-6.1.2/pyface/mdi_application_window.py --- python-pyface-4.5.2/pyface/mdi_application_window.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/mdi_application_window.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,180 +6,11 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -""" An MDI top-level application window. """ -from __future__ import absolute_import - -# Major package imports. -import wx - -# Enthought library imports. -from traits.api import Bool, Instance, Int, Tuple - -# Local imports. -from .application_window import ApplicationWindow -from .image_resource import ImageResource - -try: - import wx.aui - AUI = True -except: - AUI = False - - -class MDIApplicationWindow(ApplicationWindow): - """ An MDI top-level application window. - - The application window has support for a menu bar, tool bar and a status - bar (all of which are optional). - - Usage: Create a sub-class of this class and override the protected - '_create_contents' method. - - """ - - #### 'MDIApplicationWindow' interface ##################################### - - # The workarea background image. - background_image = Instance(ImageResource, ImageResource('background')) - - # Should we tile the workarea background image? The alternative is to - # scale it. Be warned that scaling the image allows for 'pretty' images, - # but is MUCH slower than tiling. - tile_background_image = Bool(True) - - # WX HACK FIXME - # UPDATE: wx 2.6.1 does NOT fix this issue. - _wx_offset = Tuple(Int, Int) - - ########################################################################### - # 'MDIApplicationWindow' interface. - ########################################################################### - - def create_child_window(self, title=None, is_mdi=True, float=True): - """ Create a child window. """ - if title is None: - title = self.title - - if is_mdi: - return wx.MDIChildFrame(self.control, -1, title) - else: - if float: - style = wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT - else: - style = wx.DEFAULT_FRAME_STYLE - return wx.Frame(self.control, -1, title, style=style) - - ########################################################################### - # Protected 'Window' interface. - ########################################################################### - - def _create_contents(self, parent): - """ Create the contents of the MDI window. """ - - # Create the 'trim' widgets (menu, tool and status bars etc). - self._create_trim_widgets(self.control) - - # The work-area background image (it can be tiled or scaled). - self._image = self.background_image.create_image() - self._bmp = self._image.ConvertToBitmap() - - # Frame events. - # - # We respond to size events to layout windows around the MDI frame. - wx.EVT_SIZE(self.control, self._on_size) - - # Client window events. - client_window = self.control.GetClientWindow() - wx.EVT_ERASE_BACKGROUND(client_window, self._on_erase_background) - - self._wx_offset = client_window.GetPositionTuple() - - if AUI: - # Let the AUI manager look after the frame. - self._aui_manager.SetManagedWindow(self.control) - contents = super(MDIApplicationWindow, self)._create_contents(parent) +# Note: The MDIApplicationWindow is currently wx-specific - return contents - - def _create_control(self, parent): - """ Create the toolkit-specific control that represents the window. """ - - control = wx.MDIParentFrame( - parent, -1, self.title, style=wx.DEFAULT_FRAME_STYLE, - size=self.size, pos=self.position - ) - - return control - - ########################################################################### - # Private interface. - ########################################################################### - - - def _tile_background_image(self, dc, width, height): - """ Tiles the background image. """ - - w = self._bmp.GetWidth() - h = self._bmp.GetHeight() - - x = 0 - while x < width: - y = 0 - while y < height: - dc.DrawBitmap(self._bmp, x, y) - y = y + h - - x = x + w - - return - - def _scale_background_image(self, dc, width, height): - """ Scales the background image. """ - - # Scale the image (if necessary). - image = self._image - if image.GetWidth() != width or image.GetHeight()!= height: - image = self._image.Copy() - image.Rescale(width, height) - - # Convert it to a bitmap and draw it. - dc.DrawBitmap(image.ConvertToBitmap(), 0, 0) - - return - - ##### wx event handlers ################################################### - - def _on_size(self, event): - """ Called when the frame is resized. """ - - wx.LayoutAlgorithm().LayoutMDIFrame(self.control) - - return - - def _on_erase_background(self, event): - """ Called when the background of the MDI client window is erased. """ - - # fixme: Close order... - if self.control is None: - return - - frame = self.control - - dc = event.GetDC() - if not dc: - dc = wx.ClientDC(frame.GetClientWindow()) - - size = frame.GetClientSize() - - # Currently you have two choices, tile the image or scale it. Be - # warned that scaling is MUCH slower than tiling. - if self.tile_background_image: - self._tile_background_image(dc, size.width, size.height) +# Import the toolkit specific version. +from __future__ import absolute_import - else: - self._scale_background_image(dc, size.width, size.height) +from .toolkit import toolkit_object +MDIApplicationWindow = toolkit_object('mdi_application_window:MDIApplicationWindow') diff -Nru python-pyface-4.5.2/pyface/mdi_window_menu.py python-pyface-6.1.2/pyface/mdi_window_menu.py --- python-pyface-4.5.2/pyface/mdi_window_menu.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/mdi_window_menu.py 2019-05-03 08:18:49.000000000 +0000 @@ -22,7 +22,7 @@ from traits.api import Str # Local imports. -from action.api import MenuManager, Separator, WindowAction +from .action.api import MenuManager, Separator, WindowAction class Cascade(WindowAction): diff -Nru python-pyface-4.5.2/pyface/message_dialog.py python-pyface-6.1.2/pyface/message_dialog.py --- python-pyface-4.5.2/pyface/message_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/message_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,41 +13,88 @@ #------------------------------------------------------------------------------ """ The implementation of a dialog that displays a message. """ +from __future__ import absolute_import + # Convenience functions. -def information(parent, message, title='Information'): - """ Convenience function to show an information message dialog. """ +def information(parent, message, title='Information', + detail='', informative=''): + """ Convenience method to show an information message dialog. + + Parameters + ---------- + parent : toolkit control or None + The toolkit control that should be the parent of the dialog. + message : str + The text of the message to display. + title : str + The text of the dialog title. + detail : str + Further details about the message (displayed when the user clicks + "Show details"). + informative : str + Explanatory text to display along with the message. + """ dialog = MessageDialog( - parent=parent, message=message, title=title, severity='information' + parent=parent, message=message, title=title, + severity='information', detail=detail, informative=informative ) dialog.open() - return -def warning(parent, message, title='Warning'): - """ Convenience function to show a warning message dialog. """ +def warning(parent, message, title='Warning', detail='', informative=''): + """ Convenience function to show a warning message dialog. + + Parameters + ---------- + parent : toolkit control or None + The toolkit control that should be the parent of the dialog. + message : str + The text of the message to display. + title : str + The text of the dialog title. + detail : str + Further details about the message (displayed when the user clicks + "Show details"). + informative : str + Explanatory text to display along with the message. + """ dialog = MessageDialog( - parent=parent, message=message, title=title, severity='warning' + parent=parent, message=message, title=title, + severity='warning', detail=detail, informative=informative ) dialog.open() - return -def error(parent, message, title='Error'): - """ Convenience function to show an error message dialog. """ +def error(parent, message, title='Error', detail='', informative=''): + """ Convenience function to show an error message dialog. + Parameters + ---------- + parent : toolkit control or None + The toolkit control that should be the parent of the dialog. + message : str + The text of the message to display. + title : str + The text of the dialog title. + detail : str + Further details about the message (displayed when the user clicks + "Show details"). + informative : str + Explanatory text to display along with the message. + + """ dialog = MessageDialog( - parent=parent, message=message, title=title, severity='error' + parent=parent, message=message, title=title, severity='error', + detail=detail, informative=informative ) dialog.open() - return - # Import the toolkit specific version. -from toolkit import toolkit_object +from .toolkit import toolkit_object MessageDialog = toolkit_object('message_dialog:MessageDialog') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/mimedata.py python-pyface-6.1.2/pyface/mimedata.py --- python-pyface-4.5.2/pyface/mimedata.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/mimedata.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,6 @@ +# Import the toolkit specific version. +from pyface.toolkit import toolkit_object + +# WIP: Currently only supports qt4 backend. API might change without +# prior notification +PyMimeData = toolkit_object('mimedata:PyMimeData') diff -Nru python-pyface-4.5.2/pyface/multi_toolbar_window.py python-pyface-6.1.2/pyface/multi_toolbar_window.py --- python-pyface-4.5.2/pyface/multi_toolbar_window.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/multi_toolbar_window.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,147 +6,11 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -""" A top-level application window that supports multiple toolbars. """ -from __future__ import absolute_import - -# Major package imports. -import wx - -# Enthought library imports -from pyface.action.api import ToolBarManager -from traits.api import Trait, TraitDict, TraitEnum, TraitList - -# Local imports -from .application_window import ApplicationWindow - - -class MultiToolbarWindow(ApplicationWindow): - """ A top-level application window that supports multiple toolbars. - - The multi-toolbar window has support for a menu bar, status bar, and - multiple toolbars (all of which are optional). - - """ - - # The toolbars in the order they were added to the window. - _tool_bar_managers = Trait([], TraitList(Trait(ToolBarManager))) - - # Map of toolbar to screen location. - _tool_bar_locations = Trait({}, - TraitDict(Trait(ToolBarManager), - TraitEnum('top', 'bottom', - 'left', 'right'))) - - ########################################################################### - # Protected 'Window' interface. - ########################################################################### - def _create_contents(self, parent): - panel = super(MultiToolbarWindow, self)._create_contents(parent) - self._create_trim_widgets(parent) - - return panel - - def _create_trim_widgets(self, parent): - - # The frame's icon. - self._set_window_icon() - - # Add the (optional) menu bar. - self._create_menu_bar(parent) - - # Add the (optional) status bar. - self._create_status_bar(parent) - - # Add the (optional) tool bars. - self.sizer = self._create_tool_bars(parent) - - return - - def _create_tool_bars(self, parent): - """ Create the tool bars for this window. """ - - if len(self._tool_bar_managers) > 0: - # Create a top level sizer to handle to main layout and attach - # it to the parent frame. - self.main_sizer = sizer = wx.BoxSizer(wx.VERTICAL) - parent.SetSizer(sizer) - parent.SetAutoLayout(True) - for tool_bar_manager in self._tool_bar_managers: - location = self._tool_bar_locations[tool_bar_manager] - sizer = self._create_tool_bar(parent, sizer, tool_bar_manager, - location) +# Note: The MultiToolbarWindow is currently wx-specific - return sizer - - return None - - def _create_tool_bar(self, parent, sizer, tool_bar_manager, location): - """ Create and add the toolbar to the parent window at the specified - location. - - Returns the sizer where the remaining content should be added. For - 'top' and 'left' toolbars, we can return the same sizer that contains - the toolbar, because subsequent additions will be added below or to - the right of those toolbars. For 'right' and 'bottom' toolbars, we - create a spacer toolbar to hold the content. - """ - - tool_bar = tool_bar_manager.create_tool_bar(parent) - - if location == 'top': - child_sizer = wx.BoxSizer(wx.VERTICAL) - child_sizer.Add(tool_bar, 0, wx.ALL | wx.ALIGN_LEFT | wx.EXPAND) - sizer.Add(child_sizer, 1, wx.ALL | wx.EXPAND) - - if location == 'bottom': - toolbar_sizer = wx.BoxSizer(wx.VERTICAL) - - # Add the placeholder for the content before adding the toolbar. - child_sizer = self._create_content_spacer(toolbar_sizer) - - # Add the tool bar. - toolbar_sizer.Add(tool_bar, 0, wx.ALL | wx.ALIGN_TOP | wx.EXPAND) - sizer.Add(toolbar_sizer, 1, wx.ALL | wx.EXPAND) - - if location == 'left': - child_sizer = wx.BoxSizer(wx.HORIZONTAL) - child_sizer.Add(tool_bar, 0, wx.ALL | wx.ALIGN_TOP | wx.EXPAND) - sizer.Add(child_sizer, 1, wx.ALL | wx.EXPAND) - - if location == 'right': - toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL) - - # Add the placeholder for the content before adding the toolbar. - child_sizer = self._create_content_spacer(toolbar_sizer) - - # Add the tool bar. - toolbar_sizer.Add(tool_bar, 0, wx.ALL | wx.ALIGN_TOP | wx.EXPAND) - sizer.Add(toolbar_sizer, 1, wx.ALL | wx.EXPAND) - - return child_sizer - - def _create_content_spacer(self, sizer): - spacer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(spacer, 1, wx.ALL | wx.EXPAND) - - return spacer - - ########################################################################### - # Public MultiToolbarWindow interface - ########################################################################### - - def add_tool_bar(self, tool_bar_manager, location='top'): - """ Add a toolbar in the specified location. - - Valid locations are 'top', 'bottom', 'left', and 'right' - """ - - self._tool_bar_managers.append(tool_bar_manager) - self._tool_bar_locations[tool_bar_manager] = location +# Import the toolkit specific version. +from __future__ import absolute_import -#### EOF ###################################################################### +from .toolkit import toolkit_object +MultiToolbarWindow = toolkit_object('multi_toolbar_window:MultiToolbarWindow') diff -Nru python-pyface-4.5.2/pyface/preference/api.py python-pyface-6.1.2/pyface/preference/api.py --- python-pyface-4.5.2/pyface/preference/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/preference/api.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2005-2015, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -11,6 +11,9 @@ # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ -from preference_page import PreferencePage -from preference_dialog import PreferenceDialog -from preference_node import PreferenceNode + +from __future__ import absolute_import + +from .preference_page import PreferencePage +from .preference_dialog import PreferenceDialog +from .preference_node import PreferenceNode diff -Nru python-pyface-4.5.2/pyface/preference/preference_dialog.py python-pyface-6.1.2/pyface/preference/preference_dialog.py --- python-pyface-4.5.2/pyface/preference/preference_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/preference/preference_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,206 +6,11 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ """ The preference dialog. """ -# Major package imports. -import wx - -# Enthought library imports. -from pyface.api import HeadingText, LayeredPanel, SplitDialog -from pyface.util.font_helper import new_font_like -from pyface.viewer.api import TreeViewer, DefaultTreeContentProvider -from traits.api import Any, Dict, Float, Instance, Str - -# Local imports. -from preference_node import PreferenceNode - - -class PreferenceDialog(SplitDialog): - """ The preference dialog. """ - - #### 'Dialog' interface ################################################### - - # The dialog title. - title = Str('Preferences') - - #### 'SplitDialog' interface ############################################## - - # The ratio of the size of the left/top pane to the right/bottom pane. - ratio = Float(0.25) - - #### 'PreferenceDialog' interface ######################################### - - # The root of the preference hierarchy. - root = Instance(PreferenceNode) - - #### Private interface #################################################### - - # The preference pages in the dialog (they are created lazily). - _pages = Dict - - # The current visible preference page. - _current_page = Any - - ########################################################################### - # Protected 'Dialog' interface. - ########################################################################### - - def _create_buttons(self, parent): - """ Creates the buttons. """ - - sizer = wx.BoxSizer(wx.HORIZONTAL) - - # 'Done' button. - done = wx.Button(parent, wx.ID_OK, "Done") - done.SetDefault() - wx.EVT_BUTTON(parent, wx.ID_OK, self._wx_on_ok) - sizer.Add(done) - - return sizer - - ########################################################################### - # Protected 'SplitDialog' interface. - ########################################################################### - - def _create_lhs(self, parent): - """ Creates the panel containing the preference page tree. """ - - return self._create_tree(parent) - - def _create_rhs(self, parent): - """ Creates the panel containing the selected preference page. """ - - panel = wx.Panel(parent, -1, style=wx.CLIP_CHILDREN) - sizer = wx.BoxSizer(wx.VERTICAL) - panel.SetSizer(sizer) - panel.SetAutoLayout(True) - - # The 'pretty' title bar ;^) - self.__title = HeadingText(panel) - sizer.Add( - self.__title.control, 0, - wx.EXPAND | wx.BOTTOM | wx.LEFT | wx.RIGHT, 5 - ) - - # The preference page of the node currently selected in the tree. - self._layered_panel = LayeredPanel(panel, min_width=-1, min_height=-1) - sizer.Add( - self._layered_panel.control, 1, - wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, 5 - ) - - # The 'Restore Defaults' button etc. - buttons = self._create_page_buttons(panel) - sizer.Add(buttons, 0, wx.ALIGN_RIGHT | wx.TOP | wx.RIGHT, 5) - - # A separator. - line = wx.StaticLine(panel, -1) - sizer.Add(line, 0, wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, 5) - - # Resize the panel to fit the sizer's minimum size. - sizer.Fit(panel) - - return panel - - ########################################################################### - # Private interface. - ########################################################################### - - def _create_tree(self, parent): - """ Creates the preference page tree. """ - - tree_viewer = TreeViewer( - parent, - input = self.root, - show_images = False, - show_root = False, - content_provider = DefaultTreeContentProvider() - ) - - tree_viewer.on_trait_change(self._on_selection_changed, 'selection') - - return tree_viewer.control - - def _create_page_buttons(self, parent): - """ Creates the 'Restore Defaults' button, etc. - - At the moment the "etc." is an optional 'Help' button. - - """ - - self._button_sizer = sizer = wx.BoxSizer(wx.HORIZONTAL) - - # 'Help' button. Comes first so 'Restore Defaults' doesn't jump around. - self._help = help = wx.Button(parent, -1, "Help") - wx.EVT_BUTTON(parent, help.GetId(), self._on_help) - sizer.Add(help, 0, wx.RIGHT, 5) - - # 'Restore Defaults' button. - restore = wx.Button(parent, -1, "Restore Defaults") - wx.EVT_BUTTON(parent, restore.GetId(), self._on_restore_defaults) - sizer.Add(restore) - - return sizer - - ########################################################################### - # wx event handlers. - ########################################################################### - - def _on_restore_defaults(self, event): - """ Called when the 'Restore Defaults' button is pressed. """ - - page = self._pages[self._layered_panel.current_layer_name] - page.restore_defaults() - - return - - def _on_help(self, event): - """ Called when the 'Help' button is pressed. """ - - page = self._pages[self._layered_panel.current_layer_name] - page.show_help_topic() - - return - - ########################################################################### - # Trait event handlers. - ########################################################################### - - def _on_selection_changed(self, selection): - """ Called when a node in the tree is selected. """ - - if len(selection) > 0: - # The tree is in single selection mode. - node = selection[0] - - # We only show the help button if the selected node has a help - # topic Id. - if len(node.help_id) > 0: - self._button_sizer.Show(self._help, True) - - else: - self._button_sizer.Show(self._help, False) - - # Show the selected preference page. - layered_panel = self._layered_panel - parent = self._layered_panel.control - - # If we haven't yet displayed the node's preference page during the - # lifetime of this dialog, then we have to create it. - if not layered_panel.has_layer(node.name): - page = node.create_page() - layered_panel.add_layer(node.name, page.create_control(parent)) - self._pages[node.name] = page - - layered_panel.show_layer(node.name) - self.__title.text = node.name - - return +# Import the toolkit specific version. +from __future__ import absolute_import -#### EOF ###################################################################### +from pyface.toolkit import toolkit_object +TreeViewer = toolkit_object('preference.preference_dialog:PreferenceDialog') diff -Nru python-pyface-4.5.2/pyface/progress_dialog.py python-pyface-6.1.2/pyface/progress_dialog.py --- python-pyface-4.5.2/pyface/progress_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/progress_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -16,7 +16,9 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object ProgressDialog = toolkit_object('progress_dialog:ProgressDialog') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/python_editor.py python-pyface-6.1.2/pyface/python_editor.py --- python-pyface-4.5.2/pyface/python_editor.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/python_editor.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,7 +15,9 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object PythonEditor = toolkit_object('python_editor:PythonEditor') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/python_shell.py python-pyface-6.1.2/pyface/python_shell.py --- python-pyface-4.5.2/pyface/python_shell.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/python_shell.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,7 +15,9 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object PythonShell = toolkit_object('python_shell:PythonShell') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/qt/__init__.py python-pyface-6.1.2/pyface/qt/__init__.py --- python-pyface-4.5.2/pyface/qt/__init__.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/qt/__init__.py 2019-05-08 10:09:07.000000000 +0000 @@ -9,31 +9,88 @@ # Description: Qt API selector. Can be used to switch between pyQt and PySide #------------------------------------------------------------------------------ +import importlib import os +import sys + +QtAPIs = [ + ('pyside', 'PySide'), + ('pyside2', 'PySide2'), + ('pyqt5', 'PyQt5'), + ('pyqt', 'PyQt4'), +] + def prepare_pyqt4(): - # Set PySide compatible APIs. + """ Set PySide compatible APIs. """ + # This is not needed for Python 3 and can be removed when we no longer + # support Python 2. import sip - sip.setapi('QString', 2) - sip.setapi('QVariant', 2) - -qt_api = os.environ.get('QT_API') + try: + sip.setapi('QDate', 2) + sip.setapi('QDateTime', 2) + sip.setapi('QString', 2) + sip.setapi('QTextStream', 2) + sip.setapi('QTime', 2) + sip.setapi('QUrl', 2) + sip.setapi('QVariant', 2) + except ValueError as exc: + if sys.version_info[0] <= 2: + # most likely caused by something else setting the API version + # before us: try to give a better error message to direct the user + # how to fix. + msg = exc.args[0] + msg += (". Pyface expects PyQt API 2 under Python 2. " + "Either import Pyface before any other Qt-using packages, " + "or explicitly set the API before importing any other " + "Qt-using packages.") + raise ValueError(msg) + else: + # don't expect the above on Python 3, so just re-raise + raise + + +qt_api = None + +# have we already imported a Qt API? +for api_name, module in QtAPIs: + if module in sys.modules: + qt_api = api_name + if qt_api == 'pyqt': + # set the PyQt4 APIs + # this is a likely place for failure - pyface really wants to be + # imported first, before eg. matplotlib + prepare_pyqt4() + break +else: + # does our environment give us a preferred API? + qt_api = os.environ.get('QT_API') + if qt_api == 'pyqt': + # set the PyQt4 APIs + prepare_pyqt4() +# if we have no preference, is a Qt API available? Or fail with ImportError. if qt_api is None: - try: - import PySide - qt_api = 'pyside' - except ImportError: + for api_name, module in QtAPIs: try: - prepare_pyqt4() - import PyQt4 - qt_api = 'pyqt' + if api_name == 'pyqt': + # set the PyQt4 APIs + prepare_pyqt4() + importlib.import_module(module) + importlib.import_module('.QtCore', module) + qt_api = api_name + break except ImportError: - raise ImportError('Cannot import PySide or PyQt4') - -elif qt_api == 'pyqt': - prepare_pyqt4() - -elif qt_api != 'pyside': - raise RuntimeError("Invalid Qt API %r, valid values are: 'pyqt' or 'pyside'" - % qt_api) + continue + else: + raise ImportError('Cannot import PySide, PySide2, PyQt5 or PyQt4') + +# otherwise check QT_API value is valid +elif qt_api not in {api_name for api_name, module in QtAPIs}: + msg = ("Invalid Qt API %r, valid values are: " + + "'pyside, 'pyside2', 'pyqt' or 'pyqt5'") % qt_api + raise RuntimeError(msg) + +# useful constants +is_qt4 = (qt_api in {'pyqt', 'pyside'}) +is_qt5 = (qt_api in {'pyqt5', 'pyside2'}) diff -Nru python-pyface-4.5.2/pyface/qt/QtCore.py python-pyface-6.1.2/pyface/qt/QtCore.py --- python-pyface-4.5.2/pyface/qt/QtCore.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/qt/QtCore.py 2019-05-03 08:18:49.000000000 +0000 @@ -12,6 +12,23 @@ __version__ = QT_VERSION_STR __version_info__ = tuple(map(int, QT_VERSION_STR.split('.'))) +elif qt_api == 'pyqt5': + from PyQt5.QtCore import * + + from PyQt5.QtCore import pyqtProperty as Property + from PyQt5.QtCore import pyqtSignal as Signal + from PyQt5.QtCore import pyqtSlot as Slot + from PyQt5.Qt import QCoreApplication + from PyQt5.Qt import Qt + + __version__ = QT_VERSION_STR + __version_info__ = tuple(map(int, QT_VERSION_STR.split('.'))) + + +elif qt_api == 'pyside2': + from PySide2.QtCore import * + + from PySide2 import __version__, __version_info__ else: try: from PySide import __version__, __version_info__ diff -Nru python-pyface-4.5.2/pyface/qt/QtGui.py python-pyface-6.1.2/pyface/qt/QtGui.py --- python-pyface-4.5.2/pyface/qt/QtGui.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/qt/QtGui.py 2019-05-03 08:18:49.000000000 +0000 @@ -3,6 +3,30 @@ if qt_api == 'pyqt': from PyQt4.Qt import QKeySequence, QTextCursor from PyQt4.QtGui import * - + +elif qt_api == 'pyqt5': + from PyQt5.QtGui import * + from PyQt5.QtWidgets import * + from PyQt5.QtPrintSupport import * + from PyQt5.QtCore import ( + QAbstractProxyModel, QItemSelection, QItemSelectionModel, + QItemSelectionRange, QSortFilterProxyModel, QStringListModel + ) + QStyleOptionTabV2 = QStyleOptionTab + QStyleOptionTabV3 = QStyleOptionTab + QStyleOptionTabBarBaseV2 = QStyleOptionTabBarBase + +elif qt_api == 'pyside2': + from PySide2.QtGui import * + from PySide2.QtWidgets import * + from PySide2.QtPrintSupport import * + from PySide2.QtCore import ( + QAbstractProxyModel, QItemSelection, QItemSelectionModel, + QItemSelectionRange, QSortFilterProxyModel + ) + QStyleOptionTabV2 = QStyleOptionTab + QStyleOptionTabV3 = QStyleOptionTab + QStyleOptionTabBarBaseV2 = QStyleOptionTabBarBase + else: from PySide.QtGui import * diff -Nru python-pyface-4.5.2/pyface/qt/QtNetwork.py python-pyface-6.1.2/pyface/qt/QtNetwork.py --- python-pyface-4.5.2/pyface/qt/QtNetwork.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/qt/QtNetwork.py 2019-05-03 08:18:49.000000000 +0000 @@ -2,6 +2,12 @@ if qt_api == 'pyqt': from PyQt4.QtNetwork import * - + +elif qt_api == 'pyqt5': + from PyQt5.QtNetwork import * + +elif qt_api == 'pyside2': + from PySide2.QtNetwork import * + else: from PySide.QtNetwork import * diff -Nru python-pyface-4.5.2/pyface/qt/QtOpenGL.py python-pyface-6.1.2/pyface/qt/QtOpenGL.py --- python-pyface-4.5.2/pyface/qt/QtOpenGL.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/qt/QtOpenGL.py 2019-05-03 08:18:49.000000000 +0000 @@ -2,6 +2,12 @@ if qt_api == 'pyqt': from PyQt4.QtOpenGL import * - + +elif qt_api == 'pyqt5': + from PyQt5.QtOpenGL import * + +elif qt_api == 'pyside2': + from PySide2.QtOpenGL import * + else: from PySide.QtOpenGL import * diff -Nru python-pyface-4.5.2/pyface/qt/QtScript.py python-pyface-6.1.2/pyface/qt/QtScript.py --- python-pyface-4.5.2/pyface/qt/QtScript.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/qt/QtScript.py 2019-06-18 10:52:41.000000000 +0000 @@ -2,6 +2,14 @@ if qt_api == 'pyqt': from PyQt4.QtScript import * - + +elif qt_api == 'pyqt5': + import warnings + warnings.warn(DeprecationWarning("QtScript is not supported in PyQt5")) + +elif qt_api == 'pyside2': + import warnings + warnings.warn(DeprecationWarning("QtScript is not supported in PyQt5")) + else: from PySide.QtScript import * diff -Nru python-pyface-4.5.2/pyface/qt/QtSvg.py python-pyface-6.1.2/pyface/qt/QtSvg.py --- python-pyface-4.5.2/pyface/qt/QtSvg.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/qt/QtSvg.py 2019-05-03 08:18:49.000000000 +0000 @@ -2,6 +2,12 @@ if qt_api == 'pyqt': from PyQt4.QtSvg import * - + +elif qt_api == 'pyqt5': + from PyQt5.QtSvg import * + +elif qt_api == 'pyside2': + from PySide2.QtSvg import * + else: from PySide.QtSvg import * diff -Nru python-pyface-4.5.2/pyface/qt/QtTest.py python-pyface-6.1.2/pyface/qt/QtTest.py --- python-pyface-4.5.2/pyface/qt/QtTest.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/qt/QtTest.py 2019-05-03 08:18:49.000000000 +0000 @@ -2,6 +2,12 @@ if qt_api == 'pyqt': from PyQt4.QtTest import * - + +elif qt_api == 'pyqt5': + from PyQt5.QtTest import * + +elif qt_api == 'pyside2': + from PySide2.QtTest import * + else: from PySide.QtTest import * diff -Nru python-pyface-4.5.2/pyface/qt/QtWebKit.py python-pyface-6.1.2/pyface/qt/QtWebKit.py --- python-pyface-4.5.2/pyface/qt/QtWebKit.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/qt/QtWebKit.py 2019-06-18 10:52:41.000000000 +0000 @@ -2,6 +2,36 @@ if qt_api == 'pyqt': from PyQt4.QtWebKit import * - + +elif qt_api == 'pyqt5': + from PyQt5.QtWidgets import * + try: + from PyQt5.QtWebEngine import * + from PyQt5.QtWebEngineWidgets import ( + QWebEngineHistory as QWebHistory, + QWebEngineHistoryItem as QWebHistoryItem, + QWebEnginePage as QWebPage, + QWebEngineView as QWebView, + QWebEngineSettings as QWebSettings, + ) + except ImportError: + from PyQt5.QtWebKit import * + from PyQt5.QtWebKitWidgets import * + +elif qt_api == 'pyside2': + from PySide2.QtWidgets import * + # WebKit is currently in flux in PySide2 + try: + from PySide2.QtWebEngineWidgets import ( + #QWebEngineHistory as QWebHistory, + QWebEngineHistoryItem as QWebHistoryItem, + QWebEnginePage as QWebPage, + QWebEngineView as QWebView, + QWebEngineSettings as QWebSettings, + ) + except ImportError: + from PySide2.QtWebKit import * + from PySide2.QtWebKitWidgets import * + else: from PySide.QtWebKit import * diff -Nru python-pyface-4.5.2/pyface/resource/api.py python-pyface-6.1.2/pyface/resource/api.py --- python-pyface-4.5.2/pyface/resource/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/resource/api.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2005-2015, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -11,6 +11,8 @@ # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ -from resource_factory import ResourceFactory -from resource_manager import ResourceManager -from resource_path import resource_path +from __future__ import absolute_import + +from .resource_factory import ResourceFactory +from .resource_manager import ResourceManager +from .resource_path import resource_path diff -Nru python-pyface-4.5.2/pyface/resource/resource_manager.py python-pyface-6.1.2/pyface/resource/resource_manager.py --- python-pyface-4.5.2/pyface/resource/resource_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/resource/resource_manager.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,7 +15,7 @@ """ # Standard library imports. -import glob, inspect, operator, os, sys, types +import collections, glob, inspect, os, sys, types from os.path import join from zipfile import is_zipfile, ZipFile @@ -24,8 +24,9 @@ from traits.util.resource import get_path # Local imports. -from resource_factory import ResourceFactory -from resource_reference import ImageReference +from pyface.resource.resource_factory import ResourceFactory +from pyface.resource.resource_reference import ImageReference +import six class ResourceManager(HasTraits): @@ -54,12 +55,12 @@ def locate_image(self, image_name, path, size=None): """ Locates an image. """ - if not operator.isSequenceType(path): + if not isinstance(path, collections.Sequence): path = [path] resource_path = [] for item in list(path) + self.extra_paths: - if isinstance(item, basestring): + if isinstance(item, six.string_types): resource_path.append(item) elif isinstance(item, types.ModuleType): resource_path.append(item) diff -Nru python-pyface-4.5.2/pyface/resource/resource_path.py python-pyface-6.1.2/pyface/resource/resource_path.py --- python-pyface-4.5.2/pyface/resource/resource_path.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/resource/resource_path.py 2019-05-03 08:18:49.000000000 +0000 @@ -17,8 +17,7 @@ import sys -from os import getcwd -from os.path import dirname, exists +from traits.trait_base import get_resource_path def resource_module(level = 2): @@ -41,22 +40,6 @@ """Return a resource path calculated from the caller's stack. """ - module = sys._getframe(level).f_globals.get('__name__', '__main__') - - if module != '__main__': - # Return the path to the module: - try: - return dirname(getattr(sys.modules.get(module), '__file__')) - except: - # Apparently 'module' is not a registered module...treat it like - # '__main__': - pass - - # '__main__' is not a real module, so we need a work around: - for path in [ dirname(sys.argv[0] ), getcwd()]: - if exists(path): - break - - return path + return get_resource_path(level + 1) #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/resource/resource_reference.py python-pyface-6.1.2/pyface/resource/resource_reference.py --- python-pyface-4.5.2/pyface/resource/resource_reference.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/resource/resource_reference.py 2019-05-03 08:18:49.000000000 +0000 @@ -18,7 +18,7 @@ from traits.api import Any, HasTraits, Instance # Local imports. -from resource_factory import ResourceFactory +from pyface.resource.resource_factory import ResourceFactory class ResourceReference(HasTraits): diff -Nru python-pyface-4.5.2/pyface/resource_manager.py python-pyface-6.1.2/pyface/resource_manager.py --- python-pyface-4.5.2/pyface/resource_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/resource_manager.py 2019-05-03 08:18:49.000000000 +0000 @@ -13,17 +13,17 @@ #------------------------------------------------------------------------------ """ The implementation of a shared resource manager. """ +from __future__ import absolute_import # Enthought library imports. from pyface.resource.api import ResourceManager - # Import the toolkit specific version. -from toolkit import toolkit_object +from .toolkit import toolkit_object PyfaceResourceFactory = toolkit_object('resource_manager:PyfaceResourceFactory') -# A shared instance. +#: A shared instance. resource_manager = ResourceManager(resource_factory=PyfaceResourceFactory()) #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/single_choice_dialog.py python-pyface-6.1.2/pyface/single_choice_dialog.py --- python-pyface-4.5.2/pyface/single_choice_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/single_choice_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -12,88 +12,46 @@ # Description: #------------------------------------------------------------------------------ """ A dialog that allows the user to chose a single item from a list. """ -from __future__ import absolute_import -# Major package imports. -import wx +from __future__ import absolute_import -# Enthought library imports. -from traits.api import List, Str, Any +from .constant import OK +from .toolkit import toolkit_object -# Local imports. -from .dialog import Dialog +# Import the toolkit specific version. +SingleChoiceDialog = toolkit_object('single_choice_dialog:SingleChoiceDialog') -class SingleChoiceDialog(Dialog): - """ A dialog that allows the user to chose a single item from a list. - choices is the list of things to choose from. If name_attribute is - set then we assume it is a list of objects getattr(obj, name_attribute) - gives us the string to put in the dialog. Otherwise we just call str() - on the choices to get the strings. +# Convenience functions. +def choose_one(parent, message, choices, title='Choose', cancel=True): + """ Convenience method to show an information message dialog. + + Parameters + ---------- + parent : toolkit control or None + The toolkit control that should be the parent of the dialog. + message : str + The text of the message to display. + choices : list + List of objects to choose from. + title : str + The text of the dialog title. + cancel : bool + Whether or not the dialog can be cancelled. + + Returns + ------- + choice : any + The selected object, or None if cancelled. """ - - choices = List(Any) - choice = Any - name_attribute = Str - caption = Str - - ########################################################################### - # 'Window' interface. - ########################################################################### - - def close(self): - """ Closes the window. """ - - # Get the chosen object. - if self.control is not None: - self.choice = self.choices[self.control.GetSelection()] - - # Let the window close as normal. - super(SingleChoiceDialog, self).close() - - return - - ########################################################################### - # Protected 'Window' interface. - ########################################################################### - - def _create_control(self, parent): - """ Create the toolkit-specific control that represents the window. """ - - dialog = wx.SingleChoiceDialog( - parent, - self.title, - self.caption, - self._get_string_choices(), - self.STYLE - ) - - return dialog - - def _create_contents(self, parent): - """ Creates the window contents. """ - - # In this case, wx does it all for us in 'wx.SingleChoiceDialog' - pass - - ########################################################################### - # 'Private' interface. - ########################################################################### - - def _get_string_choices(self): - """ Returns the list of strings to display in the dialog. """ - - if len(self.name_attribute) > 0: - # We asssume choices is a list of objects with this attribute - choices = [ - getattr(obj, self.name_attribute) for obj in self.choices - ] - - else: - # We just convert to strings - choices = [str(obj) for obj in self.choices] - - return choices - -#### EOF ###################################################################### + dialog = SingleChoiceDialog( + parent=parent, message=message, choices=choices, title=title, + cancel=cancel + ) + result = dialog.open() + if result == OK: + choice = dialog.choice + else: + choice = None + return choice diff -Nru python-pyface-4.5.2/pyface/splash_screen_log_handler.py python-pyface-6.1.2/pyface/splash_screen_log_handler.py --- python-pyface-4.5.2/pyface/splash_screen_log_handler.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/splash_screen_log_handler.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2005-2015, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -16,27 +16,32 @@ # Standard library imports. from logging import Handler +import six class SplashScreenLogHandler(Handler): """ A log handler that displays log messages on a splash screen. """ def __init__(self, splash_screen): - """ Creates a new handler for a splash screen. """ + """ Creates a new handler for a splash screen. + Parameters + ---------- + splash_screen : ISplashScreen instance + The splash screen being used to display the log messages + """ # Base class constructor. - Handler.__init__(self) + super(SplashScreenLogHandler, self).__init__() # The splash screen that we will display log messages on. self._splash_screen = splash_screen - return - def emit(self, record): - """ Emits the log record. """ - - self._splash_screen.text = unicode(record.getMessage()) + u'...' - - return + """ Emits the log record's message to the splash screen. -#### EOF ###################################################################### + Parameters + ---------- + record : logging record instance + The log record to be displayed. + """ + self._splash_screen.text = six.text_type(record.getMessage()) + u'...' diff -Nru python-pyface-4.5.2/pyface/splash_screen.py python-pyface-6.1.2/pyface/splash_screen.py --- python-pyface-4.5.2/pyface/splash_screen.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/splash_screen.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,7 +15,9 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object SplashScreen = toolkit_object('splash_screen:SplashScreen') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/split_application_window.py python-pyface-6.1.2/pyface/split_application_window.py --- python-pyface-4.5.2/pyface/split_application_window.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/split_application_window.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,8 +15,8 @@ # Local imports. -from application_window import ApplicationWindow -from split_widget import SplitWidget +from pyface.application_window import ApplicationWindow +from pyface.split_widget import SplitWidget class SplitApplicationWindow(ApplicationWindow, SplitWidget): @@ -27,8 +27,17 @@ ########################################################################### def _create_contents(self, parent): - """ Creates the window contents. """ + """ Creates the window contents. + Parameters + ---------- + parent : toolkit control + The window's toolkit control to be used as the parent for the + splitter control. + + Returns + ------- + control : toolkit control + The splitter control to be used for contents of the window. + """ return self._create_splitter(parent) - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/split_dialog.py python-pyface-6.1.2/pyface/split_dialog.py --- python-pyface-4.5.2/pyface/split_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/split_dialog.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,8 +15,8 @@ # Local imports. -from dialog import Dialog -from split_widget import SplitWidget +from pyface.dialog import Dialog +from pyface.split_widget import SplitWidget class SplitDialog(Dialog, SplitWidget): @@ -27,8 +27,16 @@ ########################################################################### def _create_dialog_area(self, parent): - """ Creates the main content of the dialog. """ + """ Creates the main content of the dialog. + Parameters + ---------- + parent : toolkit control + A toolkit control to be used as the parent for the splitter. + + Returns + ------- + control : toolkit control + The splitter control. + """ return self._create_splitter(parent) - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/split_panel.py python-pyface-6.1.2/pyface/split_panel.py --- python-pyface-4.5.2/pyface/split_panel.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/split_panel.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,8 +15,8 @@ # Local imports. -from split_widget import SplitWidget -from widget import Widget +from pyface.split_widget import SplitWidget +from pyface.widget import Widget class SplitPanel(Widget, SplitWidget): @@ -34,7 +34,3 @@ # Create the widget's toolkit-specific control. self.control = self._create_splitter(parent) - - return - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/split_widget.py python-pyface-6.1.2/pyface/split_widget.py --- python-pyface-4.5.2/pyface/split_widget.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/split_widget.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,7 +15,9 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object SplitWidget = toolkit_object('split_widget:SplitWidget') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/system_metrics.py python-pyface-6.1.2/pyface/system_metrics.py --- python-pyface-4.5.2/pyface/system_metrics.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/system_metrics.py 2019-05-03 08:18:49.000000000 +0000 @@ -17,7 +17,9 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object SystemMetrics = toolkit_object('system_metrics:SystemMetrics') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/tasks/action/api.py python-pyface-6.1.2/pyface/tasks/action/api.py --- python-pyface-4.5.2/pyface/tasks/action/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/action/api.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,10 +1,29 @@ +# Copyright (c) 2010-18, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + +from __future__ import absolute_import + # Local imports. -from dock_pane_toggle_group import DockPaneToggleGroup -from schema import ActionSchema, GroupSchema, MenuSchema, MenuBarSchema, \ - ToolBarSchema, SGroup, SMenu, SMenuBar, SToolBar -from schema_addition import SchemaAddition -from task_action import CentralPaneAction, DockPaneAction, EditorAction, \ - TaskAction, TaskWindowAction -from task_action_controller import TaskActionController -from task_action_manager_builder import TaskActionManagerBuilder -from task_toggle_group import TaskToggleGroup +from .dock_pane_toggle_group import DockPaneToggleGroup +from .schema import ( + ActionSchema, GroupSchema, MenuSchema, MenuBarSchema, ToolBarSchema, + SGroup, SMenu, SMenuBar, SToolBar +) +from .schema_addition import SchemaAddition +from .task_action import ( + CentralPaneAction, DockPaneAction, EditorAction, TaskAction, + TaskWindowAction +) +from .task_action_controller import TaskActionController +from .task_action_manager_builder import TaskActionManagerBuilder +from .task_toggle_group import TaskToggleGroup +from .task_window_toggle_group import TaskWindowToggleGroup +from .tasks_application_action import ( + CreateTaskWindowAction, TasksApplicationAction +) diff -Nru python-pyface-4.5.2/pyface/tasks/action/listening_action.py python-pyface-6.1.2/pyface/tasks/action/listening_action.py --- python-pyface-4.5.2/pyface/tasks/action/listening_action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/action/listening_action.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,130 +1,3 @@ -# Standard library imports. -import logging +# Backward compatibility import -# Enthought library imports. -from pyface.action.api import Action -from traits.api import Any, Str - -# Logging. -logger = logging.getLogger(__name__) - - -class ListeningAction(Action): - """ An Action that listens and makes a callback to an object. - """ - - #### ListeningAction interface ############################################ - - # The (extended) name of the method to call. By default, the on_perform - # function will be called with the event. - method = Str - - # The (extended) name of the attribute that determines whether the action is - # enabled. By default, the action is always enabled when an object is set. - enabled_name = Str - - # The (extended) name of the attribute that determines whether the action is - # visible. By default, the action is always visible. - visible_name = Str - - # The object to which the names above apply. - object = Any - - ########################################################################### - # 'Action' interface. - ########################################################################### - - def destroy(self): - """ Called when the action is no longer required. - - Remove all the task listeners. - - """ - - if self.object: - self.object.on_trait_change( - self._enabled_update, self.enabled_name, remove=True - ) - self.object.on_trait_change( - self._visible_update, self.visible_name, remove=True - ) - - def perform(self, event=None): - """ Call the appropriate function. - """ - if self.method != '': - method = self._get_attr(self.object, self.method) - if method: - method() - else: - super(ListeningAction, self).perform(event) - - ########################################################################### - # Protected interface. - ########################################################################### - - def _get_attr(self, obj, name, default=None): - try: - for attr in name.split('.'): - # Perform the access in the Trait name style: if the object is - # None, assume it simply hasn't been initialized and don't show - # the warning. - if obj is None: - return default - else: - obj = getattr(obj, attr) - except AttributeError: - logger.error("Did not find name %r on %r" % (attr, obj)) - return default - return obj - - #### Trait change handlers ################################################ - - def _enabled_name_changed(self, old, new): - obj = self.object - if obj is not None: - if old: - obj.on_trait_change(self._enabled_update, old, remove=True) - if new: - obj.on_trait_change(self._enabled_update, new) - self._enabled_update() - - def _visible_name_changed(self, old, new): - obj = self.object - if obj is not None: - if old: - obj.on_trait_change(self._visible_update, old, remove=True) - if new: - obj.on_trait_change(self._visible_update, new) - self._visible_update() - - def _object_changed(self, old, new): - for kind in ('enabled', 'visible'): - method = getattr(self, '_%s_update' % kind) - name = getattr(self, '%s_name' % kind) - if name: - if old: - old.on_trait_change(method, name, remove=True) - if new: - new.on_trait_change(method, name) - method() - - def _enabled_update(self): - if self.enabled_name: - if self.object: - self.enabled = bool(self._get_attr(self.object, - self.enabled_name, False)) - else: - self.enabled = False - else: - self.enabled = bool(self.object) - - def _visible_update(self): - if self.visible_name: - if self.object: - self.visible = bool(self._get_attr(self.object, - self.visible_name, False)) - else: - self.visible = False - else: - self.visible = True +from pyface.action.listening_action import ListeningAction \ No newline at end of file diff -Nru python-pyface-4.5.2/pyface/tasks/action/schema.py python-pyface-6.1.2/pyface/tasks/action/schema.py --- python-pyface-4.5.2/pyface/tasks/action/schema.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/action/schema.py 2019-07-20 11:46:59.000000000 +0000 @@ -60,7 +60,7 @@ return [] def create(self, children): - """ Create the appropriate PyFace Action instance. """ + """ Create the appropriate Pyface Action instance. """ traits = dict(id=self.id) return self.action_factory(**traits) @@ -88,6 +88,9 @@ # The menu's user visible name. name = Unicode + # Does the menu require a separator before the menu item? + separator = Bool(False) + # The default action for tool button when shown in a toolbar (Qt only) action = Instance(Action) @@ -95,7 +98,7 @@ menu_manager_factory = Callable(MenuManager) def create(self, children): - traits = dict(id=self.id, name=self.name) + traits = dict(id=self.id, name=self.name, separator=self.separator) if self.action: traits['action'] = self.action return self.menu_manager_factory(*children, **traits) @@ -144,7 +147,7 @@ def create(self, children): traits = dict(id=self.id, name=self.name, image_size=self.image_size, - orientation=self.orientation, + orientation=self.orientation, show_divider=self.show_divider, show_tool_names=self.show_tool_names) return self.tool_bar_manager_factory(*children, **traits) diff -Nru python-pyface-4.5.2/pyface/tasks/action/task_action_controller.py python-pyface-6.1.2/pyface/tasks/action/task_action_controller.py --- python-pyface-4.5.2/pyface/tasks/action/task_action_controller.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/action/task_action_controller.py 2019-05-03 08:18:49.000000000 +0000 @@ -4,7 +4,7 @@ # Local imports. from pyface.tasks.task import Task -from task_action import TaskAction +from pyface.tasks.action.task_action import TaskAction class TaskActionController(ActionController): diff -Nru python-pyface-4.5.2/pyface/tasks/action/task_action_manager_builder.py python-pyface-6.1.2/pyface/tasks/action/task_action_manager_builder.py --- python-pyface-4.5.2/pyface/tasks/action/task_action_manager_builder.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/action/task_action_manager_builder.py 2019-05-03 08:18:49.000000000 +0000 @@ -9,8 +9,8 @@ # Local imports. from pyface.tasks.task import Task from pyface.tasks.topological_sort import before_after_sort -from schema import Schema, ToolBarSchema -from schema_addition import SchemaAddition +from pyface.tasks.action.schema import Schema, ToolBarSchema +from pyface.tasks.action.schema_addition import SchemaAddition # Logging. logger = logging.getLogger(__name__) @@ -247,7 +247,7 @@ # controller so that custom Groups, MenuManagers, etc. can get # access to their Tasks. item.controller = self.controller - + children.append(item) # Finally, create the pyface.action instance for this schema. @@ -256,5 +256,5 @@ #### Trait initializers ################################################### def _controller_default(self): - from task_action_controller import TaskActionController + from .task_action_controller import TaskActionController return TaskActionController(task=self.task) diff -Nru python-pyface-4.5.2/pyface/tasks/action/task_action.py python-pyface-6.1.2/pyface/tasks/action/task_action.py --- python-pyface-4.5.2/pyface/tasks/action/task_action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/action/task_action.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,9 +1,18 @@ +# Copyright (c) 2010-18, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + # Enthought library imports. -from pyface.tasks.api import Editor, Task, TaskPane from traits.api import Bool, Instance, Property, Str, cached_property # Local imports. -from listening_action import ListeningAction +from pyface.tasks.api import Editor, Task, TaskPane +from pyface.action.listening_action import ListeningAction class TaskAction(ListeningAction): @@ -21,7 +30,7 @@ # The Task with which the action is associated. Set by the framework. task = Instance(Task) - + ########################################################################### # Protected interface. ########################################################################### @@ -38,7 +47,7 @@ class TaskWindowAction(TaskAction): """ An Action that makes a callback to a Task's window. """ - + #### ListeningAction interface ############################################ object = Property(depends_on='task.window') @@ -51,7 +60,7 @@ if self.task: return self.task.window return None - + class CentralPaneAction(TaskAction): """ An Action that makes a callback to a Task's central pane. @@ -72,7 +81,7 @@ @cached_property def _get_central_pane(self): - if self.task: + if self.task and self.task.window is not None: return self.task.window.get_central_pane(self.task) return None @@ -102,7 +111,7 @@ @cached_property def _get_dock_pane(self): - if self.task: + if self.task and self.task.window is not None: return self.task.window.get_dock_pane(self.dock_pane_id, self.task) return None @@ -113,7 +122,7 @@ class EditorAction(CentralPaneAction): """ An action that makes a callback to the active editor in an editor pane. """ - + #### ListeningAction interface ############################################ object = Property(depends_on='active_editor') @@ -121,8 +130,9 @@ #### EditorAction interface ############################################### # The active editor in the central pane with which the action is associated. - active_editor = Property(Instance(Editor), - depends_on='central_pane.active_editor') + active_editor = Property( + Instance(Editor), depends_on='central_pane.active_editor' + ) ########################################################################### # Protected interface. diff -Nru python-pyface-4.5.2/pyface/tasks/action/tasks_application_action.py python-pyface-6.1.2/pyface/tasks/action/tasks_application_action.py --- python-pyface-4.5.2/pyface/tasks/action/tasks_application_action.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/action/tasks_application_action.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,33 @@ +from traits.api import Instance + +from pyface.action.api import GUIApplicationAction +from pyface.tasks.tasks_application import TasksApplication +from pyface.tasks.task_window_layout import TaskWindowLayout + + +class TasksApplicationAction(GUIApplicationAction): + + #: The Tasks application the action applies to. + application = Instance(TasksApplication) + + +class CreateTaskWindowAction(TasksApplicationAction): + """ A standard 'New Window' menu action. """ + name = u'New Window' + accelerator = 'Ctrl+N' + + #: The task window wayout to use when creating the new window. + layout = Instance('pyface.tasks.task_window_layout.TaskWindowLayout') + + def perform(self, event=None): + window = self.application.create_window(layout=self.layout) + self.application.add_window(window) + + def _layout_default(self): + if self.application.default_layout: + layout = self.application.default_layout[0] + else: + layout = TaskWindowLayout() + if self.task_factories: + layout.items = [self.task_factories[0].id] + return layout diff -Nru python-pyface-4.5.2/pyface/tasks/action/task_toggle_group.py python-pyface-6.1.2/pyface/tasks/action/task_toggle_group.py --- python-pyface-4.5.2/pyface/tasks/action/task_toggle_group.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/action/task_toggle_group.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,3 +1,12 @@ +# Copyright (c) 2010-18, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + # Enthought library imports. from pyface.action.api import Action, ActionItem, Group from traits.api import Any, List, Instance, Property, Unicode, on_trait_change @@ -13,14 +22,19 @@ #### 'Action' interface ################################################### + #: The user-visible name of the action, matches the task name. name = Property(Unicode, depends_on='task.name') + + #: The action is a toggle menu item. style = 'toggle' + + #: The tooltip to display for the menu item. tooltip = Property(Unicode, depends_on='name') #### 'TaskActivateAction' interface ####################################### - + task = Instance(Task) - + ########################################################################### # 'Action' interface. ########################################################################### @@ -53,8 +67,9 @@ def _update_checked(self): if self.task: window = self.task.window - self.checked = (window is not None - and window.active_task == self.task) + self.checked = ( + window is not None and window.active_task == self.task + ) class TaskToggleGroup(Group): @@ -73,16 +88,20 @@ # The window that contains the group. window = Instance(TaskWindow) - + ########################################################################### # Private interface. ########################################################################### def _get_items(self): items = [] - for task in self.window.tasks: - action = TaskToggleAction(task=task) - items.append(ActionItem(action=action)) + if len(self.window.tasks) > 1: + # at least two tasks, so something to toggle + items = [ + ActionItem( + action=TaskToggleAction(task=task), + ) for task in self.window.tasks + ] return items def _rebuild(self): @@ -92,7 +111,7 @@ # Inform our manager that it needs to be rebuilt. self.manager.changed = True - + #### Trait initializers ################################################### def _items_default(self): @@ -104,6 +123,6 @@ while isinstance(manager, Group): manager = manager.parent return manager - + def _window_default(self): - return self.manager.controller.task.window + return self.manager.controller.task.window \ No newline at end of file diff -Nru python-pyface-4.5.2/pyface/tasks/action/task_window_toggle_group.py python-pyface-6.1.2/pyface/tasks/action/task_window_toggle_group.py --- python-pyface-4.5.2/pyface/tasks/action/task_window_toggle_group.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/action/task_window_toggle_group.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,122 @@ +# Copyright (c) 2010-18, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + +# Enthought library imports. +from pyface.action.api import Action, ActionItem, Group +from traits.api import Any, Instance, List, Property, Unicode, on_trait_change + + +class TaskWindowToggleAction(Action): + """ An action for activating an application window. + """ + + # 'Action' interface ----------------------------------------------------- + + #: The name of the action for the window. + name = Property(Unicode, depends_on='window.title') + + #: The action is a toggle action. + style = 'toggle' + + # 'TaskWindowToggleAction' interface ------------------------------------- + + # The window to use for this action. + window = Instance('pyface.tasks.task_window.TaskWindow') + + # ------------------------------------------------------------------------- + # 'Action' interface. + # ------------------------------------------------------------------------- + + def perform(self, event=None): + if self.window: + self.window.activate() + + # ------------------------------------------------------------------------- + # Private interface. + # ------------------------------------------------------------------------- + + def _get_name(self): + if self.window.title: + return self.window.title + return u'' + + @on_trait_change('window:activated') + def _window_activated(self): + self.checked = True + + @on_trait_change('window:deactivated') + def _window_deactivated(self): + self.checked = False + + +class TaskWindowToggleGroup(Group): + """ A Group for toggling the activation state of an application's windows. + """ + + # 'Group' interface ------------------------------------------------------ + + #: The id of the action group. + id = 'TaskWindowToggleGroup' + + #: The actions in the action group + items = List + + # 'TaskWindowToggleGroup' interface -------------------------------------- + + #: The application that contains the group. + application = Instance('pyface.tasks.tasks_application.TasksApplication') + + #: The ActionManager to which the group belongs. + manager = Any + + # ------------------------------------------------------------------------- + # 'Group' interface. + # ------------------------------------------------------------------------- + + def destroy(self): + """ Called when the group is no longer required. + """ + super(TaskWindowToggleGroup, self).destroy() + if self.application: + self.application.on_trait_change( + self._rebuild, 'windows[]', remove=True + ) + + # ------------------------------------------------------------------------- + # Private interface. + # ------------------------------------------------------------------------- + + def _get_items(self): + items = [] + for window in self.application.windows: + active = window == self.application.active_window + action = TaskWindowToggleAction(window=window, checked=active) + items.append(ActionItem(action=action)) + return items + + def _rebuild(self): + # Clear out the old group, then build the new one. + for item in self.items: + item.destroy() + self.items = self._get_items() + + # Inform our manager that it needs to be rebuilt. + self.manager.changed = True + + # Trait initializers ----------------------------------------------------- + + def _items_default(self): + self.application.on_trait_change(self._rebuild, 'windows[]') + return self._get_items() + + def _manager_default(self): + manager = self + while isinstance(manager, Group): + manager = manager.parent + return manager diff -Nru python-pyface-4.5.2/pyface/tasks/api.py python-pyface-6.1.2/pyface/tasks/api.py --- python-pyface-4.5.2/pyface/tasks/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/api.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,3 +1,14 @@ +# Copyright (c) 2010-18, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + +from __future__ import absolute_import + # Local imports. from .advanced_editor_area_pane import AdvancedEditorAreaPane from .split_editor_area_pane import SplitEditorAreaPane @@ -12,6 +23,7 @@ from .i_editor_area_pane import IEditorAreaPane from .i_task_pane import ITaskPane from .task import Task +from .tasks_application import TasksApplication, TaskFactory from .task_layout import TaskLayout, PaneItem, Tabbed, Splitter, HSplitter, \ VSplitter from .task_pane import TaskPane diff -Nru python-pyface-4.5.2/pyface/tasks/contrib/README.txt python-pyface-6.1.2/pyface/tasks/contrib/README.txt --- python-pyface-4.5.2/pyface/tasks/contrib/README.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/contrib/README.txt 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,5 @@ +This subpackage is for Tasks components that are generic and re-usable, but not +required for the proper functioning of Tasks. + +In other words, if this subpackage were to be completely removed, there should +be no breakage in Tasks. diff -Nru python-pyface-4.5.2/pyface/tasks/i_advanced_editor_area_pane.py python-pyface-6.1.2/pyface/tasks/i_advanced_editor_area_pane.py --- python-pyface-4.5.2/pyface/tasks/i_advanced_editor_area_pane.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/i_advanced_editor_area_pane.py 2019-05-03 08:18:49.000000000 +0000 @@ -2,7 +2,7 @@ from traits.api import Interface # Local imports. -from i_editor_area_pane import IEditorAreaPane +from pyface.tasks.i_editor_area_pane import IEditorAreaPane class IAdvancedEditorAreaPane(IEditorAreaPane): @@ -29,7 +29,7 @@ The layout should have panes with IDs as described in ``get_layout()``. For example, if one wanted to open two editors side by side, with the first to the left of the right, something like this would appropriate:: - + editor_area.edit(File('foo.py')) editor_area.edit(File('bar.py')) editor_area.set_layout(VSplitter(PaneItem(0), diff -Nru python-pyface-4.5.2/pyface/tasks/i_dock_pane.py python-pyface-6.1.2/pyface/tasks/i_dock_pane.py --- python-pyface-4.5.2/pyface/tasks/i_dock_pane.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/i_dock_pane.py 2019-05-03 08:18:49.000000000 +0000 @@ -2,7 +2,7 @@ from traits.api import Bool, Enum, HasTraits, Str, Tuple # Local imports. -from i_task_pane import ITaskPane +from pyface.tasks.i_task_pane import ITaskPane class IDockPane(ITaskPane): @@ -66,6 +66,8 @@ movable = Bool(True) size = Tuple visible = Bool(False) + caption_visible = Bool(True) + dock_layer = Bool(0) ########################################################################### # 'IDockPane' interface. diff -Nru python-pyface-4.5.2/pyface/tasks/i_editor_area_pane.py python-pyface-6.1.2/pyface/tasks/i_editor_area_pane.py --- python-pyface-4.5.2/pyface/tasks/i_editor_area_pane.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/i_editor_area_pane.py 2019-05-03 08:18:49.000000000 +0000 @@ -6,8 +6,8 @@ List, Str # Local imports. -from i_editor import IEditor -from i_task_pane import ITaskPane +from pyface.tasks.i_editor import IEditor +from pyface.tasks.i_task_pane import ITaskPane # Logger. logger = logging.getLogger(__name__) @@ -49,7 +49,7 @@ def activate_editor(self, editor): """ Activates the specified editor in the pane. """ - + def add_editor(self, editor): """ Adds an editor to the pane. """ @@ -160,7 +160,7 @@ else: self.add_editor(editor) self.activate_editor(editor) - + return editor def get_editor(self, obj): @@ -174,11 +174,11 @@ def get_factory(self, obj): """ Returns an editor factory suitable for editing an object. """ - for factory, filters in self._factory_map.iteritems(): - for filter in filters: + for factory, filters in self._factory_map.items(): + for filter_ in filters: # FIXME: We should swallow exceptions, but silently? try: - if filter(obj): + if filter_(obj): return factory except: pass diff -Nru python-pyface-4.5.2/pyface/tasks/i_editor.py python-pyface-6.1.2/pyface/tasks/i_editor.py --- python-pyface-4.5.2/pyface/tasks/i_editor.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/i_editor.py 2019-07-20 11:46:59.000000000 +0000 @@ -7,35 +7,35 @@ """ The base interface for all panes (central and dock) in a Task. """ - # The editor's user-visible name. + #: The editor's user-visible name. name = Unicode - # The tooltip to show for the editor's tab, if any. + #: The tooltip to show for the editor's tab, if any. tooltip = Unicode - # The toolkit-specific control that represents the editor. + #: The toolkit-specific control that represents the editor. control = Any - # The object that the editor is editing. + #: The object that the editor is editing. obj = Any - # Has the editor's object been modified but not saved? + #: Has the editor's object been modified but not saved? dirty = Bool - # The editor area to which the editor belongs. + #: The editor area to which the editor belongs. editor_area = Instance( 'pyface.tasks.i_editor_area_pane.IEditorAreaPane') - # Is the editor active in the editor area? + #: Is the editor active in the editor area? is_active = Bool - # Does the editor currently have the focus? + #: Does the editor currently have the focus? has_focus = Bool - # Fired when the editor has been requested to close. + #: Fired when the editor has been requested to close. closing = VetoableEvent - # Fired when the editor has been closed. + #: Fired when the editor has been closed. closed = Event ########################################################################### diff -Nru python-pyface-4.5.2/pyface/tasks/i_task_pane.py python-pyface-6.1.2/pyface/tasks/i_task_pane.py --- python-pyface-4.5.2/pyface/tasks/i_task_pane.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/i_task_pane.py 2019-07-20 11:46:59.000000000 +0000 @@ -3,26 +3,26 @@ Str, Unicode # Local imports. -from task import Task +from pyface.tasks.task import Task class ITaskPane(Interface): """ The base interface for all panes (central and dock) in a Task. """ - # The pane's identifier, unique within a Task. + #: The pane's identifier, unique within a Task. id = Str - # The pane's user-visible name. + #: The pane's user-visible name. name = Unicode - # The toolkit-specific control that represents the pane. + #: The toolkit-specific control that represents the pane. control = Any - # Does the pane currently have focus? + #: Does the pane currently have focus? has_focus = Bool - # The task with which the pane is associated. Set by the framework. + #: The task with which the pane is associated. Set by the framework. task = Instance(Task) ########################################################################### diff -Nru python-pyface-4.5.2/pyface/tasks/i_task_window_backend.py python-pyface-6.1.2/pyface/tasks/i_task_window_backend.py --- python-pyface-4.5.2/pyface/tasks/i_task_window_backend.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/i_task_window_backend.py 2019-07-20 11:46:59.000000000 +0000 @@ -10,10 +10,10 @@ layout functionality. """ - # The root control of the TaskWindow to which the layout belongs. + #: The root control of the TaskWindow to which the layout belongs. control = Any - # The TaskWindow to which the layout belongs. + #: The TaskWindow to which the layout belongs. window = Instance('pyface.tasks.task_window.TaskWindow') ########################################################################### diff -Nru python-pyface-4.5.2/pyface/tasks/task_layout.py python-pyface-6.1.2/pyface/tasks/task_layout.py --- python-pyface-4.5.2/pyface/tasks/task_layout.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/task_layout.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,5 @@ # Standard library imports. -from cStringIO import StringIO +from six.moves import cStringIO as StringIO import sys # Enthought library imports. @@ -40,7 +40,7 @@ args = [(None, arg) for arg in self.pargs()] traits = [] - for name, trait in sorted(self.traits().iteritems()): + for name, trait in sorted(self.traits().items()): if not trait.pretty_skip and not trait.transient: value = getattr(self, name) if trait.default != value: @@ -74,8 +74,15 @@ items = List(pretty_skip=True) def __init__(self, *items, **traits): + # Items may either be specified as a positional arg or a kwarg. + if items: + if 'items' in traits: + raise ValueError( + "Received 'items' as positional and keyword argument." + ) + else: + traits['items'] = list(items) super(LayoutContainer, self).__init__(**traits) - self.items = list(items) def iterleaves(self): for item in self.items: diff -Nru python-pyface-4.5.2/pyface/tasks/task.py python-pyface-6.1.2/pyface/tasks/task.py --- python-pyface-4.5.2/pyface/tasks/task.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/task.py 2019-05-03 08:18:49.000000000 +0000 @@ -4,9 +4,9 @@ Unicode # Local imports. -from action.schema import MenuBarSchema, ToolBarSchema -from action.schema_addition import SchemaAddition -from task_layout import TaskLayout +from .action.schema import MenuBarSchema, ToolBarSchema +from .action.schema_addition import SchemaAddition +from pyface.tasks.task_layout import TaskLayout class Task(HasTraits): diff -Nru python-pyface-4.5.2/pyface/tasks/tasks_application.py python-pyface-6.1.2/pyface/tasks/tasks_application.py --- python-pyface-4.5.2/pyface/tasks/tasks_application.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/tasks_application.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,263 @@ +# Copyright (c) 2014-2016 by Enthought, Inc., Austin, TX +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +""" Define a base Task application class to create the event loop, and launch +the creation of tasks and corresponding windows. +""" + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +from functools import partial +import logging + +from traits.api import ( + Callable, HasStrictTraits, List, Instance, Property, Str, Unicode, + cached_property, on_trait_change +) + +from pyface.gui_application import GUIApplication + +logger = logging.getLogger(__name__) + + +class TaskFactory(HasStrictTraits): + """ A factory for creating a Task with some additional metadata. + """ + + #: The task factory's unique identifier. This ID is assigned to all tasks + #: created by the factory. + id = Str + + #: The task factory's user-visible name. + name = Unicode + + #: A callable with the following signature: + #: + #: callable(**traits) -> Task + #: + #: Often this attribute will simply be a Task subclass. + factory = Callable + + def create(self, **traits): + """ Creates the Task. + + The default implementation simply calls the 'factory' attribute. + """ + return self.factory(**traits) + + +class TasksApplication(GUIApplication): + """ A base class for Pyface tasks applications. + """ + + # ------------------------------------------------------------------------- + # 'TaskApplication' interface + # ------------------------------------------------------------------------- + + # Task management -------------------------------------------------------- + + #: List of all running tasks + tasks = List(Instance("pyface.tasks.task.Task")) + + #: Currently active Task if any. + active_task = Property(depends_on='active_window.active_task') + + #: List of all application task factories. + task_factories = List() + + #: The default layout for the application. If not specified, a single + #: window will be created with the first available task factory. + default_layout = List( + Instance('pyface.tasks.task_window_layout.TaskWindowLayout') + ) + + #: Hook to add global schema additions to tasks/windows + extra_actions = List( + Instance('pyface.tasks.action.schema_addition.SchemaAddition') + ) + + #: Hook to add global dock pane additions to tasks/windows + extra_dock_pane_factories = List(Callable) + + # Window lifecycle methods ----------------------------------------------- + + def create_task(self, id): + """ Creates the Task with the specified ID. + + Parameters + ---------- + id : str + The id of the task factory to use. + + Returns + ------- + The new Task, or None if there is not a suitable TaskFactory. + """ + factory = self._get_task_factory(id) + if factory is None: + logger.warning("Could not find task factory {}".format(id)) + return None + + task = factory.create(id=factory.id) + task.extra_actions.extend(self.extra_actions) + task.extra_dock_pane_factories.extend(self.extra_dock_pane_factories) + return task + + def create_window(self, layout=None, **kwargs): + """ Connect task to application and open task in a new window. + + Parameters + ---------- + layout : TaskLayout instance or None + The pane layout for the window. + **kwargs : dict + Additional keyword arguments to pass to the window factory. + + + Returns + ------- + window : ITaskWindow instance or None + The new TaskWindow. + """ + from pyface.tasks.task_window_layout import TaskWindowLayout + + window = super(TasksApplication, self).create_window(**kwargs) + + if layout is not None: + for task_id in layout.get_tasks(): + task = self.create_task(task_id) + if task is not None: + window.add_task(task) + else: + msg = 'Missing factory for task with ID %r' + logger.error(msg, task_id) + else: + # Create an empty layout to set default size and position only + layout = TaskWindowLayout() + + window.set_window_layout(layout) + + return window + + def _create_windows(self): + """ Create the initial windows to display from the default layout. + """ + for layout in self.default_layout: + window = self.create_window(layout) + self.add_window(window) + self.active_window = window + + # ------------------------------------------------------------------------- + # Private interface + # ------------------------------------------------------------------------- + + def _get_task_factory(self, id): + """ Returns the TaskFactory with the specified ID, or None. + """ + for factory in self.task_factories: + if factory.id == id: + return factory + return None + + # Destruction utilities --------------------------------------------------- + + @on_trait_change('windows:closed') + def _on_window_closed(self, window, trait, old, new): + """ Listener that ensures window handles are released when closed. + """ + if getattr(window, 'active_task', None) in self.tasks: + self.tasks.remove(window.active_task) + super(TasksApplication, + self)._on_window_closed(window, trait, old, new) + + # Trait initializers and property getters --------------------------------- + + def _window_factory_default(self): + """ Default to TaskWindow. + + This will be sufficient in many cases as customized behaviour comes + from the Task and the TaskWindow is just a shell. + """ + from pyface.tasks.task_window import TaskWindow + return TaskWindow + + def _default_layout_default(self): + from pyface.tasks.task_window_layout import TaskWindowLayout + window_layout = TaskWindowLayout() + if self.task_factories: + window_layout.items = [self.task_factories[0].id] + return [window_layout] + + def _extra_actions_default(self): + """ Extra application-wide menu items + + This adds a collection of standard Tasks application menu items and + groups to a Task's set of menus. Whether or not they actually appear + depends on whether the appropriate menus are provided by the Task. + + These default additions assume that the window will hold an editor pane + so that Ctrl-N and Ctrl-W will be bound to creating/closing new editors + rather than new task windows. + """ + from pyface.action.api import ( + AboutAction, CloseActiveWindowAction, ExitAction + ) + from pyface.tasks.action.api import ( + CreateTaskWindowAction, SchemaAddition, SMenu, + TaskWindowToggleGroup + ) + + return [ + SchemaAddition( + factory=CreateTaskWindowAction.factory( + application=self, + accelerator='Ctrl+Shift+N', + ), + path='MenuBar/File/new_group', + ), + SchemaAddition( + id='close_action', + factory=CloseActiveWindowAction.factory( + application=self, + accelerator='Ctrl+Shift+W', + ), + path='MenuBar/File/close_group', + ), + SchemaAddition( + id='exit_action', + factory=ExitAction.factory(application=self), + path='MenuBar/File/close_group', + absolute_position='last', + ), + SchemaAddition( + #id='Window', + factory=lambda: SMenu( + TaskWindowToggleGroup(application=self), + id='Window', + name='&Window', + ), + path='MenuBar', + after="View", + before="Help" + ), + SchemaAddition( + id='about_action', + factory=AboutAction.factory(application=self), + path='MenuBar/Help', + absolute_position='first', + ), + ] + + @cached_property + def _get_active_task(self): + if self.active_window is not None: + return getattr(self.active_window, 'active_task', None) + else: + return None diff -Nru python-pyface-4.5.2/pyface/tasks/task_window_layout.py python-pyface-6.1.2/pyface/tasks/task_window_layout.py --- python-pyface-4.5.2/pyface/tasks/task_window_layout.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/task_window_layout.py 2019-05-03 08:18:49.000000000 +0000 @@ -2,7 +2,8 @@ from traits.api import Either, List, Str, Tuple, Enum # Local imports. -from task_layout import LayoutContainer, TaskLayout +from pyface.tasks.task_layout import LayoutContainer, TaskLayout +import six class TaskWindowLayout(LayoutContainer): @@ -32,13 +33,13 @@ return self.active_task elif self.items: first = self.items[0] - return first if isinstance(first, basestring) else first.id + return first if isinstance(first, six.string_types) else first.id return None def get_tasks(self): """ Returns the IDs of the tasks in the layout. """ - return [ (item if isinstance(item, basestring) else item.id) + return [ (item if isinstance(item, six.string_types) else item.id) for item in self.items ] def is_equivalent_to(self, layout): diff -Nru python-pyface-4.5.2/pyface/tasks/task_window.py python-pyface-6.1.2/pyface/tasks/task_window.py --- python-pyface-4.5.2/pyface/tasks/task_window.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/task_window.py 2019-05-03 08:18:49.000000000 +0000 @@ -8,12 +8,13 @@ List, Property, Unicode, Vetoable, on_trait_change # Local imports. -from action.task_action_manager_builder import TaskActionManagerBuilder -from i_dock_pane import IDockPane -from i_task_pane import ITaskPane -from task import Task, TaskLayout -from task_window_backend import TaskWindowBackend -from task_window_layout import TaskWindowLayout +from pyface.tasks.action.task_action_manager_builder import TaskActionManagerBuilder +from pyface.tasks.i_dock_pane import IDockPane +from pyface.tasks.i_task_pane import ITaskPane +from pyface.tasks.task import Task, TaskLayout +from pyface.tasks.task_window_backend import TaskWindowBackend +from pyface.tasks.task_window_layout import TaskWindowLayout +import six # Logging. logger = logging.getLogger(__name__) @@ -29,7 +30,7 @@ #### IWindow interface #################################################### # Unless a title is specifically assigned, delegate to the active task. - title = Property(Unicode, depends_on='active_task, _title') + title = Property(Unicode, depends_on=['active_task.name', '_title']) #### TaskWindow interface ################################################ @@ -72,7 +73,7 @@ """ # Allow the TaskWindowBackend to clean up first. self._window_backend.destroy() - + # Don't use 'remove_task' here to avoid changing the active state and # thereby removing the window's menus and toolbars. This can lead to # undesirable animations when the window is being closed. @@ -103,22 +104,8 @@ self.show(True) self.opened = self - - return self.control is not None - - def close(self): - """ Closes the window. - Overriden to make the 'closing' event vetoable. Returns whether the - window was closed. - """ - if self.control is not None: - self.closing = event = Vetoable() - if not event.veto: - self.destroy() - self.closed = self - - return self.control is None + return self.control is not None and not event.veto ########################################################################### # Protected 'IApplicationWindow' interface. @@ -154,17 +141,20 @@ # replaced at this time. self._active_state = state task.activated() - elif not state: - logger.warn("Cannot activate task %r: task does not belong to the " - "window." % task) + logger.warn( + "Cannot activate task %r: task does not belong to the " + "window." % task + ) def add_task(self, task): """ Adds a task to the window. The task is not activated. """ if task.window is not None: - logger.error("Cannot add task %r: task has already been added " - "to a window!" % task) + logger.error( + "Cannot add task %r: task has already been added " + "to a window!" % task + ) return task.window = self @@ -210,8 +200,10 @@ self._destroy_state(state) self._states.remove(state) else: - logger.warn("Cannot remove task %r: task does not belong to the " - "window." % task) + logger.warn( + "Cannot remove task %r: task does not belong to the " + "window." % task + ) def focus_next_pane(self): """ Shifts focus to the "next" pane, taking into account the active pane @@ -291,8 +283,9 @@ def get_window_layout(self): """ Returns a TaskWindowLayout for the current state of the window. """ - result = TaskWindowLayout(position=self.position, size=self.size, - size_state=self.size_state) + result = TaskWindowLayout( + position=self.position, size=self.size, size_state=self.size_state + ) for state in self._states: if state == self._active_state: result.active_task = state.task.id @@ -313,14 +306,16 @@ # Store layouts for the tasks, including the active task. for layout in window_layout.items: - if isinstance(layout, basestring): + if isinstance(layout, six.string_types): continue state = self._get_state(layout.id) if state: state.layout = layout else: - logger.warn("Cannot apply layout for task %r: task does not " - "belong to the window." % layout.id) + logger.warn( + "Cannot apply layout for task %r: task does not " + "belong to the window." % layout.id + ) # Attempt to activate the requested task. state = self._get_state(window_layout.get_active_task()) @@ -368,8 +363,10 @@ for area in ('top', 'right', 'bottom', 'left'): item = getattr(layout, area) if item: - panes.extend([ self.get_dock_pane(pane_item.id) - for pane_item in item.iterleaves() ]) + panes.extend([ + self.get_dock_pane(pane_item.id) + for pane_item in item.iterleaves() + ]) return panes def _get_state(self, id_or_task): @@ -419,7 +416,7 @@ @on_trait_change('_states[]') def _states_updated(self): - self.tasks = [ state.task for state in self._states ] + self.tasks = [state.task for state in self._states] class TaskState(HasStrictTraits): diff -Nru python-pyface-4.5.2/pyface/tasks/tests/test_action_manager_builder.py python-pyface-6.1.2/pyface/tasks/tests/test_action_manager_builder.py --- python-pyface-4.5.2/pyface/tasks/tests/test_action_manager_builder.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/tests/test_action_manager_builder.py 2019-05-03 08:18:49.000000000 +0000 @@ -18,7 +18,7 @@ def setUp(self): """ Create some dummy actions to use while testing. """ - for i in xrange(1, 7): + for i in range(1, 7): action_id = 'action%i' % i setattr(self, action_id, Action(id=action_id, name='Action %i'%i)) @@ -44,7 +44,7 @@ children1, children2 = first.items, second.items self.assertEquals(len(children1), len(children2)) - for i in xrange(len(children1)): + for i in range(len(children1)): self.assertActionElementsEqual(children1[i], children2[i]) #### Tests ################################################################ diff -Nru python-pyface-4.5.2/pyface/tasks/tests/test_dock_pane_toggle_group.py python-pyface-6.1.2/pyface/tasks/tests/test_dock_pane_toggle_group.py --- python-pyface-4.5.2/pyface/tasks/tests/test_dock_pane_toggle_group.py 2015-07-21 14:05:50.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/tests/test_dock_pane_toggle_group.py 2019-05-03 08:18:49.000000000 +0000 @@ -5,6 +5,7 @@ from pyface.tasks.action.api import SMenu, SMenuBar, SGroup, \ DockPaneToggleGroup from pyface.tasks.api import DockPane, Task, TaskPane, TaskWindow +from pyface.gui import GUI from traits.api import List from traits.etsconfig.api import ETSConfig @@ -48,10 +49,12 @@ @unittest.skipIf(USING_WX, "TaskWindowBackend is not implemented in WX") def setUp(self): + self.gui = GUI() + # Set up the bogus task with its window. self.task = BogusTask() - window = TaskWindow() + self.window = window = TaskWindow() window.add_task(self.task) self.task_state = window._get_state(self.task) @@ -66,6 +69,18 @@ self.dock_pane_toggle_group = dock_pane_toggle_group[0] + def tearDown(self): + del self.task + del self.task_state + del self.dock_pane_toggle_group + + if self.window.control is not None: + self.window.destroy() + self.gui.process_events() + del self.window + del self.gui + + def get_dock_pane_toggle_action_names(self): names = [ action_item.action.name @@ -83,7 +98,7 @@ # Names are sorted by the group. names = self.get_dock_pane_toggle_action_names() expected_names = ['Dock Pane 1', 'Dock Pane 2'] - self.assertItemsEqual(expected_names, names) + self.assertEqual(list(sorted(expected_names)), list(sorted(names))) def test_react_to_dock_pane_added(self): # Add a dock pane to the task. @@ -97,7 +112,7 @@ # Names are sorted by the group. names = self.get_dock_pane_toggle_action_names() expected_names = ['Dock Pane 0', 'Dock Pane 1', 'Dock Pane 2'] - self.assertItemsEqual(expected_names, names) + self.assertEqual(list(sorted(expected_names)), list(sorted(names))) def test_react_to_dock_pane_removed(self): # Remove a dock pane from the task. @@ -108,7 +123,7 @@ names = self.get_dock_pane_toggle_action_names() expected_names = ['Dock Pane 1'] - self.assertItemsEqual(expected_names, names) + self.assertEqual(list(sorted(expected_names)), list(sorted(names))) if __name__ == '__main__': diff -Nru python-pyface-4.5.2/pyface/tasks/tests/test_enaml_dock_pane.py python-pyface-6.1.2/pyface/tasks/tests/test_enaml_dock_pane.py --- python-pyface-4.5.2/pyface/tasks/tests/test_enaml_dock_pane.py 2015-07-21 14:05:50.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/tests/test_enaml_dock_pane.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,11 +1,24 @@ -from traits.testing.unittest_tools import unittest +import unittest + from traits.etsconfig.api import ETSConfig +# Skip tests if Enaml is not installed or we're using the wx backend. +SKIP_REASON = None if ETSConfig.toolkit not in ['', 'qt4']: - raise unittest.SkipTest("TestEnamlDockPane: Enaml does not support WX") + SKIP_REASON = "Enaml does not support WX" +else: + try: + from enaml.widgets.api import Label + from traits_enaml.testing.gui_test_assistant import GuiTestAssistant + except ImportError: + SKIP_REASON = "Enaml not installed" + +if SKIP_REASON is not None: + # Dummy class so that the TestEnamlTaskPane class definition below + # doesn't fail. -from traits_enaml.testing.gui_test_assistant import GuiTestAssistant -from enaml.widgets.api import Label + class GuiTestAssistant(object): + pass from pyface.tasks.api import EnamlDockPane, Task @@ -16,6 +29,7 @@ return Label(text='test label') +@unittest.skipIf(SKIP_REASON is not None, SKIP_REASON) class TestEnamlDockPane(GuiTestAssistant, unittest.TestCase): ########################################################################### diff -Nru python-pyface-4.5.2/pyface/tasks/tests/test_enaml_editor.py python-pyface-6.1.2/pyface/tasks/tests/test_enaml_editor.py --- python-pyface-4.5.2/pyface/tasks/tests/test_enaml_editor.py 2015-07-21 14:05:50.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/tests/test_enaml_editor.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,14 +1,27 @@ -from traits.testing.unittest_tools import unittest -from traits.api import Str +import unittest + from traits.etsconfig.api import ETSConfig +# Skip tests if Enaml is not installed or we're using the wx backend. +SKIP_REASON = None if ETSConfig.toolkit not in ['', 'qt4']: - raise unittest.SkipTest("TestEnamlEditor: Enaml does not support WX") + SKIP_REASON = "Enaml does not support WX" +else: + try: + from enaml.widgets.api import Label + from traits_enaml.testing.gui_test_assistant import GuiTestAssistant + except ImportError: + SKIP_REASON = "Enaml not installed" + +if SKIP_REASON is not None: + # Dummy class so that the TestEnamlTaskPane class definition below + # doesn't fail. -from traits_enaml.testing.gui_test_assistant import GuiTestAssistant -from enaml.widgets.api import Label + class GuiTestAssistant(object): + pass +from traits.api import Str from pyface.tasks.api import EnamlEditor @@ -19,7 +32,7 @@ def create_component(self): return Label(text=self.obj) - +@unittest.skipIf(SKIP_REASON is not None, SKIP_REASON) class TestEnamlEditor(GuiTestAssistant, unittest.TestCase): ########################################################################### diff -Nru python-pyface-4.5.2/pyface/tasks/tests/test_enaml_task_pane.py python-pyface-6.1.2/pyface/tasks/tests/test_enaml_task_pane.py --- python-pyface-4.5.2/pyface/tasks/tests/test_enaml_task_pane.py 2015-07-21 14:05:50.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/tests/test_enaml_task_pane.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,11 +1,24 @@ -from traits.testing.unittest_tools import unittest +import unittest + from traits.etsconfig.api import ETSConfig +# Skip tests if Enaml is not installed or we're using the wx backend. +SKIP_REASON = None if ETSConfig.toolkit not in ['', 'qt4']: - raise unittest.SkipTest("TestEnamlTaskPane: Enaml does not support WX") + SKIP_REASON = "Enaml does not support WX" +else: + try: + from enaml.widgets.api import Label + from traits_enaml.testing.gui_test_assistant import GuiTestAssistant + except ImportError: + SKIP_REASON = "Enaml not installed" + +if SKIP_REASON is not None: + # Dummy class so that the TestEnamlTaskPane class definition below + # doesn't fail. -from traits_enaml.testing.gui_test_assistant import GuiTestAssistant -from enaml.widgets.api import Label + class GuiTestAssistant(object): + pass from pyface.tasks.api import EnamlTaskPane @@ -16,6 +29,7 @@ return Label(text='test label') +@unittest.skipIf(SKIP_REASON is not None, SKIP_REASON) class TestEnamlTaskPane(GuiTestAssistant, unittest.TestCase): ########################################################################### diff -Nru python-pyface-4.5.2/pyface/tasks/tests/test_task_layout.py python-pyface-6.1.2/pyface/tasks/tests/test_task_layout.py --- python-pyface-4.5.2/pyface/tasks/tests/test_task_layout.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/tests/test_task_layout.py 2019-05-03 08:18:49.000000000 +0000 @@ -3,6 +3,7 @@ # Enthought library imports. from pyface.tasks.api import HSplitter, PaneItem, Tabbed, VSplitter +from ..task_layout import LayoutContainer class LayoutItemsTestCase(unittest.TestCase): @@ -30,6 +31,22 @@ layout = VSplitter(*self.items) self.assertEqual(layout.items, self.items) + def test_layout_container_positional_items(self): + items = self.items + container = LayoutContainer(*items) + self.assertListEqual(items, container.items) + + def test_layout_container_keyword_items(self): + items = self.items + container = LayoutContainer(items=items) + self.assertListEqual(items, container.items) + + def test_layout_container_keyword_and_positional_items(self): + items = self.items + with self.assertRaises(ValueError): + LayoutContainer(*items, items=items) + + if __name__ == '__main__': unittest.main() diff -Nru python-pyface-4.5.2/pyface/tasks/tests/test_tasks_application.py python-pyface-6.1.2/pyface/tasks/tests/test_tasks_application.py --- python-pyface-4.5.2/pyface/tasks/tests/test_tasks_application.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/tests/test_tasks_application.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,130 @@ +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +import unittest + +from traits.api import Bool + +from pyface.application_window import ApplicationWindow +from pyface.toolkit import toolkit_object + +from ..tasks_application import TasksApplication + +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') + +EVENTS = [ + 'starting', 'started', 'application_initialized', 'stopping', 'stopped' +] + + +class TestingApp(TasksApplication): + + #: Whether the app should start cleanly. + start_cleanly = Bool(True) + + #: Whether the app should stop cleanly. + stop_cleanly = Bool(True) + + #: Whether to try invoking exit method. + do_exit = Bool(False) + + #: Whether the exit should be invoked as an error exit. + error_exit = Bool(False) + + #: Whether to try force the exit (ie. ignore vetoes). + force_exit = Bool(False) + + #: Whether to veto a call to the exit method. + veto_exit = Bool(False) + + #: Whether to veto a closing a window. + veto_close = Bool(False) + + #: Whether or not a call to the exit method was vetoed. + exit_vetoed = Bool(False) + + #: Whether exit preparation happened. + exit_prepared = Bool(False) + + #: Whether exit preparation raises an error. + exit_prepared_error = Bool(False) + + def start(self): + if not self.start_cleanly: + return False + super(TestingApp, self).start() + + window = self.windows[0] + window.on_trait_change(self._on_window_closing, 'closing') + return True + + def stop(self): + super(TestingApp, self).stop() + return self.stop_cleanly + + def _on_window_closing(self, window, trait, old, new): + if self.veto_close_window and not self.exit_vetoed: + new.veto = True + self.exit_vetoed = True + + def _exiting_fired(self, event): + event.veto = self.veto_exit + self.exit_vetoed = self.veto_exit + + def _prepare_exit(self): + if not self.exit_vetoed: + self.exit_prepared = True + if self.exit_prepared_error: + raise Exception("Exit preparation failed") + super(TestingApp, self)._prepare_exit() + + +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestApplication(unittest.TestCase, GuiTestAssistant): + def setUp(self): + GuiTestAssistant.setUp(self) + self.application_events = [] + + if toolkit_object.toolkit == 'wx': + import wx + self.event_loop() + wx.GetApp().DeletePendingEvents() + else: + self.event_loop() + + def tearDown(self): + GuiTestAssistant.tearDown(self) + + def event_listener(self, event): + self.application_events.append(event) + + def connect_listeners(self, app): + for event in EVENTS: + app.on_trait_change(self.event_listener, event) + + def test_defaults(self): + from traits.etsconfig.api import ETSConfig + + app = TasksApplication() + + self.assertEqual(app.home, ETSConfig.application_home) + self.assertEqual(app.user_data, ETSConfig.user_data) + self.assertEqual(app.company, ETSConfig.company) + + def test_lifecycle(self): + + app = TasksApplication() + self.connect_listeners(app) + window = ApplicationWindow() + app.on_trait_change(lambda: app.add_window(window), 'started') + + with self.assertMultiTraitChanges([app], EVENTS, []): + self.gui.invoke_after(1000, app.exit) + result = app.run() + + self.assertTrue(result) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS) + self.assertEqual(app.windows, []) diff -Nru python-pyface-4.5.2/pyface/tasks/tests/test_task_window.py python-pyface-6.1.2/pyface/tasks/tests/test_task_window.py --- python-pyface-4.5.2/pyface/tasks/tests/test_task_window.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/tests/test_task_window.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,153 @@ +import unittest + +from traits.testing.unittest_tools import UnittestTools +from pyface.tasks.api import Task +from ..task_window import TaskWindow + + + +def _task_window_with_named_tasks(*names, **kwargs): + tasks = [Task(name=name) for name in names] + + first_active = kwargs.pop('first_active', False) + if first_active: + kwargs['active_task'] = tasks[0] + + task = TaskWindow(tasks=tasks, **kwargs) + return task + + +class TestTaskWindow(unittest.TestCase, UnittestTools): + + def test_title_default(self): + task_window = TaskWindow() + + # default is empty + self.assertEqual(task_window.title, '') + + def test_title_no_active_task(self): + task_window = _task_window_with_named_tasks( + 'Test Task', 'Test Task 2') + + # should be empty + self.assertEqual(task_window.title, '') + + def test_title_activate_task(self): + task_window = _task_window_with_named_tasks('Test Task') + task = task_window.tasks[0] + + # activate task + with self.assertTraitChanges(task_window, 'title', count=1): + task_window.active_task = task + self.assertEqual(task_window.title, 'Test Task') + + def test_title_change_active_task_name(self): + task_window = _task_window_with_named_tasks( + 'Test Task', first_active=True) + task_1 = task_window.tasks[0] + + # change task name + with self.assertTraitChanges(task_window, 'title', count=1): + task_1.name = 'Changed Name' + self.assertEqual(task_window.title, 'Changed Name') + + def test_title_change_active_task(self): + task_window = _task_window_with_named_tasks( + 'Test Task 1', 'Test Task 2', first_active=True) + task = task_window.tasks[1] + + # change active task + with self.assertTraitChanges(task_window, 'title', count=1): + task_window.active_task = task + self.assertEqual(task_window.title, 'Test Task 2') + + def test_title_change_deactivate_task(self): + task_window = _task_window_with_named_tasks( + 'Test Task 1', first_active=True) + + # change active task + with self.assertTraitChanges(task_window, 'title', count=1): + task_window.active_task = None + self.assertEqual(task_window.title, '') + + def test_set_title_no_tasks(self): + task_window = _task_window_with_named_tasks() + + # set window title + with self.assertTraitChanges(task_window, 'title', count=1): + task_window.title = "Window title" + self.assertEqual(task_window.title, "Window title") + + def test_set_title_change_title(self): + task_window = _task_window_with_named_tasks(title="Window Title") + + # set window title + with self.assertTraitChanges(task_window, 'title', count=1): + task_window.title = "New Window title" + self.assertEqual(task_window.title, "New Window title") + + def test_set_title_no_active_task(self): + task_window = _task_window_with_named_tasks('Test Task') + + # set window title + with self.assertTraitChanges(task_window, 'title', count=1): + task_window.title = "Window title" + self.assertEqual(task_window.title, "Window title") + + def test_set_title_active_task(self): + task_window = _task_window_with_named_tasks( + 'Test Task', first_active=True) + + # set window title + with self.assertTraitChanges(task_window, 'title', count=1): + task_window.title = "Window title" + self.assertEqual(task_window.title, "Window title") + + def test_set_title_activate_task(self): + task_window = _task_window_with_named_tasks( + 'Test Task', title="Window title") + task = task_window.tasks[0] + + # change activate task (trait fires, no window title change) + with self.assertTraitChanges(task_window, 'title', count=1): + task_window.active_task = task + self.assertEqual(task_window.title, "Window title") + + def test_set_title_change_active_task_name(self): + task_window = _task_window_with_named_tasks( + 'Test Task', title="Window title", first_active=True) + task = task_window.tasks[0] + + # change task name (trait fires, no window title change) + with self.assertTraitChanges(task_window, 'title', count=1): + task.name = 'Changed Name' + self.assertEqual(task_window.title, "Window title") + + def test_set_title_change_active_task(self): + task_window = _task_window_with_named_tasks( + 'Test Task', 'Test Task 2', title="Window title", + active_first=True) + task = task_window.tasks[1] + + # change task name (trait fires, no window title change) + with self.assertTraitChanges(task_window, 'title', count=1): + task_window.active_task = task + self.assertEqual(task_window.title, "Window title") + + def test_reset_title_active_task(self): + task_window = _task_window_with_named_tasks( + 'Test Task', title="Window title", first_active=True) + + # reset window title + with self.assertTraitChanges(task_window, 'title', count=1): + task_window.title = "" + self.assertEqual(task_window.title, "Test Task") + + def test_reset_title(self): + task_window = _task_window_with_named_tasks( + 'Test Task', title="Window title") + + # set window title + with self.assertTraitChanges(task_window, 'title', count=1): + task_window.title = "" + self.assertEqual(task_window.title, "") diff -Nru python-pyface-4.5.2/pyface/tasks/tests/test_topological_sort.py python-pyface-6.1.2/pyface/tasks/tests/test_topological_sort.py --- python-pyface-4.5.2/pyface/tasks/tests/test_topological_sort.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/tests/test_topological_sort.py 2019-05-03 08:18:49.000000000 +0000 @@ -16,6 +16,9 @@ def __init__(self, id, **traits): super(TestItem, self).__init__(id=id, **traits) + def __hash__(self): + return hash(self.id) + def __eq__(self, other): return self.id == other.id diff -Nru python-pyface-4.5.2/pyface/tasks/topological_sort.py python-pyface-6.1.2/pyface/tasks/topological_sort.py --- python-pyface-4.5.2/pyface/tasks/topological_sort.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/topological_sort.py 2019-05-03 08:18:49.000000000 +0000 @@ -79,7 +79,7 @@ # Descend through graph, removing parents as we go. for parent in result: - if graph.has_key(parent): + if parent in graph: for child in graph[parent]: num_parents[child] -= 1 if num_parents[child] == 0: @@ -89,5 +89,5 @@ # If there's a cycle, just throw in whatever is left over. has_cycle = bool(graph) if has_cycle: - result.extend(graph.keys()) + result.extend(list(graph.keys())) return result, has_cycle diff -Nru python-pyface-4.5.2/pyface/tasks/traits_dock_pane.py python-pyface-6.1.2/pyface/tasks/traits_dock_pane.py --- python-pyface-4.5.2/pyface/tasks/traits_dock_pane.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/traits_dock_pane.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,9 +1,8 @@ # Enthought library imports. from traits.api import HasTraits, Instance -from traitsui.api import UI # Local imports. -from dock_pane import DockPane +from pyface.tasks.dock_pane import DockPane class TraitsDockPane(DockPane): @@ -16,7 +15,7 @@ model = Instance(HasTraits) # The UI object associated with the Traits view, if it has been constructed. - ui = Instance(UI) + ui = Instance('traitsui.ui.UI') ########################################################################### # 'HasTraits' interface. diff -Nru python-pyface-4.5.2/pyface/tasks/traits_editor.py python-pyface-6.1.2/pyface/tasks/traits_editor.py --- python-pyface-4.5.2/pyface/tasks/traits_editor.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/traits_editor.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,9 +1,8 @@ # Enthought library imports. from traits.api import HasTraits, Instance -from traitsui.api import UI # Local imports. -from editor import Editor +from pyface.tasks.editor import Editor class TraitsEditor(Editor): @@ -16,7 +15,7 @@ model = Instance(HasTraits) # The UI object associated with the Traits view, if it has been constructed. - ui = Instance(UI) + ui = Instance('traitsui.ui.UI') ########################################################################### # 'HasTraits' interface. @@ -26,7 +25,7 @@ """ Use the model object for the Traits UI context, if appropriate. """ if self.model: - return { 'object': self.model, 'editor': self } + return {'object': self.model, 'editor': self} return super(TraitsEditor, self).trait_context() ########################################################################### @@ -43,5 +42,6 @@ """ Destroy the toolkit-specific control that represents the editor. """ self.control = None - self.ui.dispose() + if self.ui is not None: + self.ui.dispose() self.ui = None diff -Nru python-pyface-4.5.2/pyface/tasks/traits_task_pane.py python-pyface-6.1.2/pyface/tasks/traits_task_pane.py --- python-pyface-4.5.2/pyface/tasks/traits_task_pane.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tasks/traits_task_pane.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,9 +1,8 @@ # Enthought library imports. from traits.api import HasTraits, Instance -from traitsui.api import UI # Local imports. -from task_pane import TaskPane +from .task_pane import TaskPane class TraitsTaskPane(TaskPane): @@ -16,7 +15,7 @@ model = Instance(HasTraits) # The UI object associated with the Traits view, if it has been constructed. - ui = Instance(UI) + ui = Instance('traitsui.ui.UI') ########################################################################### # 'HasTraits' interface. diff -Nru python-pyface-4.5.2/pyface/tests/test_about_dialog.py python-pyface-6.1.2/pyface/tests/test_about_dialog.py --- python-pyface-4.5.2/pyface/tests/test_about_dialog.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_about_dialog.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,6 +1,6 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest +import unittest from ..about_dialog import AboutDialog from ..constant import OK, CANCEL @@ -8,42 +8,52 @@ from ..toolkit import toolkit_object from ..window import Window -ModalDialogTester = toolkit_object('util.modal_dialog_tester:ModalDialogTester') -no_modal_dialog_tester = (ModalDialogTester.__name__ == 'Unimplemented') +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') +ModalDialogTester = toolkit_object( + 'util.modal_dialog_tester:ModalDialogTester' +) +no_modal_dialog_tester = (ModalDialogTester.__name__ == 'Unimplemented') -class TestAboutDialog(unittest.TestCase): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestAboutDialog(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.dialog = AboutDialog() + def tearDown(self): + if self.dialog.control is not None: + with self.delete_widget(self.dialog.control): + self.dialog.destroy() + self.dialog = None + GuiTestAssistant.tearDown(self) + def test_create(self): # test that creation and destruction works as expected - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_destroy(self): # test that destroy works even when no control - self.dialog.destroy() + with self.event_loop(): + self.dialog.destroy() def test_create_parent(self): # test that creation and destruction works as expected with a parent parent = Window() self.dialog.parent = parent.control - parent._create() - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() - parent.destroy() - - def test_create_ok_renamed(self): - # test that creation and destruction works as expected with ok_label - self.dialog.ok_label = u"Sure" - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + parent._create() + self.dialog._create() + + with self.event_loop(): + self.dialog.destroy() + with self.event_loop(): + parent.destroy() @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_accept(self): @@ -64,23 +74,6 @@ self.assertEqual(self.dialog.return_code, CANCEL) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') - def test_ok(self): - # test that OK works as expected - tester = ModalDialogTester(self.dialog.open) - tester.open_and_wait(when_opened=lambda x: x.click_button(OK)) - self.assertEqual(tester.result, OK) - self.assertEqual(self.dialog.return_code, OK) - - @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') - def test_renamed_ok(self): - self.dialog.ok_label = u"Sure" - # test that OK works as expected if renamed - tester = ModalDialogTester(self.dialog.open) - tester.open_and_wait(when_opened=lambda x: x.click_widget(u"Sure")) - self.assertEqual(tester.result, OK) - self.assertEqual(self.dialog.return_code, OK) - - @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_parent(self): # test that lifecycle works with a parent parent = Window() @@ -88,6 +81,8 @@ parent.open() tester = ModalDialogTester(self.dialog.open) tester.open_and_run(when_opened=lambda x: x.close(accept=True)) - parent.close() + with self.event_loop(): + parent.close() + self.assertEqual(tester.result, OK) self.assertEqual(self.dialog.return_code, OK) diff -Nru python-pyface-4.5.2/pyface/tests/test_application.py python-pyface-6.1.2/pyface/tests/test_application.py --- python-pyface-4.5.2/pyface/tests/test_application.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_application.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,211 @@ +# Copyright (c) 2014-2018 by Enthought, Inc., Austin, TX +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +import os +from shutil import rmtree +from tempfile import mkdtemp +from unittest import TestCase + +from traits.api import Bool +from traits.testing.unittest_tools import UnittestTools + +from ..application import ApplicationExit, Application + +EVENTS = [ + 'starting', 'started', 'application_initialized', 'stopping', 'stopped' +] + + +class TestingApp(Application): + + #: Whether the app should start cleanly. + start_cleanly = Bool(True) + + #: Whether the app should stop cleanly. + stop_cleanly = Bool(True) + + #: Whether to try invoking exit method. + do_exit = Bool(False) + + #: Whether the exit should be invoked as an error exit. + error_exit = Bool(False) + + #: Whether to try force the exit (ie. ignore vetoes). + force_exit = Bool(False) + + #: Whether to veto a call to the exit method. + veto_exit = Bool(False) + + #: Whether or not a call to the exit method was vetoed. + exit_vetoed = Bool(False) + + #: Whether exit preparation happened. + exit_prepared = Bool(False) + + #: Whether exit preparation raises an error. + exit_prepared_error = Bool(False) + + def start(self): + super(TestingApp, self).start() + return self.start_cleanly + + def stop(self): + super(TestingApp, self).stop() + return self.stop_cleanly + + def _run(self): + super(TestingApp, self)._run() + if self.do_exit: + if self.error_exit: + raise ApplicationExit("error message") + else: + self.exit(self.force_exit) + self.exit_vetoed = True + return True + + def _exiting_fired(self, event): + event.veto = self.veto_exit + + def _prepare_exit(self): + self.exit_prepared = True + if self.exit_prepared_error: + raise Exception("Exit preparation failed") + + +class TestApplication(TestCase, UnittestTools): + def setUp(self): + self.application_events = [] + + def event_listener(self, event): + self.application_events.append(event) + + def connect_listeners(self, app): + for event in EVENTS: + app.on_trait_change(self.event_listener, event) + + def test_defaults(self): + from traits.etsconfig.api import ETSConfig + + app = Application() + + self.assertEqual(app.home, ETSConfig.application_home) + self.assertEqual(app.user_data, ETSConfig.user_data) + self.assertEqual(app.company, ETSConfig.company) + + def test_initialize_application_home(self): + dirpath = mkdtemp() + home = os.path.join(dirpath, "test") + app = Application(home=home) + + app.initialize_application_home() + try: + self.assertTrue(os.path.exists(home)) + finally: + rmtree(dirpath) + + def test_lifecycle(self): + app = Application() + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS, []): + result = app.run() + + self.assertTrue(result) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS) + + def test_exit(self): + app = TestingApp(do_exit=True) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS, []): + result = app.run() + + self.assertTrue(result) + self.assertFalse(app.exit_vetoed) + self.assertTrue(app.exit_prepared) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS) + + def test_exit_prepare_error(self): + app = TestingApp(do_exit=True, exit_prepared_error=True) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS, []): + result = app.run() + + self.assertTrue(result) + self.assertFalse(app.exit_vetoed) + self.assertTrue(app.exit_prepared) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS) + + def test_veto_exit(self): + app = TestingApp(do_exit=True, veto_exit=True) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS, []): + result = app.run() + + self.assertTrue(result) + self.assertTrue(app.exit_vetoed) + self.assertFalse(app.exit_prepared) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS) + + def test_force_exit(self): + app = TestingApp(do_exit=True, force_exit=True, veto_exit=True) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS, []): + result = app.run() + + self.assertTrue(result) + self.assertFalse(app.exit_vetoed) + self.assertTrue(app.exit_prepared) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS) + + def test_error_exit(self): + app = TestingApp(do_exit=True, error_exit=True) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS, []): + result = app.run() + + self.assertFalse(result) + self.assertFalse(app.exit_vetoed) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS) + + def test_bad_start(self): + app = TestingApp(start_cleanly=False) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS[:1], EVENTS[1:]): + result = app.run() + + self.assertFalse(result) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS[:1]) + + def test_bad_stop(self): + app = TestingApp(stop_cleanly=False) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS[:-1], EVENTS[-1:]): + result = app.run() + + self.assertFalse(result) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS[:-1]) \ No newline at end of file diff -Nru python-pyface-4.5.2/pyface/tests/test_application_window.py python-pyface-6.1.2/pyface/tests/test_application_window.py --- python-pyface-4.5.2/pyface/tests/test_application_window.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_application_window.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,95 +1,111 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest, UnittestTools +import unittest from ..action.api import Action, MenuManager, MenuBarManager, StatusBarManager, ToolBarManager from ..application_window import ApplicationWindow -from ..gui import GUI +from ..toolkit import toolkit_object from ..image_resource import ImageResource +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') -class TestApplicationWindow(unittest.TestCase, UnittestTools): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestApplicationWindow(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.window = ApplicationWindow() - def test_destroy(self): - # test that destroy works even when no control - self.window.destroy() + def tearDown(self): + if self.window.control is not None: + with self.delete_widget(self.window.control): + self.window.destroy() + GuiTestAssistant.tearDown(self) + + def test_close(self): + # test that close works even when no control + self.window.close() def test_open_close(self): # test that opening and closing works as expected with self.assertTraitChanges(self.window, 'opening', count=1): with self.assertTraitChanges(self.window, 'opened', count=1): - self.window.open() - self.gui.process_events() + with self.event_loop(): + self.window.open() with self.assertTraitChanges(self.window, 'closing', count=1): with self.assertTraitChanges(self.window, 'closed', count=1): - self.window.close() - self.gui.process_events() + with self.event_loop(): + self.window.close() def test_show(self): # test that show and hide works as expected - self.window._create() - self.window.show(True) - self.gui.process_events() - self.window.show(False) - self.gui.process_events() - self.window.destroy() + with self.event_loop(): + self.window._create() + self.window.show(True) + with self.event_loop(): + self.window.show(False) + with self.event_loop(): + self.window.close() def test_activate(self): # test that activation works as expected - self.window.open() - self.gui.process_events() - self.window.activate() - self.gui.process_events() - self.window.close() + with self.event_loop(): + self.window.open() + with self.event_loop(): + self.window.activate() + with self.event_loop(): + self.window.close() def test_position(self): # test that default position works as expected self.window.position = (100, 100) - self.window.open() - self.gui.process_events() - self.window.close() + with self.event_loop(): + self.window.open() + with self.event_loop(): + self.window.close() def test_reposition(self): # test that changing position works as expected - self.window.open() - self.gui.process_events() - self.window.position = (100, 100) - self.gui.process_events() - self.window.close() + with self.event_loop(): + self.window.open() + with self.event_loop(): + self.window.position = (100, 100) + with self.event_loop(): + self.window.close() def test_size(self): # test that default size works as expected self.window.size = (100, 100) - self.window.open() - self.gui.process_events() - self.window.close() + with self.event_loop(): + self.window.open() + with self.event_loop(): + self.window.close() def test_resize(self): # test that changing size works as expected self.window.open() - self.gui.process_events() - self.window.size = (100, 100) - self.gui.process_events() - self.window.close() + with self.event_loop(): + self.window.size = (100, 100) + with self.event_loop(): + self.window.close() def test_title(self): # test that default title works as expected self.window.title = "Test Title" - self.window.open() - self.gui.process_events() - self.window.close() + with self.event_loop(): + self.window.open() + with self.event_loop(): + self.window.close() def test_retitle(self): # test that changing title works as expected - self.window.open() - self.gui.process_events() - self.window.title = "Test Title" - self.gui.process_events() - self.window.close() + with self.event_loop(): + self.window.open() + with self.event_loop(): + self.window.title = "Test Title" + with self.event_loop(): + self.window.close() def test_menubar(self): # test that menubar gets created as expected @@ -103,47 +119,105 @@ name='File', ) ) - self.window._create() - self.window.show(True) - self.gui.process_events() - self.window.show(False) - self.gui.process_events() - self.window.destroy() + with self.event_loop(): + self.window._create() + with self.event_loop(): + self.window.show(True) + with self.event_loop(): + self.window.show(False) + with self.event_loop(): + self.window.close() def test_toolbar(self): # test that toolbar gets created as expected - self.window.tool_bar_manager = ToolBarManager( - Action(name="New", image=ImageResource('core')), - Action(name="Open", image=ImageResource('core')), - Action(name="Save", image=ImageResource('core')), - Action(name="Close", image=ImageResource('core')), - Action(name="Quit", image=ImageResource('core')), - ) - self.window._create() - self.window.show(True) - self.gui.process_events() - self.window.show(False) - self.gui.process_events() - self.window.destroy() + self.window.tool_bar_managers = [ + ToolBarManager( + Action(name="New", image=ImageResource('core')), + Action(name="Open", image=ImageResource('core')), + Action(name="Save", image=ImageResource('core')), + Action(name="Close", image=ImageResource('core')), + Action(name="Quit", image=ImageResource('core')), + ) + ] + with self.event_loop(): + self.window._create() + with self.event_loop(): + self.window.show(True) + with self.event_loop(): + self.window.show(False) + with self.event_loop(): + self.window.close() + + def test_toolbar_changed(self): + # test that toolbar gets changed as expected + self.window.tool_bar_managers = [ + ToolBarManager( + Action(name="New", image=ImageResource('core')), + Action(name="Open", image=ImageResource('core')), + Action(name="Save", image=ImageResource('core')), + Action(name="Close", image=ImageResource('core')), + Action(name="Quit", image=ImageResource('core')), + ) + ] + with self.event_loop(): + self.window._create() + with self.event_loop(): + self.window.show(True) + with self.event_loop(): + self.window.tool_bar_managers = [ + ToolBarManager( + Action(name="New", image=ImageResource('core')), + Action(name="Open", image=ImageResource('core')), + Action(name="Save", image=ImageResource('core')), + Action(name="Close", image=ImageResource('core')), + Action(name="Quit", image=ImageResource('core')), + ) + ] + with self.event_loop(): + self.window.show(False) + with self.event_loop(): + self.window.close() def test_statusbar(self): # test that status bar gets created as expected self.window.status_bar_manager = StatusBarManager( message="hello world", ) - self.window._create() - self.window.show(True) - self.gui.process_events() - self.window.show(False) - self.gui.process_events() - self.window.destroy() + with self.event_loop(): + self.window._create() + with self.event_loop(): + self.window.show(True) + with self.event_loop(): + self.window.show(False) + with self.event_loop(): + self.window.close() + + def test_statusbar_changed(self): + # test that status bar gets changed as expected + self.window.status_bar_manager = StatusBarManager( + message="hello world", + ) + with self.event_loop(): + self.window._create() + with self.event_loop(): + self.window.show(True) + with self.event_loop(): + self.window.status_bar_manager = StatusBarManager( + message="goodbye world", + ) + with self.event_loop(): + self.window.show(False) + with self.event_loop(): + self.window.close() def test_icon(self): # test that status bar gets created as expected self.window.icon = ImageResource('core') - self.window._create() - self.window.show(True) - self.gui.process_events() - self.window.show(False) - self.gui.process_events() - self.window.destroy() + with self.event_loop(): + self.window._create() + with self.event_loop(): + self.window.show(True) + with self.event_loop(): + self.window.show(False) + with self.event_loop(): + self.window.close() diff -Nru python-pyface-4.5.2/pyface/tests/test_base_toolkit.py python-pyface-6.1.2/pyface/tests/test_base_toolkit.py --- python-pyface-4.5.2/pyface/tests/test_base_toolkit.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_base_toolkit.py 2019-06-14 12:22:56.000000000 +0000 @@ -0,0 +1,51 @@ +import unittest + +from traits.etsconfig.api import ETSConfig + +from pyface.base_toolkit import find_toolkit, import_toolkit + + +class TestToolkit(unittest.TestCase): + + def test_import_null_toolkit(self): + toolkit = import_toolkit('null') + self.assertEqual(toolkit.package, 'pyface') + self.assertEqual(toolkit.toolkit, 'null') + + def test_missing_toolkit(self): + # test that we get an error with an undefined toolkit + with self.assertRaises(RuntimeError): + import_toolkit('nosuchtoolkit') + + def test_find_current_toolkit_no_etsconfig(self): + old_etsconfig_toolkit = ETSConfig._toolkit + ETSConfig._toolkit = '' + try: + toolkit = find_toolkit('pyface.toolkits', old_etsconfig_toolkit) + self.assertEqual(toolkit.package, 'pyface') + self.assertEqual(toolkit.toolkit, old_etsconfig_toolkit) + self.assertEqual(ETSConfig.toolkit, old_etsconfig_toolkit) + finally: + ETSConfig._toolkit = old_etsconfig_toolkit + + def test_find_null_toolkit_no_etsconfig(self): + old_etsconfig_toolkit = ETSConfig._toolkit + ETSConfig._toolkit = '' + try: + toolkit = find_toolkit('pyface.toolkits', 'null') + self.assertEqual(toolkit.package, 'pyface') + self.assertEqual(toolkit.toolkit, 'null') + self.assertEqual(ETSConfig.toolkit, 'null') + finally: + ETSConfig._toolkit = old_etsconfig_toolkit + + def test_find_nonexistent_toolkit_no_etsconfig(self): + old_etsconfig_toolkit = ETSConfig._toolkit + ETSConfig._toolkit = '' + try: + toolkit = find_toolkit('pyface.toolkits', 'nonexistent') + self.assertEqual(toolkit.package, 'pyface') + self.assertEqual(toolkit.toolkit, 'null') + self.assertEqual(ETSConfig.toolkit, 'null') + finally: + ETSConfig._toolkit = old_etsconfig_toolkit diff -Nru python-pyface-4.5.2/pyface/tests/test_beep.py python-pyface-6.1.2/pyface/tests/test_beep.py --- python-pyface-4.5.2/pyface/tests/test_beep.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_beep.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,6 +1,8 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest, UnittestTools +import unittest + +from traits.testing.unittest_tools import UnittestTools from ..beep import beep diff -Nru python-pyface-4.5.2/pyface/tests/test_clipboard.py python-pyface-6.1.2/pyface/tests/test_clipboard.py --- python-pyface-4.5.2/pyface/tests/test_clipboard.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_clipboard.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,6 +1,6 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest +import unittest from ..clipboard import clipboard diff -Nru python-pyface-4.5.2/pyface/tests/test_confirmation_dialog.py python-pyface-6.1.2/pyface/tests/test_confirmation_dialog.py --- python-pyface-4.5.2/pyface/tests/test_confirmation_dialog.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_confirmation_dialog.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,94 +1,141 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest +import platform +import unittest from ..confirmation_dialog import ConfirmationDialog, confirm from ..constant import YES, NO, OK, CANCEL -from ..gui import GUI from ..image_resource import ImageResource from ..toolkit import toolkit_object from ..window import Window -ModalDialogTester = toolkit_object('util.modal_dialog_tester:ModalDialogTester') +is_qt = toolkit_object.toolkit == 'qt4' +if is_qt: + from pyface.qt import qt_api + +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') + +ModalDialogTester = toolkit_object( + 'util.modal_dialog_tester:ModalDialogTester' +) no_modal_dialog_tester = (ModalDialogTester.__name__ == 'Unimplemented') +is_pyqt5 = (is_qt and qt_api == 'pyqt5') +is_pyqt4_linux = (is_qt and qt_api == 'pyqt' and platform.system() == 'Linux') -class TestConfirmationDialog(unittest.TestCase): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestConfirmationDialog(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.dialog = ConfirmationDialog() + def tearDown(self): + if self.dialog.control is not None: + with self.delete_widget(self.dialog.control): + self.dialog.destroy() + self.dialog = None + GuiTestAssistant.tearDown(self) + def test_create(self): # test that creation and destruction works as expected - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_destroy(self): # test that destroy works even when no control - self.dialog.destroy() + with self.event_loop(): + self.dialog.destroy() + + def test_size(self): + # test that size works as expected + self.dialog.size = (100, 100) + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() + + def test_position(self): + # test that position works as expected + self.dialog.position = (100, 100) + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_create_parent(self): # test that creation and destruction works as expected with a parent - parent = Window() - self.dialog.parent = parent.control - parent._create() - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() - parent.destroy() + with self.event_loop(): + parent = Window() + self.dialog.parent = parent.control + parent._create() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() + with self.event_loop(): + parent.destroy() def test_create_yes_renamed(self): # test that creation and destruction works as expected with ok_label self.dialog.yes_label = u"Sure" - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_create_no_renamed(self): # test that creation and destruction works as expected with ok_label self.dialog.no_label = u"No Way" - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_create_yes_default(self): # test that creation and destruction works as expected with ok_label self.dialog.default = YES - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_create_cancel(self): # test that creation and destruction works with cancel button self.dialog.cancel = True - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_create_cancel_renamed(self): # test that creation and destruction works with cancel button self.dialog.cancel = True self.dialog.cancel_label = "Back" - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_create_cancel_default(self): # test that creation and destruction works as expected with ok_label self.dialog.cancel = True self.dialog.default = CANCEL - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_create_image(self): # test that creation and destruction works with a non-standard image self.dialog.image = ImageResource('core') - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_close(self): @@ -96,6 +143,7 @@ # XXX duplicate of Dialog test, not needed? tester = ModalDialogTester(self.dialog.open) tester.open_and_run(when_opened=lambda x: self.dialog.close()) + self.assertEqual(tester.result, NO) self.assertEqual(self.dialog.return_code, NO) @@ -105,52 +153,100 @@ self.dialog.cancel = True tester = ModalDialogTester(self.dialog.open) tester.open_and_run(when_opened=lambda x: self.dialog.close()) + self.assertEqual(tester.result, CANCEL) self.assertEqual(self.dialog.return_code, CANCEL) + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_yes(self): # test that Yes works as expected tester = ModalDialogTester(self.dialog.open) tester.open_and_wait(when_opened=lambda x: x.click_button(YES)) + self.assertEqual(tester.result, YES) self.assertEqual(self.dialog.return_code, YES) + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_renamed_yes(self): self.dialog.yes_label = u"Sure" # test that Yes works as expected if renamed tester = ModalDialogTester(self.dialog.open) tester.open_and_wait(when_opened=lambda x: x.click_widget(u"Sure")) + self.assertEqual(tester.result, YES) self.assertEqual(self.dialog.return_code, YES) + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_no(self): # test that No works as expected tester = ModalDialogTester(self.dialog.open) tester.open_and_wait(when_opened=lambda x: x.click_button(NO)) + self.assertEqual(tester.result, NO) self.assertEqual(self.dialog.return_code, NO) + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_renamed_no(self): self.dialog.no_label = u"No way" # test that No works as expected if renamed tester = ModalDialogTester(self.dialog.open) tester.open_and_wait(when_opened=lambda x: x.click_widget(u"No way")) + self.assertEqual(tester.result, NO) self.assertEqual(self.dialog.return_code, NO) + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_cancel(self): self.dialog.cancel = True # test that Cancel works as expected tester = ModalDialogTester(self.dialog.open) tester.open_and_wait(when_opened=lambda x: x.click_button(CANCEL)) + self.assertEqual(tester.result, CANCEL) self.assertEqual(self.dialog.return_code, CANCEL) + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_cancel_renamed(self): self.dialog.cancel = True @@ -158,6 +254,7 @@ # test that Cancel works as expected tester = ModalDialogTester(self.dialog.open) tester.open_and_wait(when_opened=lambda x: x.click_widget(u"Back")) + self.assertEqual(tester.result, CANCEL) self.assertEqual(self.dialog.return_code, CANCEL) @@ -166,69 +263,129 @@ # test that lifecycle works with a parent parent = Window() self.dialog.parent = parent.control - parent.open() + with self.event_loop(): + parent.open() tester = ModalDialogTester(self.dialog.open) tester.open_and_run(when_opened=lambda x: x.close(accept=True)) - parent.close() + with self.event_loop(): + parent.close() + self.assertEqual(tester.result, OK) self.assertEqual(self.dialog.return_code, OK) -class TestConfirm(unittest.TestCase): - +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestConfirm(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) + + def tearDown(self): + GuiTestAssistant.tearDown(self) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_reject(self): # test that cancel works as expected - tester = ModalDialogTester(lambda: confirm(None, "message", cancel=True)) + tester = ModalDialogTester( + lambda: confirm(None, "message", cancel=True) + ) tester.open_and_run(when_opened=lambda x: x.close(accept=False)) + self.assertEqual(tester.result, CANCEL) + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_yes(self): # test that yes works as expected tester = ModalDialogTester(lambda: confirm(None, "message")) tester.open_and_wait(when_opened=lambda x: x.click_button(YES)) - self.gui.process_events() + self.assertEqual(tester.result, YES) + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_no(self): # test that yes works as expected tester = ModalDialogTester(lambda: confirm(None, "message")) tester.open_and_wait(when_opened=lambda x: x.click_button(NO)) - self.gui.process_events() + self.assertEqual(tester.result, NO) + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_cancel(self): # test that cancel works as expected - tester = ModalDialogTester(lambda: confirm(None, "message", cancel=True)) + tester = ModalDialogTester( + lambda: confirm(None, "message", cancel=True) + ) tester.open_and_wait(when_opened=lambda x: x.click_button(CANCEL)) - self.gui.process_events() + self.assertEqual(tester.result, CANCEL) + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_title(self): # test that title works as expected - tester = ModalDialogTester(lambda: confirm(None, "message", - title='Title')) + tester = ModalDialogTester( + lambda: confirm(None, "message", title='Title') + ) tester.open_and_run(when_opened=lambda x: x.click_button(NO)) + self.assertEqual(tester.result, NO) + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_default_yes(self): # test that default works as expected - tester = ModalDialogTester(lambda: confirm(None, "message", default=YES)) + tester = ModalDialogTester( + lambda: confirm(None, "message", default=YES) + ) tester.open_and_run(when_opened=lambda x: x.click_button(YES)) + self.assertEqual(tester.result, YES) + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_default_cancel(self): # test that default works as expected - tester = ModalDialogTester(lambda: confirm(None, "message", - cancel=True, default=YES)) + tester = ModalDialogTester( + lambda: confirm(None, "message", cancel=True, default=YES) + ) tester.open_and_run(when_opened=lambda x: x.click_button(CANCEL)) + self.assertEqual(tester.result, CANCEL) diff -Nru python-pyface-4.5.2/pyface/tests/test_dialog.py python-pyface-6.1.2/pyface/tests/test_dialog.py --- python-pyface-4.5.2/pyface/tests/test_dialog.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_dialog.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,73 +1,108 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest +import platform +import unittest from ..dialog import Dialog from ..constant import OK, CANCEL -from ..gui import GUI from ..toolkit import toolkit_object -ModalDialogTester = toolkit_object('util.modal_dialog_tester:ModalDialogTester') +is_qt = toolkit_object.toolkit == 'qt4' +if is_qt: + from pyface.qt import qt_api + +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') + +ModalDialogTester = toolkit_object( + 'util.modal_dialog_tester:ModalDialogTester' +) no_modal_dialog_tester = (ModalDialogTester.__name__ == 'Unimplemented') +is_pyqt5 = (is_qt and qt_api == 'pyqt5') +is_pyqt4_linux = (is_qt and qt_api == 'pyqt' and platform.system() == 'Linux') -class TestDialog(unittest.TestCase): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestDialog(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.dialog = Dialog() + def tearDown(self): + if self.dialog.control is not None: + with self.delete_widget(self.dialog.control): + self.dialog.destroy() + self.dialog = None + GuiTestAssistant.tearDown(self) + def test_create(self): # test that creation and destruction works as expected - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_destroy(self): # test that destroy works even when no control - self.dialog.destroy() + with self.event_loop(): + self.dialog.destroy() def test_size(self): - # test that default size works as expected + # test that size works as expected self.dialog.size = (100, 100) - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() + + def test_position(self): + # test that position works as expected + self.dialog.position = (100, 100) + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_create_ok_renamed(self): # test that creation and destruction works as expected with ok_label self.dialog.ok_label = u"Sure" - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_create_cancel_renamed(self): # test that creation and destruction works as expected with cancel_label self.dialog.cancel_label = u"I Don't Think So" - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_create_help(self): # test that creation and destruction works as expected with help self.dialog.help_id = "test_help" - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_create_help_label(self): # test that creation and destruction works as expected with help self.dialog.help_id = "test_help" self.dialog.help_label = u"Assistance" - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_accept(self): # test that accept works as expected tester = ModalDialogTester(self.dialog.open) tester.open_and_run(when_opened=lambda x: x.close(accept=True)) + self.assertEqual(tester.result, OK) self.assertEqual(self.dialog.return_code, OK) @@ -76,6 +111,7 @@ # test that reject works as expected tester = ModalDialogTester(self.dialog.open) tester.open_and_run(when_opened=lambda x: x.close(accept=False)) + self.assertEqual(tester.result, CANCEL) self.assertEqual(self.dialog.return_code, CANCEL) @@ -84,43 +120,85 @@ # test that closing works as expected tester = ModalDialogTester(self.dialog.open) tester.open_and_run(when_opened=lambda x: self.dialog.close()) + self.assertEqual(tester.result, CANCEL) self.assertEqual(self.dialog.return_code, CANCEL) + @unittest.skipIf( + is_pyqt5, "Dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_ok(self): # test that OK works as expected tester = ModalDialogTester(self.dialog.open) tester.open_and_wait(when_opened=lambda x: x.click_button(OK)) + self.assertEqual(tester.result, OK) self.assertEqual(self.dialog.return_code, OK) + @unittest.skipIf( + is_pyqt5, "Dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_cancel(self): # test that cancel works as expected tester = ModalDialogTester(self.dialog.open) tester.open_and_run(when_opened=lambda x: x.click_button(CANCEL)) + self.assertEqual(tester.result, CANCEL) self.assertEqual(self.dialog.return_code, CANCEL) + @unittest.skipIf( + is_pyqt5, "Dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_renamed_ok(self): self.dialog.ok_label = u"Sure" # test that OK works as expected if renames tester = ModalDialogTester(self.dialog.open) tester.open_and_wait(when_opened=lambda x: x.click_widget(u"Sure")) + self.assertEqual(tester.result, OK) self.assertEqual(self.dialog.return_code, OK) + @unittest.skipIf( + is_pyqt5, "Dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_renamed_cancel(self): self.dialog.cancel_label = u"I Don't Think So" # test that OK works as expected if renames tester = ModalDialogTester(self.dialog.open) - tester.open_and_wait(when_opened=lambda x: x.click_widget(u"I Don't Think So")) + tester.open_and_wait( + when_opened=lambda x: x.click_widget(u"I Don't Think So") + ) + self.assertEqual(tester.result, CANCEL) self.assertEqual(self.dialog.return_code, CANCEL) + @unittest.skipIf( + is_pyqt5, "Dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_help(self): def click_help_and_close(tester): @@ -131,9 +209,17 @@ # test that OK works as expected if renames tester = ModalDialogTester(self.dialog.open) tester.open_and_wait(when_opened=click_help_and_close) + self.assertEqual(tester.result, OK) self.assertEqual(self.dialog.return_code, OK) + @unittest.skipIf( + is_pyqt5, "Dialog click tests don't work on pyqt5." + ) # noqa + @unittest.skipIf( + is_pyqt4_linux, + "Dialog click tests don't work reliably on linux. Issue #282." + ) # noqa @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_renamed_help(self): def click_help_and_close(tester): @@ -145,6 +231,7 @@ # test that OK works as expected if renames tester = ModalDialogTester(self.dialog.open) tester.open_and_wait(when_opened=click_help_and_close) + self.assertEqual(tester.result, OK) self.assertEqual(self.dialog.return_code, OK) @@ -152,9 +239,10 @@ # test that closing works as expected self.dialog.style = 'nonmodal' result = self.dialog.open() - self.gui.process_events() - self.dialog.close() - self.gui.process_events() + + with self.event_loop(): + self.dialog.close() + self.assertEqual(result, OK) self.assertEqual(self.dialog.return_code, OK) @@ -163,9 +251,10 @@ # XXX use nonmodal for better cross-platform coverage self.dialog.style = 'nonmodal' self.dialog.resizable = False - result = self.dialog.open() - self.gui.process_events() - self.dialog.close() - self.gui.process_events() + with self.event_loop(): + result = self.dialog.open() + with self.event_loop(): + self.dialog.close() + self.assertEqual(result, OK) self.assertEqual(self.dialog.return_code, OK) diff -Nru python-pyface-4.5.2/pyface/tests/test_directory_dialog.py python-pyface-6.1.2/pyface/tests/test_directory_dialog.py --- python-pyface-4.5.2/pyface/tests/test_directory_dialog.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_directory_dialog.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,58 +1,75 @@ from __future__ import absolute_import import os - -from traits.testing.unittest_tools import unittest +import unittest from ..directory_dialog import DirectoryDialog from ..gui import GUI from ..toolkit import toolkit_object -ModalDialogTester = toolkit_object('util.modal_dialog_tester:ModalDialogTester') -no_modal_dialog_tester = (ModalDialogTester.__name__ == 'Unimplemented') +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') +ModalDialogTester = toolkit_object( + 'util.modal_dialog_tester:ModalDialogTester' +) +no_modal_dialog_tester = (ModalDialogTester.__name__ == 'Unimplemented') -class TestDirectoryDialog(unittest.TestCase): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestDirectoryDialog(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.dialog = DirectoryDialog() + def tearDown(self): + if self.dialog.control is not None: + with self.delete_widget(self.dialog.control): + self.dialog.destroy() + del self.dialog + GuiTestAssistant.tearDown(self) + def test_create(self): # test that creation and destruction works as expected - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_destroy(self): # test that destroy works even when no control - self.dialog.destroy() + with self.event_loop(): + self.dialog.destroy() def test_close(self): # test that close works - self.dialog._create() - self.gui.process_events() - self.dialog.close() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.close() def test_default_path(self): # test that default path works self.dialog.default_path = os.path.join('images', 'core.png') - self.dialog._create() - self.gui.process_events() - self.dialog.close() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.close() def test_no_new_directory(self): # test that block on new directories works self.dialog.new_directory = False - self.dialog._create() - self.gui.process_events() - self.dialog.close() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.close() def test_message(self): # test that message setting works self.dialog.message = 'Select a directory' - self.dialog._create() - self.gui.process_events() - self.dialog.close() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.close() #XXX would be nice to actually test with an open dialog, but not right now diff -Nru python-pyface-4.5.2/pyface/tests/test_file_dialog.py python-pyface-6.1.2/pyface/tests/test_file_dialog.py --- python-pyface-4.5.2/pyface/tests/test_file_dialog.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_file_dialog.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,75 +1,94 @@ from __future__ import absolute_import import os - -from traits.testing.unittest_tools import unittest +import unittest from ..file_dialog import FileDialog from ..gui import GUI from ..toolkit import toolkit_object -ModalDialogTester = toolkit_object('util.modal_dialog_tester:ModalDialogTester') -no_modal_dialog_tester = (ModalDialogTester.__name__ == 'Unimplemented') +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') +ModalDialogTester = toolkit_object( + 'util.modal_dialog_tester:ModalDialogTester' +) +no_modal_dialog_tester = (ModalDialogTester.__name__ == 'Unimplemented') -class TestFileDialog(unittest.TestCase): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestFileDialog(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.dialog = FileDialog() + def tearDown(self): + if self.dialog.control is not None: + with self.delete_widget(self.dialog.control): + self.dialog.destroy() + del self.dialog + GuiTestAssistant.tearDown(self) + def test_create_wildcard(self): wildcard = FileDialog.create_wildcard('Python', '*.py') self.assertTrue(len(wildcard) != 0) def test_create_wildcard_multiple(self): wildcard = FileDialog.create_wildcard( - 'Python', ['*.py', '*.pyo', '*.pyc', '*.pyd']) + 'Python', ['*.py', '*.pyo', '*.pyc', '*.pyd'] + ) self.assertTrue(len(wildcard) != 0) def test_create(self): # test that creation and destruction works as expected - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_destroy(self): # test that destroy works even when no control - self.dialog.destroy() + with self.event_loop(): + self.dialog.destroy() def test_close(self): # test that close works - self.dialog._create() - self.gui.process_events() - self.dialog.close() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.close() def test_default_path(self): # test that default path works self.dialog.default_path = os.path.join('images', 'core.png') - self.dialog._create() - self.gui.process_events() - self.dialog.close() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.close() def test_default_dir_and_file(self): # test that default dir and path works self.dialog.default_directory = 'images' self.dialog.default_filename = 'core.png' - self.dialog._create() - self.gui.process_events() - self.dialog.close() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.close() def test_open_files(self): # test that open files action works self.dialog.action = 'open files' - self.dialog._create() - self.gui.process_events() - self.dialog.close() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.close() def test_save_as(self): # test that open files action works self.dialog.action = 'save as' - self.dialog._create() - self.gui.process_events() - self.dialog.close() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.close() #XXX would be nice to actually test with an open dialog, but not right now diff -Nru python-pyface-4.5.2/pyface/tests/test_gui_application.py python-pyface-6.1.2/pyface/tests/test_gui_application.py --- python-pyface-4.5.2/pyface/tests/test_gui_application.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_gui_application.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,286 @@ +# Copyright (c) 2014-2018 by Enthought, Inc., Austin, TX +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +import os +from shutil import rmtree +from tempfile import mkdtemp +import unittest + +from traits.api import Bool, on_trait_change + +from ..application_window import ApplicationWindow +from ..gui_application import GUIApplication +from ..toolkit import toolkit_object + +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') + +EVENTS = [ + 'starting', 'started', 'application_initialized', 'stopping', 'stopped' +] + + +class TestingApp(GUIApplication): + + #: Whether the app should start cleanly. + start_cleanly = Bool(True) + + #: Whether the app should stop cleanly. + stop_cleanly = Bool(True) + + #: Whether to try invoking exit method. + do_exit = Bool(False) + + #: Whether the exit should be invoked as an error exit. + error_exit = Bool(False) + + #: Whether to try force the exit (ie. ignore vetoes). + force_exit = Bool(False) + + #: Whether to veto a call to the exit method. + veto_exit = Bool(False) + + #: Whether to veto a opening a window. + veto_open_window = Bool(False) + + #: Whether to veto a closing a window. + veto_close_window = Bool(False) + + #: Whether or not a call to the open a window was vetoed. + window_open_vetoed = Bool(False) + + #: Whether or not a call to the exit method was vetoed. + exit_vetoed = Bool(False) + + #: Whether exit preparation happened. + exit_prepared = Bool(False) + + #: Whether exit preparation raises an error. + exit_prepared_error = Bool(False) + + def start(self): + if not self.start_cleanly: + return False + super(TestingApp, self).start() + + window = self.windows[0] + window.on_trait_change(self._on_window_closing, 'closing') + return True + + def stop(self): + super(TestingApp, self).stop() + return self.stop_cleanly + + def _on_window_closing(self, window, trait, old, new): + if self.veto_close_window and not self.exit_vetoed: + new.veto = True + self.exit_vetoed = True + + def _application_initialized_fired(self): + self.window_open_vetoed = ( + len(self.windows) > 0 and self.windows[0].control is None + ) + + def _exiting_fired(self, event): + event.veto = self.veto_exit + self.exit_vetoed = self.veto_exit + + def _prepare_exit(self): + super(TestingApp, self)._prepare_exit() + if not self.exit_vetoed: + self.exit_prepared = True + if self.exit_prepared_error: + raise Exception("Exit preparation failed") + + @on_trait_change('windows:opening') + def _on_activate_window(self, event): + if self.veto_open_window: + event.veto = self.veto_open_window + + +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestGUIApplication(unittest.TestCase, GuiTestAssistant): + def setUp(self): + GuiTestAssistant.setUp(self) + self.application_events = [] + + if toolkit_object.toolkit == 'wx': + import wx + self.event_loop() + wx.GetApp().DeletePendingEvents() + else: + self.event_loop() + + def tearDown(self): + GuiTestAssistant.tearDown(self) + + def event_listener(self, event): + self.application_events.append(event) + + def connect_listeners(self, app): + for event in EVENTS: + app.on_trait_change(self.event_listener, event) + + def test_defaults(self): + from traits.etsconfig.api import ETSConfig + + app = GUIApplication() + + self.assertEqual(app.home, ETSConfig.application_home) + self.assertEqual(app.user_data, ETSConfig.user_data) + self.assertEqual(app.company, ETSConfig.company) + + def test_initialize_application_home(self): + dirpath = mkdtemp() + home = os.path.join(dirpath, "test") + app = GUIApplication(home=home) + + app.initialize_application_home() + try: + self.assertTrue(os.path.exists(home)) + finally: + rmtree(dirpath) + + def test_lifecycle(self): + + app = GUIApplication() + self.connect_listeners(app) + window = ApplicationWindow() + app.on_trait_change(lambda: app.add_window(window), 'started') + + with self.assertMultiTraitChanges([app], EVENTS, []): + self.gui.invoke_after(1000, app.exit) + result = app.run() + + self.assertTrue(result) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS) + self.assertEqual(app.windows, []) + + def test_exit_prepare_error(self): + app = TestingApp(exit_prepared_error=True) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS, []): + self.gui.invoke_after(1000, app.exit) + result = app.run() + + self.assertTrue(result) + self.assertFalse(app.exit_vetoed) + self.assertTrue(app.exit_prepared) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS) + self.assertEqual(app.windows, []) + + def test_veto_exit(self): + app = TestingApp(veto_exit=True) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS, []): + self.gui.invoke_after(1000, app.exit) + self.gui.invoke_after(2000, app.exit, force=True) + result = app.run() + + self.assertTrue(result) + self.assertTrue(app.exit_vetoed) + self.assertFalse(app.exit_prepared) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS) + self.assertEqual(app.windows, []) + + def test_veto_open_window(self): + app = TestingApp(veto_open_window=True) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS, []): + self.gui.invoke_after(1000, app.exit) + result = app.run() + + self.assertTrue(result) + self.assertTrue(app.window_open_vetoed) + self.assertFalse(app.exit_vetoed) + self.assertTrue(app.exit_prepared) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS) + self.assertEqual(app.windows, []) + + def test_veto_close_window(self): + app = TestingApp(veto_close_window=True) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS, []): + self.gui.invoke_after(1000, app.exit) + self.gui.invoke_after(2000, app.exit, force=True) + result = app.run() + + self.assertTrue(result) + self.assertTrue(app.exit_vetoed) + self.assertFalse(app.exit_prepared) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS) + self.assertEqual(app.windows, []) + + def test_force_exit(self): + app = TestingApp(do_exit=True, force_exit=True, veto_exit=True) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS, []): + self.gui.invoke_after(100, app.exit, True) + result = app.run() + + self.assertTrue(result) + self.assertFalse(app.exit_vetoed) + self.assertTrue(app.exit_prepared) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS) + self.assertEqual(app.windows, []) + + def test_force_exit_close_veto(self): + app = TestingApp(do_exit=True, force_exit=True, veto_close_window=True) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS, []): + self.gui.invoke_after(1000, app.exit, True) + result = app.run() + + self.assertTrue(result) + self.assertFalse(app.exit_vetoed) + self.assertTrue(app.exit_prepared) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS) + self.assertEqual(app.windows, []) + + def test_bad_start(self): + app = TestingApp(start_cleanly=False) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS[:1], EVENTS[1:]): + result = app.run() + + self.assertFalse(result) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS[:1]) + self.assertEqual(app.windows, []) + + def test_bad_stop(self): + app = TestingApp(stop_cleanly=False) + self.connect_listeners(app) + + with self.assertMultiTraitChanges([app], EVENTS[:-1], EVENTS[-1:]): + self.gui.invoke_after(1000, app.exit, True) + result = app.run() + + self.assertFalse(result) + event_order = [event.event_type for event in self.application_events] + self.assertEqual(event_order, EVENTS[:-1]) + self.assertEqual(app.windows, []) diff -Nru python-pyface-4.5.2/pyface/tests/test_heading_text.py python-pyface-6.1.2/pyface/tests/test_heading_text.py --- python-pyface-4.5.2/pyface/tests/test_heading_text.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_heading_text.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,52 +1,66 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest +import unittest -from ..gui import GUI from ..heading_text import HeadingText from ..image_resource import ImageResource +from ..toolkit import toolkit_object from ..window import Window +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') -class TestHeadingText(unittest.TestCase): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestHeadingText(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.window = Window() self.window._create() def tearDown(self): - self.widget.destroy() - self.window.destroy() + if self.widget.control is not None: + with self.delete_widget(self.widget.control): + self.widget.destroy() + + if self.window.control is not None: + with self.delete_widget(self.window.control): + self.window.destroy() + + del self.widget + del self.window + GuiTestAssistant.tearDown(self) def test_lifecycle(self): # test that destroy works - self.widget = HeadingText(self.window.control) - self.gui.process_events() - self.widget.destroy() - self.gui.process_events() + with self.event_loop(): + self.widget = HeadingText(self.window.control) + with self.event_loop(): + self.widget.destroy() def test_message(self): # test that create works with message - self.widget = HeadingText(self.window.control, text="Hello") - self.gui.process_events() - self.widget.destroy() - self.gui.process_events() + with self.event_loop(): + self.widget = HeadingText(self.window.control, text="Hello") + with self.event_loop(): + self.widget.destroy() def test_image(self): # test that image works # XXX this image doesn't make sense here, but that's fine # XXX this isn't implemented in qt4 backend, but shouldn't fail - self.widget = HeadingText(self.window.control, image=ImageResource('core.png')) - self.gui.process_events() - self.widget.destroy() - self.gui.process_events() + with self.event_loop(): + self.widget = HeadingText( + self.window.control, image=ImageResource('core.png') + ) + with self.event_loop(): + self.widget.destroy() def test_level(self): # test that create works with level # XXX this image doesn't make sense here, but that's fine # XXX this isn't implemented in qt4 backend, but shouldn't fail - self.widget = HeadingText(self.window.control, level=2) - self.gui.process_events() - self.widget.destroy() - self.gui.process_events() + with self.event_loop(): + self.widget = HeadingText(self.window.control, level=2) + with self.event_loop(): + self.widget.destroy() diff -Nru python-pyface-4.5.2/pyface/tests/test_image_cache.py python-pyface-6.1.2/pyface/tests/test_image_cache.py --- python-pyface-4.5.2/pyface/tests/test_image_cache.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_image_cache.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,8 +1,7 @@ from __future__ import absolute_import import os - -from traits.testing.unittest_tools import unittest +import unittest from ..image_cache import ImageCache diff -Nru python-pyface-4.5.2/pyface/tests/test_image_resource.py python-pyface-6.1.2/pyface/tests/test_image_resource.py --- python-pyface-4.5.2/pyface/tests/test_image_resource.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_image_resource.py 2019-06-14 12:22:56.000000000 +0000 @@ -0,0 +1,93 @@ +from __future__ import absolute_import + +import os +import platform +import pkg_resources +import unittest + +import pyface +import pyface.tests +from ..image_resource import ImageResource +from ..toolkit import toolkit_object + + +is_qt = toolkit_object.toolkit == 'qt4' +if is_qt: + from pyface.qt import qt_api +is_pyqt4_windows = (is_qt and qt_api == 'pyqt' and platform.system() == 'Windows') + + +SEARCH_PATH = pkg_resources.resource_filename('pyface', 'images') +IMAGE_DIR = pkg_resources.resource_filename(__name__, 'images') +IMAGE_PATH = os.path.join(IMAGE_DIR, 'core.png') + + +class TestImageResource(unittest.TestCase): + + def setUp(self): + # clear cached "not found" image + ImageResource._image_not_found = None + + def test_create_image(self): + image_resource = ImageResource('core') + image = image_resource.create_image() + self.assertIsNotNone(image) + self.assertEqual(image_resource.absolute_path, IMAGE_PATH) + + def test_create_image_again(self): + image_resource = ImageResource('core') + image = image_resource.create_image() + self.assertIsNotNone(image) + self.assertEqual(image_resource.absolute_path, IMAGE_PATH) + + def test_create_image_search_path(self): + image_resource = ImageResource('splash.jpg', [SEARCH_PATH]) + self.assertEqual(image_resource.search_path, + [SEARCH_PATH, pyface.tests]) + image = image_resource.create_image() + self.assertIsNotNone(image) + self.assertEqual(image_resource.absolute_path, + os.path.join(SEARCH_PATH, 'splash.jpg')) + + def test_create_image_search_path_string(self): + image_resource = ImageResource('splash.jpg', SEARCH_PATH) + self.assertEqual(image_resource.search_path, + [SEARCH_PATH, pyface.tests]) + image = image_resource.create_image() + self.assertIsNotNone(image) + self.assertEqual(image_resource.absolute_path, + os.path.join(SEARCH_PATH, 'splash.jpg')) + + def test_create_image_missing(self): + image_resource = ImageResource('doesnt_exist.png') + image = image_resource.create_image() + self.assertIsNotNone(image) + self.assertIsNotNone(image_resource._image_not_found) + + def test_create_bitmap(self): + image_resource = ImageResource('core.png') + image = image_resource.create_bitmap() + self.assertIsNotNone(image) + self.assertEqual(image_resource.absolute_path, IMAGE_PATH) + + def test_create_icon(self): + image_resource = ImageResource('core.png') + image = image_resource.create_icon() + self.assertIsNotNone(image) + self.assertEqual(image_resource.absolute_path, IMAGE_PATH) + + def test_image_size(self): + image_resource = ImageResource('core') + image = image_resource.create_image() + size = image_resource.image_size(image) + self.assertEqual(image_resource._ref.filename, IMAGE_PATH) + self.assertEqual(size, (64, 64)) + + @unittest.skipIf(is_pyqt4_windows, "QPixmap bug returns (0, 0). Issue #301.") # noqa + def test_image_size_search_path(self): + image_resource = ImageResource('splash.jpg', [SEARCH_PATH]) + image = image_resource.create_image() + size = image_resource.image_size(image) + self.assertEqual(image_resource.absolute_path, + os.path.join(SEARCH_PATH, 'splash.jpg')) + self.assertEqual(size, (450, 296)) diff -Nru python-pyface-4.5.2/pyface/tests/test_message_dialog.py python-pyface-6.1.2/pyface/tests/test_message_dialog.py --- python-pyface-4.5.2/pyface/tests/test_message_dialog.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_message_dialog.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,90 +1,141 @@ from __future__ import absolute_import -from traits.etsconfig.api import ETSConfig -from traits.testing.unittest_tools import unittest +import platform +import unittest -from ..message_dialog import MessageDialog -from ..constant import OK, CANCEL -from ..gui import GUI +from ..message_dialog import MessageDialog, information, warning, error +from ..constant import OK from ..toolkit import toolkit_object from ..window import Window -ModalDialogTester = toolkit_object('util.modal_dialog_tester:ModalDialogTester') +is_qt = toolkit_object.toolkit == 'qt4' +if is_qt: + from pyface.qt import qt_api + +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') + +ModalDialogTester = toolkit_object( + 'util.modal_dialog_tester:ModalDialogTester' +) no_modal_dialog_tester = (ModalDialogTester.__name__ == 'Unimplemented') -USING_QT = ETSConfig.toolkit not in ['', 'wx'] +is_pyqt5 = (is_qt and qt_api == 'pyqt5') +is_pyqt4_linux = (is_qt and qt_api == 'pyqt' and platform.system() == 'Linux') -class TestMessageDialog(unittest.TestCase): +USING_QT = is_qt + +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestMessageDialog(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.dialog = MessageDialog() + def tearDown(self): + if self.dialog.control is not None: + with self.delete_widget(self.dialog.control): + self.dialog.destroy() + del self.dialog + GuiTestAssistant.tearDown(self) + def test_create(self): # test that creation and destruction works as expected - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_destroy(self): # test that destroy works even when no control - self.dialog.destroy() + with self.event_loop(): + self.dialog.destroy() + + def test_size(self): + # test that size works as expected + self.dialog.size = (100, 100) + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() + + def test_position(self): + # test that position works as expected + self.dialog.position = (100, 100) + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_create_parent(self): # test that creation and destruction works as expected with a parent parent = Window() self.dialog.parent = parent.control - parent._create() - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() - parent.destroy() + with self.event_loop(): + parent._create() + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() + parent.destroy() def test_create_ok_renamed(self): # test that creation and destruction works as expected with ok_label self.dialog.ok_label = u"Sure" - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_message(self): # test that creation and destruction works as expected with message self.dialog.message = u"This is the message" - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_informative(self): # test that creation and destruction works with informative self.dialog.message = u"This is the message" self.dialog.informative = u"This is the additional message" - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_detail(self): # test that creation and destruction works with detail self.dialog.message = u"This is the message" self.dialog.informative = u"This is the additional message" self.dialog.detail = u"This is the detail" - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_warning(self): # test that creation and destruction works with warning message self.dialog.severity = "warning" - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_error(self): # test that creation and destruction works with error message self.dialog.severity = "error" - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() - + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() + + @unittest.skipIf( + is_pyqt5, "Message dialog click tests don't work on pyqt5." + ) + @unittest.skipIf( + is_pyqt4_linux, + "Message dialog click tests don't work reliably on linux. Issue #282." + ) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_accept(self): # test that accept works as expected @@ -94,6 +145,13 @@ self.assertEqual(tester.result, OK) self.assertEqual(self.dialog.return_code, OK) + @unittest.skipIf( + is_pyqt5, "Message dialog click tests don't work on pyqt5." + ) + @unittest.skipIf( + is_pyqt4_linux, + "Message dialog click tests don't work reliably on linux. Issue #282." + ) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_close(self): # test that closing works as expected @@ -103,6 +161,13 @@ self.assertEqual(tester.result, OK) self.assertEqual(self.dialog.return_code, OK) + @unittest.skipIf( + is_pyqt5, "Message dialog click tests don't work on pyqt5." + ) + @unittest.skipIf( + is_pyqt4_linux, + "Message dialog click tests don't work reliably on linux. Issue #282." + ) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_ok(self): # test that OK works as expected @@ -121,6 +186,13 @@ self.assertEqual(tester.result, OK) self.assertEqual(self.dialog.return_code, OK) + @unittest.skipIf( + is_pyqt5, "Message dialog click tests don't work on pyqt5." + ) + @unittest.skipIf( + is_pyqt4_linux, + "Message dialog click tests don't work reliably on linux. Issue #282." + ) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_parent(self): # test that lifecycle works with a parent @@ -129,6 +201,48 @@ parent.open() tester = ModalDialogTester(self.dialog.open) tester.open_and_run(when_opened=lambda x: x.close(accept=True)) - parent.close() + + with self.event_loop(): + parent.close() + self.assertEqual(tester.result, OK) self.assertEqual(self.dialog.return_code, OK) + + +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +@unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') +class TestMessageDialogHelpers(unittest.TestCase, GuiTestAssistant): + def test_information(self): + self._check_dialog(information) + + def test_warning(self): + self._check_dialog(warning) + + def test_error(self): + self._check_dialog(error) + + def _check_dialog(self, helper): + message = 'message' + kwargs = { + 'title': 'Title', + 'detail': 'Detail', + 'informative': 'Informative' + } + + # smoke test, since dialog helper is opaque + result = self._open_and_close(helper, message, **kwargs) + + self.assertIsNone(result) + + def _open_and_close(self, helper, message, **kwargs): + parent = Window() + parent.open() + + def when_opened(x): + x.close(accept=True) + + tester = ModalDialogTester(helper) + tester.open_and_wait(when_opened, parent.control, message, **kwargs) + + parent.close() + return tester.result diff -Nru python-pyface-4.5.2/pyface/tests/test_new_toolkit/init.py python-pyface-6.1.2/pyface/tests/test_new_toolkit/init.py --- python-pyface-4.5.2/pyface/tests/test_new_toolkit/init.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_new_toolkit/init.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,5 @@ +# Dummy toolkit for testing entrypoints + +from pyface.base_toolkit import Toolkit + +toolkit_object = Toolkit('pyface', 'test', 'pyface.tests.test_new_toolkit') diff -Nru python-pyface-4.5.2/pyface/tests/test_new_toolkit/widget.py python-pyface-6.1.2/pyface/tests/test_new_toolkit/widget.py --- python-pyface-4.5.2/pyface/tests/test_new_toolkit/widget.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_new_toolkit/widget.py 2019-05-03 08:18:49.000000000 +0000 @@ -0,0 +1,9 @@ +# Dummy widget module for testing entrypoints + +from traits.api import provides +from pyface.i_widget import IWidget, MWidget + + +@provides(IWidget) +class Widget(MWidget): + pass diff -Nru python-pyface-4.5.2/pyface/tests/test_progress_dialog.py python-pyface-6.1.2/pyface/tests/test_progress_dialog.py --- python-pyface-4.5.2/pyface/tests/test_progress_dialog.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_progress_dialog.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,69 +1,87 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest +import unittest -from ..constant import CANCEL -from ..gui import GUI from ..progress_dialog import ProgressDialog from ..toolkit import toolkit_object -ModalDialogTester = toolkit_object('util.modal_dialog_tester:ModalDialogTester') -no_modal_dialog_tester = (ModalDialogTester.__name__ == 'Unimplemented') +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') +ModalDialogTester = toolkit_object( + 'util.modal_dialog_tester:ModalDialogTester' +) +no_modal_dialog_tester = (ModalDialogTester.__name__ == 'Unimplemented') -class TestDialog(unittest.TestCase): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestProgressDialog(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.dialog = ProgressDialog() + def tearDown(self): + if self.dialog.control is not None: + with self.delete_widget(self.dialog.control): + self.dialog.destroy() + del self.dialog + GuiTestAssistant.tearDown(self) + def test_create(self): # test that creation and destruction works as expected - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_destroy(self): # test that destroy works even when no control - self.dialog.destroy() + with self.event_loop(): + self.dialog.destroy() def test_can_cancel(self): # test that creation works with can_cancel - self.dialog.can_cancel = True - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + self.dialog.can_cancel = True + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_show_time(self): # test that creation works with show_time - self.dialog.show_time = True - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + self.dialog.show_time = True + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() @unittest.skip("not implemented in any backend") def test_show_percent(self): # test that creation works with show_percent - self.dialog.show_percent = True - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + self.dialog.show_percent = True + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_update(self): self.dialog.min = 0 self.dialog.max = 10 self.dialog.open() for i in range(11): - result = self.dialog.update(i) - self.gui.process_events() + with self.event_loop(): + result = self.dialog.update(i) + self.assertEqual(result, (True, False)) + self.assertIsNone(self.dialog.control) @unittest.skip("inconsistent implementations") def test_update_no_control(self): self.dialog.min = 0 self.dialog.max = 10 - result = self.dialog.update(1) + with self.event_loop(): + result = self.dialog.update(1) self.assertEqual(result, (None, None)) def test_incomplete_update(self): @@ -72,11 +90,13 @@ self.can_cancel = True self.dialog.open() for i in range(5): - result = self.dialog.update(i) - self.gui.process_events() + with self.event_loop(): + result = self.dialog.update(i) self.assertEqual(result, (True, False)) self.assertIsNotNone(self.dialog.control) - self.dialog.close() + with self.event_loop(): + self.dialog.close() + self.assertIsNone(self.dialog.control) def test_change_message(self): @@ -84,10 +104,12 @@ self.dialog.max = 10 self.dialog.open() for i in range(11): - self.dialog.change_message('Updating {}'.format(i)) - result = self.dialog.update(i) - self.gui.process_events() + with self.event_loop(): + self.dialog.change_message('Updating {}'.format(i)) + result = self.dialog.update(i) + self.assertEqual(result, (True, False)) + self.assertEqual(self.dialog.message, 'Updating {}'.format(i)) self.assertIsNone(self.dialog.control) def test_update_show_time(self): @@ -96,8 +118,9 @@ self.dialog.show_time = True self.dialog.open() for i in range(11): - result = self.dialog.update(i) - self.gui.process_events() + with self.event_loop(): + result = self.dialog.update(i) + self.assertEqual(result, (True, False)) self.assertIsNone(self.dialog.control) @@ -106,19 +129,20 @@ self.dialog.max = 0 self.dialog.open() for i in range(10): - result = self.dialog.update(i) - self.gui.process_events() + with self.event_loop(): + result = self.dialog.update(i) + self.assertEqual(result, (True, False)) - self.dialog.close() + + with self.event_loop(): + self.dialog.close() # XXX not really sure what correct behaviour is here def test_update_negative(self): self.dialog.min = 0 self.dialog.max = -10 - self.dialog.open() - for i in range(11): - result = self.dialog.update(1) - self.gui.process_events() - self.assertEqual(result, (True, False)) - self.dialog.close() + with self.assertRaises(AttributeError): + with self.event_loop(): + self.dialog.open() + self.assertIsNone(self.dialog.control) diff -Nru python-pyface-4.5.2/pyface/tests/test_python_editor.py python-pyface-6.1.2/pyface/tests/test_python_editor.py --- python-pyface-4.5.2/pyface/tests/test_python_editor.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_python_editor.py 2019-06-14 12:22:56.000000000 +0000 @@ -2,61 +2,81 @@ import os import sys +import unittest -from traits.testing.unittest_tools import unittest, UnittestTools - -from ..gui import GUI from ..python_editor import PythonEditor +from ..toolkit import toolkit_object from ..window import Window +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') -PYTHON_SCRIPT = os.path.join(os.path.dirname(__file__), 'python_shell_script.py') - +PYTHON_SCRIPT = os.path.join( + os.path.dirname(__file__), 'python_shell_script.py' +) -class TestPythonEditor(unittest.TestCase, UnittestTools): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestPythonEditor(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.window = Window() self.window._create() def tearDown(self): - self.widget.destroy() - self.window.destroy() + if self.widget.control is not None: + with self.delete_widget(self.widget.control): + self.widget.destroy() + if self.window.control is not None: + with self.delete_widget(self.window.control): + self.window.destroy() + del self.widget + del self.window + GuiTestAssistant.tearDown(self) def test_lifecycle(self): # test that destroy works - self.widget = PythonEditor(self.window.control) - self.gui.process_events() + with self.event_loop(): + self.widget = PythonEditor(self.window.control) + self.assertFalse(self.widget.dirty) - self.widget.destroy() - self.gui.process_events() + + with self.event_loop(): + self.widget.destroy() def test_show_line_numbers(self): # test that destroy works - self.widget = PythonEditor(self.window.control, show_line_numbers=False) - self.gui.process_events() - self.widget.show_line_numbers = True - self.gui.process_events() - self.widget.show_line_numbers = False - self.gui.process_events() - self.widget.destroy() - self.gui.process_events() + with self.event_loop(): + self.widget = PythonEditor( + self.window.control, show_line_numbers=False + ) + with self.event_loop(): + self.widget.show_line_numbers = True + with self.event_loop(): + self.widget.show_line_numbers = False + with self.event_loop(): + self.widget.destroy() def test_load(self): # test that destroy works - self.widget = PythonEditor(self.window.control) - self.gui.process_events() + with self.event_loop(): + self.widget = PythonEditor(self.window.control) + with self.assertTraitChanges(self.widget, 'changed', count=1): - self.widget.path = PYTHON_SCRIPT + with self.event_loop(): + self.widget.path = PYTHON_SCRIPT self.assertFalse(self.widget.dirty) - self.widget.destroy() - self.gui.process_events() + + with self.event_loop(): + self.widget.destroy() def test_select_line(self): # test that destroy works - self.widget = PythonEditor(self.window.control, path=PYTHON_SCRIPT) - self.gui.process_events() - self.widget.select_line(3) - self.widget.destroy() - self.gui.process_events() + with self.event_loop(): + self.widget = PythonEditor(self.window.control, path=PYTHON_SCRIPT) + + with self.event_loop(): + self.widget.select_line(3) + + with self.event_loop(): + self.widget.destroy() diff -Nru python-pyface-4.5.2/pyface/tests/test_python_shell.py python-pyface-6.1.2/pyface/tests/test_python_shell.py --- python-pyface-4.5.2/pyface/tests/test_python_shell.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_python_shell.py 2019-06-14 12:22:56.000000000 +0000 @@ -2,89 +2,144 @@ import os import sys +import unittest -from traits.testing.unittest_tools import unittest, UnittestTools - -from ..gui import GUI from ..python_shell import PythonShell +from ..toolkit import toolkit_object from ..window import Window +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') -PYTHON_SCRIPT = os.path.abspath(os.path.join(os.path.dirname(__file__), - 'python_shell_script.py')) - +PYTHON_SCRIPT = os.path.abspath( + os.path.join(os.path.dirname(__file__), 'python_shell_script.py') +) -class TestPythonShell(unittest.TestCase, UnittestTools): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestPythonShell(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.window = Window() self.window._create() def tearDown(self): - self.widget.destroy() - self.window.destroy() + if self.widget.control is not None: + with self.delete_widget(self.widget.control): + self.widget.destroy() + if self.window.control is not None: + with self.delete_widget(self.window.control): + self.window.destroy() + del self.widget + del self.window + GuiTestAssistant.tearDown(self) def test_lifecycle(self): # test that destroy works - self.widget = PythonShell(self.window.control) - self.gui.process_events() - self.widget.destroy() - self.gui.process_events() + with self.event_loop(): + self.widget = PythonShell(self.window.control) + with self.event_loop(): + self.widget.destroy() def test_bind(self): # test that binding a variable works - self.widget = PythonShell(self.window.control) - self.gui.process_events() - self.widget.bind('x', 1) + with self.event_loop(): + self.widget = PythonShell(self.window.control) + with self.event_loop(): + self.widget.bind('x', 1) + self.assertEqual(self.widget.interpreter().locals.get('x'), 1) - self.widget.destroy() - self.gui.process_events() + + with self.event_loop(): + self.widget.destroy() def test_execute_command(self): # test that executing a command works - self.widget = PythonShell(self.window.control) - self.gui.process_events() + with self.event_loop(): + self.widget = PythonShell(self.window.control) + with self.assertTraitChanges(self.widget, 'command_executed', count=1): - self.widget.execute_command('x = 1') - self.gui.process_events() + with self.event_loop(): + self.widget.execute_command('x = 1') + self.assertEqual(self.widget.interpreter().locals.get('x'), 1) - self.widget.destroy() - self.gui.process_events() + + with self.event_loop(): + self.widget.destroy() def test_execute_command_not_hidden(self): # test that executing a non-hidden command works - self.widget = PythonShell(self.window.control) - self.gui.process_events() + with self.event_loop(): + self.widget = PythonShell(self.window.control) + with self.assertTraitChanges(self.widget, 'command_executed', count=1): - self.widget.execute_command('x = 1', hidden=False) - self.gui.process_events() + with self.event_loop(): + self.widget.execute_command('x = 1', hidden=False) + self.assertEqual(self.widget.interpreter().locals.get('x'), 1) - self.widget.destroy() - self.gui.process_events() + + with self.event_loop(): + self.widget.destroy() def test_execute_file(self): # test that executing a file works - self.widget = PythonShell(self.window.control) - self.gui.process_events() + with self.event_loop(): + self.widget = PythonShell(self.window.control) + # XXX inconsistent behaviour between backends #with self.assertTraitChanges(self.widget, 'command_executed', count=1): - self.widget.execute_file(PYTHON_SCRIPT) - self.gui.process_events() + with self.event_loop(): + self.widget.execute_file(PYTHON_SCRIPT) + self.assertEqual(self.widget.interpreter().locals.get('x'), 1) self.assertEqual(self.widget.interpreter().locals.get('sys'), sys) - self.widget.destroy() - self.gui.process_events() + + with self.event_loop(): + self.widget.destroy() def test_execute_file_not_hidden(self): # test that executing a file works - self.widget = PythonShell(self.window.control) - self.gui.process_events() + with self.event_loop(): + self.widget = PythonShell(self.window.control) + # XXX inconsistent behaviour between backends #with self.assertTraitChanges(self.widget, 'command_executed', count=1): - self.widget.execute_file(PYTHON_SCRIPT, hidden=False) - self.gui.process_events() + with self.event_loop(): + self.widget.execute_file(PYTHON_SCRIPT, hidden=False) + self.assertEqual(self.widget.interpreter().locals.get('x'), 1) self.assertEqual(self.widget.interpreter().locals.get('sys'), sys) - self.widget.destroy() - self.gui.process_events() + + with self.event_loop(): + self.widget.destroy() + + def test_get_history(self): + # test that executing a command works + with self.event_loop(): + self.widget = PythonShell(self.window.control) + + with self.event_loop(): + self.widget.execute_command('x = 1', hidden=False) + + history, history_index = self.widget.get_history() + + self.assertEqual(history, ['x = 1']) + self.assertEqual(history_index, 1) + + with self.event_loop(): + self.widget.destroy() + + def test_set_history(self): + # test that executing a command works + with self.event_loop(): + self.widget = PythonShell(self.window.control) + + with self.event_loop(): + self.widget.set_history(['x = 1', 'y = x + 1'], 1) + + history, history_index = self.widget.get_history() + self.assertEqual(history, ['x = 1', 'y = x + 1']) + self.assertEqual(history_index, 1) + + with self.event_loop(): + self.widget.destroy() diff -Nru python-pyface-4.5.2/pyface/tests/test_resource_manager.py python-pyface-6.1.2/pyface/tests/test_resource_manager.py --- python-pyface-4.5.2/pyface/tests/test_resource_manager.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_resource_manager.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,8 +1,7 @@ from __future__ import absolute_import import os - -from traits.testing.unittest_tools import unittest +import unittest from ..resource_manager import PyfaceResourceFactory diff -Nru python-pyface-4.5.2/pyface/tests/test_single_choice_dialog.py python-pyface-6.1.2/pyface/tests/test_single_choice_dialog.py --- python-pyface-4.5.2/pyface/tests/test_single_choice_dialog.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_single_choice_dialog.py 2019-06-14 12:22:56.000000000 +0000 @@ -0,0 +1,227 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2016, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# +#------------------------------------------------------------------------------ + +from __future__ import absolute_import + +import unittest + +from traits.etsconfig.api import ETSConfig + +from ..single_choice_dialog import SingleChoiceDialog +from ..constant import OK, CANCEL +from ..gui import GUI +from ..toolkit import toolkit_object +from ..window import Window + +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') + +ModalDialogTester = toolkit_object( + 'util.modal_dialog_tester:ModalDialogTester' +) # noqa: E501 +no_modal_dialog_tester = (ModalDialogTester.__name__ == 'Unimplemented') + +USING_QT = ETSConfig.toolkit not in ['', 'wx'] + + +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestSingleChoiceDialog(unittest.TestCase, GuiTestAssistant): + def setUp(self): + GuiTestAssistant.setUp(self) + self.dialog = SingleChoiceDialog(choices=['red', 'blue', 'green']) + + def tearDown(self): + if self.dialog.control is not None: + with self.delete_widget(self.dialog.control): + self.dialog.destroy() + self.dialog = None + GuiTestAssistant.tearDown(self) + + def test_create(self): + # test that creation and destruction works as expected + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() + + def test_destroy(self): + # test that destroy works even when no control + with self.event_loop(): + self.dialog.destroy() + + def test_create_cancel(self): + # test that creation and destruction works no cancel button + self.dialog.cancel = False + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() + + def test_create_parent(self): + # test that creation and destruction works as expected with a parent + with self.event_loop(): + parent = Window() + self.dialog.parent = parent.control + parent._create() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() + with self.event_loop(): + parent.destroy() + + def test_message(self): + # test that creation and destruction works as expected with message + self.dialog.message = u"This is the message" + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() + + def test_choice_strings(self): + # test that choice strings work using simple strings + self.assertEqual( + self.dialog._choice_strings(), ['red', 'blue', 'green'] + ) + + def test_choice_strings_convert(self): + # test that choice strings work using simple strings + self.dialog.choices = [1, 2, 3] + self.assertEqual(self.dialog._choice_strings(), ['1', '2', '3']) + + def test_choice_strings_name_attribute(self): + # test that choice strings work using attribute name of objects + class Item(object): + def __init__(self, description): + self.description = description + + self.dialog.choices = [Item(name) for name in ['red', 'blue', 'green']] + self.dialog.name_attribute = 'description' + self.assertEqual( + self.dialog._choice_strings(), ['red', 'blue', 'green'] + ) + + def test_choice_strings_name_attribute_convert(self): + # test that choice strings work using attribute name of objects + class Item(object): + def __init__(self, description): + self.description = description + + self.dialog.choices = [Item(name) for name in [1, 2, 3]] + self.dialog.name_attribute = 'description' + self.assertEqual(self.dialog._choice_strings(), ['1', '2', '3']) + + def test_choice_strings_empty(self): + # test that choice strings work using simple strings + self.dialog.choices = [] + with self.assertRaises(ValueError): + self.dialog._choice_strings() + + def test_choice_strings_duplicated(self): + # test that choice strings work using simple strings + self.dialog.choices = ['red', 'green', 'blue', 'green'] + with self.assertRaises(ValueError): + self.dialog._choice_strings() + + @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') + def test_accept(self): + # test that accept works as expected + tester = ModalDialogTester(self.dialog.open) + tester.open_and_run(when_opened=lambda x: x.close(accept=True)) + self.assertEqual(tester.result, OK) + self.assertEqual(self.dialog.return_code, OK) + self.assertEqual(self.dialog.choice, 'red') + + @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') + def test_reject(self): + # test that accept works as expected + tester = ModalDialogTester(self.dialog.open) + tester.open_and_run(when_opened=lambda x: x.close(accept=False)) + + self.assertEqual(tester.result, CANCEL) + self.assertEqual(self.dialog.return_code, CANCEL) + self.assertIsNone(self.dialog.choice) + + @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') + def test_close(self): + # test that closing works as expected + tester = ModalDialogTester(self.dialog.open) + tester.open_and_run( + when_opened=lambda x: x.get_dialog_widget().close() + ) + + self.assertEqual(tester.result, CANCEL) + self.assertEqual(self.dialog.return_code, CANCEL) + self.assertIsNone(self.dialog.choice) + + @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') + def test_parent(self): + # test that lifecycle works with a parent + parent = Window() + self.dialog.parent = parent.control + parent.open() + tester = ModalDialogTester(self.dialog.open) + tester.open_and_run(when_opened=lambda x: x.close(accept=True)) + with self.event_loop(): + parent.close() + + self.assertEqual(tester.result, OK) + self.assertEqual(self.dialog.return_code, OK) + + @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') + def test_change_choice_accept(self): + # test that if we change choice it's reflected in result + def select_green_and_ok(tester): + control = tester.get_dialog_widget() + control.setTextValue("green") + tester.close(accept=True) + + tester = ModalDialogTester(self.dialog.open) + tester.open_and_run(when_opened=select_green_and_ok) + + self.assertEqual(tester.result, OK) + self.assertEqual(self.dialog.return_code, OK) + self.assertEqual(self.dialog.choice, 'green') + + @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') + def test_change_choice_with_reject(self): + # test that lifecycle works with a parent + def select_green_and_cancel(tester): + control = tester.get_dialog_widget() + control.setTextValue("green") + tester.close(accept=False) + + tester = ModalDialogTester(self.dialog.open) + tester.open_and_run(when_opened=select_green_and_cancel) + + self.assertEqual(tester.result, CANCEL) + self.assertEqual(self.dialog.return_code, CANCEL) + self.assertIsNone(self.dialog.choice) + + @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') + def test_change_choice_with_close(self): + # test that lifecycle works with a parent + def select_green_and_close(tester): + control = tester.get_dialog_widget() + control.setTextValue("green") + control.close() + + tester = ModalDialogTester(self.dialog.open) + tester.open_and_run(when_opened=select_green_and_close) + + self.assertEqual(tester.result, CANCEL) + self.assertEqual(self.dialog.return_code, CANCEL) + self.assertIsNone(self.dialog.choice) diff -Nru python-pyface-4.5.2/pyface/tests/test_splash_screen.py python-pyface-6.1.2/pyface/tests/test_splash_screen.py --- python-pyface-4.5.2/pyface/tests/test_splash_screen.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_splash_screen.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,65 +1,82 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest, UnittestTools +import unittest from ..gui import GUI from ..image_resource import ImageResource from ..splash_screen import SplashScreen +from ..toolkit import toolkit_object +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') -class TestWindow(unittest.TestCase, UnittestTools): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestWindow(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.window = SplashScreen() + def tearDown(self): + if self.window.control is not None: + with self.delete_widget(self.window.control): + self.window.destroy() + + del self.window + GuiTestAssistant.tearDown(self) + def test_destroy(self): # test that destroy works even when no control - self.window.destroy() + with self.event_loop(): + self.window.destroy() def test_open_close(self): # test that opening and closing works as expected with self.assertTraitChanges(self.window, 'opening', count=1): with self.assertTraitChanges(self.window, 'opened', count=1): - self.window.open() - self.gui.process_events() + with self.event_loop(): + self.window.open() with self.assertTraitChanges(self.window, 'closing', count=1): with self.assertTraitChanges(self.window, 'closed', count=1): - self.window.close() - self.gui.process_events() + with self.event_loop(): + self.window.close() def test_show(self): # test that show works as expected - self.window._create() - self.window.show(True) - self.gui.process_events() - self.window.show(False) - self.gui.process_events() - self.window.destroy() + with self.event_loop(): + self.window._create() + with self.event_loop(): + self.window.show(True) + with self.event_loop(): + self.window.show(False) + with self.event_loop(): + self.window.destroy() def test_image(self): # test that images work self.window.image = ImageResource('core') with self.assertTraitChanges(self.window, 'opening', count=1): with self.assertTraitChanges(self.window, 'opened', count=1): - self.window.open() - self.gui.process_events() + with self.event_loop(): + self.window.open() + with self.assertTraitChanges(self.window, 'closing', count=1): with self.assertTraitChanges(self.window, 'closed', count=1): - self.window.close() - self.gui.process_events() + with self.event_loop(): + self.window.close() def test_text(self): # test that images work self.window.text = "Splash screen" with self.assertTraitChanges(self.window, 'opening', count=1): with self.assertTraitChanges(self.window, 'opened', count=1): - self.window.open() - self.gui.process_events() + with self.event_loop(): + self.window.open() + with self.assertTraitChanges(self.window, 'closing', count=1): with self.assertTraitChanges(self.window, 'closed', count=1): - self.window.close() - self.gui.process_events() + with self.event_loop(): + self.window.close() def test_text_changed(self): # test that images work @@ -67,11 +84,13 @@ # - probably the way the test is written. with self.assertTraitChanges(self.window, 'opening', count=1): with self.assertTraitChanges(self.window, 'opened', count=1): - self.window.open() - self.gui.process_events() - self.window.text = "Splash screen" - self.gui.process_events() + with self.event_loop(): + self.window.open() + + with self.event_loop(): + self.window.text = "Splash screen" + with self.assertTraitChanges(self.window, 'closing', count=1): with self.assertTraitChanges(self.window, 'closed', count=1): - self.window.close() - self.gui.process_events() + with self.event_loop(): + self.window.close() diff -Nru python-pyface-4.5.2/pyface/tests/test_split_application_window.py python-pyface-6.1.2/pyface/tests/test_split_application_window.py --- python-pyface-4.5.2/pyface/tests/test_split_application_window.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_split_application_window.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,44 +1,57 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest, UnittestTools +import unittest -from ..gui import GUI from ..heading_text import HeadingText from ..split_application_window import SplitApplicationWindow +from ..toolkit import toolkit_object +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') -class TestSplitApplicationWindow(unittest.TestCase, UnittestTools): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestSplitApplicationWindow(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.window = SplitApplicationWindow() + def tearDown(self): + if self.window.control is not None: + with self.delete_widget(self.window.control): + self.window.destroy() + del self.window + GuiTestAssistant.tearDown(self) + def test_destroy(self): # test that destroy works even when no control - self.window.destroy() + with self.event_loop(): + self.window.destroy() def test_open_close(self): # test that opening and closing works as expected with self.assertTraitChanges(self.window, 'opening', count=1): with self.assertTraitChanges(self.window, 'opened', count=1): - self.window.open() - self.gui.process_events() + with self.event_loop(): + self.window.open() + with self.assertTraitChanges(self.window, 'closing', count=1): with self.assertTraitChanges(self.window, 'closed', count=1): - self.window.close() - self.gui.process_events() + with self.event_loop(): + self.window.close() def test_horizontal_split(self): # test that horizontal split works self.window.direction = 'horizontal' with self.assertTraitChanges(self.window, 'opening', count=1): with self.assertTraitChanges(self.window, 'opened', count=1): - self.window.open() - self.gui.process_events() + with self.event_loop(): + self.window.open() + with self.assertTraitChanges(self.window, 'closing', count=1): with self.assertTraitChanges(self.window, 'closed', count=1): - self.window.close() - self.gui.process_events() + with self.event_loop(): + self.window.close() def test_contents(self): # test that contents works @@ -46,21 +59,23 @@ self.window.rhs = HeadingText with self.assertTraitChanges(self.window, 'opening', count=1): with self.assertTraitChanges(self.window, 'opened', count=1): - self.window.open() - self.gui.process_events() + with self.event_loop(): + self.window.open() + with self.assertTraitChanges(self.window, 'closing', count=1): with self.assertTraitChanges(self.window, 'closed', count=1): - self.window.close() - self.gui.process_events() + with self.event_loop(): + self.window.close() def test_ratio(self): # test that ratio split works self.window.ratio = 0.25 with self.assertTraitChanges(self.window, 'opening', count=1): with self.assertTraitChanges(self.window, 'opened', count=1): - self.window.open() - self.gui.process_events() + with self.event_loop(): + self.window.open() + with self.assertTraitChanges(self.window, 'closing', count=1): with self.assertTraitChanges(self.window, 'closed', count=1): - self.window.close() - self.gui.process_events() + with self.event_loop(): + self.window.close() diff -Nru python-pyface-4.5.2/pyface/tests/test_split_dialog.py python-pyface-6.1.2/pyface/tests/test_split_dialog.py --- python-pyface-4.5.2/pyface/tests/test_split_dialog.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_split_dialog.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,46 +1,61 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest +import unittest -from ..gui import GUI from ..heading_text import HeadingText from ..split_dialog import SplitDialog +from ..toolkit import toolkit_object +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') -class TestDialog(unittest.TestCase): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestDialog(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.dialog = SplitDialog() + def tearDown(self): + if self.dialog.control is not None: + with self.delete_widget(self.dialog.control): + self.dialog.destroy() + del self.dialog + GuiTestAssistant.tearDown(self) + def test_create(self): # test that creation and destruction works as expected - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_destroy(self): # test that destroy works even when no control - self.dialog.destroy() + with self.event_loop(): + self.dialog.destroy() def test_horizontal(self): # test that horizontal split works self.dialog.direction = 'horizontal' - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_ratio(self): # test that ratio works self.dialog.ratio = 0.25 - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() def test_contents(self): # test that contents works self.dialog.lhs = HeadingText self.dialog.rhs = HeadingText - self.dialog._create() - self.gui.process_events() - self.dialog.destroy() + with self.event_loop(): + self.dialog._create() + with self.event_loop(): + self.dialog.destroy() diff -Nru python-pyface-4.5.2/pyface/tests/test_split_panel.py python-pyface-6.1.2/pyface/tests/test_split_panel.py --- python-pyface-4.5.2/pyface/tests/test_split_panel.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_split_panel.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,49 +1,64 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest +import unittest -from ..gui import GUI from ..heading_text import HeadingText from ..split_panel import SplitPanel +from ..toolkit import toolkit_object from ..window import Window +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') -class TestHeadingText(unittest.TestCase): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestHeadingText(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.window = Window() self.window._create() def tearDown(self): - self.widget.destroy() - self.window.destroy() + if self.widget.control is not None: + with self.delete_widget(self.widget.control): + self.widget.destroy() + + if self.window.control is not None: + with self.delete_widget(self.window.control): + self.window.destroy() + + del self.widget + del self.window + GuiTestAssistant.tearDown(self) def test_lifecycle(self): # test that destroy works - self.widget = SplitPanel(self.window.control) - self.gui.process_events() - self.widget.destroy() - self.gui.process_events() + with self.event_loop(): + self.widget = SplitPanel(self.window.control) + with self.event_loop(): + self.widget.destroy() def test_horizontal(self): # test that horizontal split works - self.widget = SplitPanel(self.window.control, direction='horizontal') - self.gui.process_events() - self.widget.destroy() - self.gui.process_events() + with self.event_loop(): + self.widget = SplitPanel( + self.window.control, direction='horizontal' + ) + with self.event_loop(): + self.widget.destroy() def test_ratio(self): # test that ratio works - self.widget = SplitPanel(self.window.control, ratio=0.25) - self.gui.process_events() - self.widget.destroy() - self.gui.process_events() + with self.event_loop(): + self.widget = SplitPanel(self.window.control, ratio=0.25) + with self.event_loop(): + self.widget.destroy() def test_contents(self): # test that contents works - self.widget = SplitPanel(self.window.control, lhs=HeadingText, - rhs=HeadingText) - self.gui.process_events() - self.widget.destroy() - self.gui.process_events() + with self.event_loop(): + self.widget = SplitPanel( + self.window.control, lhs=HeadingText, rhs=HeadingText + ) + with self.event_loop(): + self.widget.destroy() diff -Nru python-pyface-4.5.2/pyface/tests/test_system_metrics.py python-pyface-6.1.2/pyface/tests/test_system_metrics.py --- python-pyface-4.5.2/pyface/tests/test_system_metrics.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_system_metrics.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,6 +1,6 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest +import unittest from ..system_metrics import SystemMetrics diff -Nru python-pyface-4.5.2/pyface/tests/test_toolkit.py python-pyface-6.1.2/pyface/tests/test_toolkit.py --- python-pyface-4.5.2/pyface/tests/test_toolkit.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_toolkit.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,11 +1,13 @@ -from traits.testing.unittest_tools import unittest +import pkg_resources +import unittest + import pyface.toolkit class TestToolkit(unittest.TestCase): def test_missing_import(self): - # test that we get an undefined object if no Qt implementation + # test that we get an undefined object if no toolkit implementation cls = pyface.toolkit.toolkit_object('tests:Missing') with self.assertRaises(NotImplementedError): obj = cls() @@ -14,3 +16,47 @@ # test that we don't filter unrelated import errors with self.assertRaises(ImportError): cls = pyface.toolkit.toolkit_object('tests.bad_import:Missing') + + def test_core_plugins(self): + # test that we can see appropriate core entrypoints + plugins = set(entry_point.name for entry_point in + pkg_resources.iter_entry_points('pyface.toolkits')) + + self.assertLessEqual({'qt4', 'wx', 'qt', 'null'}, plugins) + + def test_toolkit_object(self): + # test that the Toolkit class works as expected + # note that if this fails many other things will too + from pyface.tests.test_new_toolkit.init import toolkit_object + from pyface.tests.test_new_toolkit.widget import Widget as TestWidget + + Widget = toolkit_object('widget:Widget') + + self.assertEqual(Widget, TestWidget) + + def test_toolkit_object_overriden(self): + # test that the Toolkit class search paths can be overridden + from pyface.tests.test_new_toolkit.widget import Widget as TestWidget + + toolkit_object = pyface.toolkit.toolkit_object + + old_packages = toolkit_object.packages + toolkit_object.packages = ['pyface.tests.test_new_toolkit'] + old_packages + try: + Widget = toolkit_object('widget:Widget') + self.assertEqual(Widget, TestWidget) + finally: + toolkit_object.packages = old_packages + + def test_toolkit_object_not_overriden(self): + # test that the Toolkit class works when object not overridden + toolkit_object = pyface.toolkit.toolkit_object + TestWindow = toolkit_object('window:Window') + + old_packages = toolkit_object.packages + toolkit_object.packages = ['pyface.tests.test_new_toolkit'] + old_packages + try: + Window = toolkit_object('window:Window') + self.assertEqual(Window, TestWindow) + finally: + toolkit_object.packages = old_packages diff -Nru python-pyface-4.5.2/pyface/tests/test_ui_traits.py python-pyface-6.1.2/pyface/tests/test_ui_traits.py --- python-pyface-4.5.2/pyface/tests/test_ui_traits.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_ui_traits.py 2019-06-18 11:33:39.000000000 +0000 @@ -0,0 +1,561 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2016, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# +# Thanks for using Enthought open source! +# +# Author: Enthought Developers +# +#------------------------------------------------------------------------------ + +import os +import unittest + +from traits.api import HasTraits, TraitError +from traits.testing.unittest_tools import UnittestTools +try: + from traits.trait_handlers import ( + CALLABLE_AND_ARGS_DEFAULT_VALUE, + UNSPECIFIED_DEFAULT_VALUE + ) +except ImportError: + UNSPECIFIED_DEFAULT_VALUE = -1 + CALLABLE_AND_ARGS_DEFAULT_VALUE = 7 + +from ..i_image_resource import IImageResource +from ..image_resource import ImageResource +from ..ui_traits import (Border, HasBorder, HasMargin, Image, Margin, + image_resource_cache, image_bitmap_cache) + + +IMAGE_PATH = os.path.join(os.path.dirname(__file__), 'images', 'core.png') + + +class ImageClass(HasTraits): + + image = Image + + +class HasMarginClass(HasTraits): + + margin = HasMargin + + +class HasBorderClass(HasTraits): + + border = HasBorder + + +class TestImageTrait(unittest.TestCase, UnittestTools): + + def setUp(self): + # clear all cached images + image_resource_cache.clear() + image_bitmap_cache.clear() + # clear cached "not found" image + ImageResource._image_not_found = None + + def test_defaults(self): + image_class = ImageClass() + + self.assertIsNone(image_class.image) + + def test_init_local_image(self): + from pyface.image_resource import ImageResource + + image_class = ImageClass(image=ImageResource('core.png')) + + self.assertIsInstance(image_class.image, ImageResource) + self.assertEqual(image_class.image.name, 'core.png') + self.assertEqual(image_class.image.absolute_path, + os.path.abspath(IMAGE_PATH)) + + def test_init_pyface_image(self): + from pyface.image_resource import ImageResource + + image_class = ImageClass(image='about') + im = image_class.image.create_image() + + self.assertIsInstance(image_class.image, ImageResource) + self.assertEqual(image_class.image.name, 'about') + self.assertIsNone(image_class.image._image_not_found) + self.assertIsNotNone(image_class.image._ref.data) + + def test_init_pyface_image_library(self): + from pyface.image_resource import ImageResource + + image_class = ImageClass(image='@icons:dialog-warning') + + self.assertIsInstance(image_class.image, ImageResource) + self.assertEqual(image_class.image.name, 'dialog-warning.png') + self.assertIsNone(image_class.image._image_not_found) + self.assertEqual(image_class.image._ref.file_name, 'dialog-warning.png') + self.assertEqual(image_class.image._ref.volume_name, 'icons') + + +class TestMargin(unittest.TestCase): + + def test_defaults(self): + margin = Margin() + self.assertEqual(margin.top, 0) + self.assertEqual(margin.bottom, 0) + self.assertEqual(margin.left, 0) + self.assertEqual(margin.right, 0) + + def test_init_one_arg(self): + margin = Margin(4) + self.assertEqual(margin.top, 4) + self.assertEqual(margin.bottom, 4) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 4) + + def test_init_two_args(self): + margin = Margin(4, 2) + self.assertEqual(margin.top, 2) + self.assertEqual(margin.bottom, 2) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 4) + + def test_init_four_args(self): + margin = Margin(4, 2, 3, 1) + self.assertEqual(margin.top, 3) + self.assertEqual(margin.bottom, 1) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 2) + + +class TestHasMargin(unittest.TestCase, UnittestTools): + + def test_defaults(self): + has_margin = HasMarginClass() + margin = has_margin.margin + + self.assertEqual(margin.top, 0) + self.assertEqual(margin.bottom, 0) + self.assertEqual(margin.left, 0) + self.assertEqual(margin.right, 0) + + def test_unspecified_default(self): + trait = HasMargin() + trait.default_value_type = UNSPECIFIED_DEFAULT_VALUE + + (dvt, dv) = trait.get_default_value() + + self.assertEqual(dvt, CALLABLE_AND_ARGS_DEFAULT_VALUE) + self.assertEqual( + dv, + ( + Margin, + (), + {'top': 0, 'bottom': 0, 'left': 0, 'right': 0}, + ) + ) + + def test_default_int(self): + + class HasMarginClass(HasTraits): + + margin = HasMargin(4) + + has_margin = HasMarginClass() + margin = has_margin.margin + + self.assertEqual(margin.top, 4) + self.assertEqual(margin.bottom, 4) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 4) + + def test_default_one_tuple(self): + + class HasMarginClass(HasTraits): + + margin = HasMargin((4,)) + + has_margin = HasMarginClass() + margin = has_margin.margin + + self.assertEqual(margin.top, 4) + self.assertEqual(margin.bottom, 4) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 4) + + def test_default_two_tuple(self): + + class HasMarginClass(HasTraits): + + margin = HasMargin((4, 2)) + + has_margin = HasMarginClass() + margin = has_margin.margin + + self.assertEqual(margin.top, 2) + self.assertEqual(margin.bottom, 2) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 4) + + def test_default_four_tuple(self): + + class HasMarginClass(HasTraits): + + margin = HasMargin((4, 2, 3, 1)) + + has_margin = HasMarginClass() + margin = has_margin.margin + + self.assertEqual(margin.top, 3) + self.assertEqual(margin.bottom, 1) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 2) + + def test_default_margin(self): + m = Margin(left=4, right=2, top=3, bottom=1) + + class HasMarginClass(HasTraits): + + margin = HasMargin(m) + + has_margin = HasMarginClass() + margin = has_margin.margin + + self.assertEqual(margin.top, 3) + self.assertEqual(margin.bottom, 1) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 2) + + def test_init_int(self): + has_margin = HasMarginClass(margin=4) + margin = has_margin.margin + + self.assertEqual(margin.top, 4) + self.assertEqual(margin.bottom, 4) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 4) + + def test_init_one_tuple(self): + has_margin = HasMarginClass(margin=(4,)) + margin = has_margin.margin + + self.assertEqual(margin.top, 4) + self.assertEqual(margin.bottom, 4) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 4) + + def test_init_two_tuple(self): + has_margin = HasMarginClass(margin=(4, 2)) + margin = has_margin.margin + + self.assertEqual(margin.top, 2) + self.assertEqual(margin.bottom, 2) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 4) + + def test_init_four_tuple(self): + has_margin = HasMarginClass(margin=(4, 2, 3, 1)) + margin = has_margin.margin + + self.assertEqual(margin.top, 3) + self.assertEqual(margin.bottom, 1) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 2) + + def test_init_margin(self): + margin = Margin() + has_margin = HasMarginClass(margin=margin) + + self.assertEqual(has_margin.margin, margin) + + def test_set_int(self): + has_margin = HasMarginClass() + with self.assertTraitChanges(has_margin, 'margin', 1): + has_margin.margin = 4 + + margin = has_margin.margin + self.assertEqual(margin.top, 4) + self.assertEqual(margin.bottom, 4) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 4) + + def test_set_one_tuple(self): + has_margin = HasMarginClass() + with self.assertTraitChanges(has_margin, 'margin', 1): + has_margin.margin = (4,) + + margin = has_margin.margin + + self.assertEqual(margin.top, 4) + self.assertEqual(margin.bottom, 4) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 4) + + def test_set_two_tuple(self): + has_margin = HasMarginClass() + with self.assertTraitChanges(has_margin, 'margin', 1): + has_margin.margin = (4, 2) + + margin = has_margin.margin + + self.assertEqual(margin.top, 2) + self.assertEqual(margin.bottom, 2) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 4) + + def test_set_four_tuple(self): + has_margin = HasMarginClass() + with self.assertTraitChanges(has_margin, 'margin', 1): + has_margin.margin = (4, 2, 3, 1) + + margin = has_margin.margin + self.assertEqual(margin.top, 3) + self.assertEqual(margin.bottom, 1) + self.assertEqual(margin.left, 4) + self.assertEqual(margin.right, 2) + + def test_set_margin(self): + margin = Margin() + has_margin = HasMarginClass() + with self.assertTraitChanges(has_margin, 'margin', 1): + has_margin.margin = margin + + self.assertEqual(has_margin.margin, margin) + + def test_set_invalid(self): + has_margin = HasMarginClass() + with self.assertRaises(TraitError): + has_margin.margin = (1, 2, 3) + + +class TestBorder(unittest.TestCase): + + def test_defaults(self): + border = Border() + self.assertEqual(border.top, 0) + self.assertEqual(border.bottom, 0) + self.assertEqual(border.left, 0) + self.assertEqual(border.right, 0) + + def test_init_one_arg(self): + border = Border(4) + self.assertEqual(border.top, 4) + self.assertEqual(border.bottom, 4) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 4) + + def test_init_two_args(self): + border = Border(4, 2) + self.assertEqual(border.top, 2) + self.assertEqual(border.bottom, 2) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 4) + + def test_init_four_args(self): + border = Border(4, 2, 3, 1) + self.assertEqual(border.top, 3) + self.assertEqual(border.bottom, 1) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 2) + + +class TestHasBorder(unittest.TestCase, UnittestTools): + + def test_defaults(self): + has_border = HasBorderClass() + border = has_border.border + + self.assertEqual(border.top, 0) + self.assertEqual(border.bottom, 0) + self.assertEqual(border.left, 0) + self.assertEqual(border.right, 0) + + def test_unspecified_default(self): + trait = HasBorder() + trait.default_value_type = UNSPECIFIED_DEFAULT_VALUE + + (dvt, dv) = trait.get_default_value() + + self.assertEqual(dvt, CALLABLE_AND_ARGS_DEFAULT_VALUE) + self.assertEqual( + dv, + ( + Border, + (), + {'top': 0, 'bottom': 0, 'left': 0, 'right': 0}, + ) + ) + + def test_default_int(self): + + class HasBorderClass(HasTraits): + + border = HasBorder(4) + + has_border = HasBorderClass() + border = has_border.border + + self.assertEqual(border.top, 4) + self.assertEqual(border.bottom, 4) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 4) + + def test_default_one_tuple(self): + + class HasBorderClass(HasTraits): + + border = HasBorder((4,)) + + has_border = HasBorderClass() + border = has_border.border + + self.assertEqual(border.top, 4) + self.assertEqual(border.bottom, 4) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 4) + + def test_default_two_tuple(self): + + class HasBorderClass(HasTraits): + + border = HasBorder((4, 2)) + + has_border = HasBorderClass() + border = has_border.border + + self.assertEqual(border.top, 2) + self.assertEqual(border.bottom, 2) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 4) + + def test_default_four_tuple(self): + + class HasBorderClass(HasTraits): + + border = HasBorder((4, 2, 3, 1)) + + has_border = HasBorderClass() + border = has_border.border + + self.assertEqual(border.top, 3) + self.assertEqual(border.bottom, 1) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 2) + + def test_default_border(self): + m = Margin(left=4, right=2, top=3, bottom=1) + + class HasBorderClass(HasTraits): + + border = HasBorder(m) + + has_border = HasBorderClass() + border = has_border.border + + self.assertEqual(border.top, 3) + self.assertEqual(border.bottom, 1) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 2) + + def test_init_int(self): + has_border = HasBorderClass(border=4) + border = has_border.border + + self.assertEqual(border.top, 4) + self.assertEqual(border.bottom, 4) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 4) + + def test_init_one_tuple(self): + has_border = HasBorderClass(border=(4,)) + border = has_border.border + + self.assertEqual(border.top, 4) + self.assertEqual(border.bottom, 4) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 4) + + def test_init_two_tuple(self): + has_border = HasBorderClass(border=(4, 2)) + border = has_border.border + + self.assertEqual(border.top, 2) + self.assertEqual(border.bottom, 2) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 4) + + def test_init_four_tuple(self): + has_border = HasBorderClass(border=(4, 2, 3, 1)) + border = has_border.border + + self.assertEqual(border.top, 3) + self.assertEqual(border.bottom, 1) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 2) + + def test_init_border(self): + border = Border() + has_border = HasBorderClass(border=border) + + self.assertEqual(has_border.border, border) + + def test_set_int(self): + has_border = HasBorderClass() + with self.assertTraitChanges(has_border, 'border', 1): + has_border.border = 4 + + border = has_border.border + self.assertEqual(border.top, 4) + self.assertEqual(border.bottom, 4) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 4) + + def test_set_one_tuple(self): + has_border = HasBorderClass() + with self.assertTraitChanges(has_border, 'border', 1): + has_border.border = (4,) + + border = has_border.border + + self.assertEqual(border.top, 4) + self.assertEqual(border.bottom, 4) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 4) + + def test_set_two_tuple(self): + has_border = HasBorderClass() + with self.assertTraitChanges(has_border, 'border', 1): + has_border.border = (4, 2) + + border = has_border.border + + self.assertEqual(border.top, 2) + self.assertEqual(border.bottom, 2) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 4) + + def test_set_four_tuple(self): + has_border = HasBorderClass() + with self.assertTraitChanges(has_border, 'border', 1): + has_border.border = (4, 2, 3, 1) + + border = has_border.border + self.assertEqual(border.top, 3) + self.assertEqual(border.bottom, 1) + self.assertEqual(border.left, 4) + self.assertEqual(border.right, 2) + + def test_set_border(self): + border = Border() + has_border = HasBorderClass() + with self.assertTraitChanges(has_border, 'border', 1): + has_border.border = border + + self.assertEqual(has_border.border, border) + + def test_set_invalid(self): + has_border = HasBorderClass() + with self.assertRaises(TraitError): + has_border.border = (1, 2, 3) diff -Nru python-pyface-4.5.2/pyface/tests/test_widget.py python-pyface-6.1.2/pyface/tests/test_widget.py --- python-pyface-4.5.2/pyface/tests/test_widget.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_widget.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,15 +1,44 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest, UnittestTools +import unittest +from traits.testing.unittest_tools import UnittestTools + +from ..toolkit import toolkit_object from ..widget import Widget +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') -class TestWidget(unittest.TestCase, UnittestTools): +class ConcreteWidget(Widget): + def _create_control(self, parent): + if toolkit_object.toolkit == 'wx': + import wx + control = wx.Window(parent) + control.Enable(self.enabled) + control.Show(self.visible) + elif toolkit_object.toolkit == 'qt4': + from pyface.qt import QtGui + control = QtGui.QWidget(parent) + control.setEnabled(self.enabled) + control.setVisible(self.visible) + else: + control = None + return control + + +class TestWidget(unittest.TestCase, UnittestTools): def setUp(self): self.widget = Widget() + def tearDown(self): + del self.widget + + def test_defaults(self): + self.assertTrue(self.widget.enabled) + self.assertTrue(self.widget.visible) + def test_create(self): # create is not Implemented with self.assertRaises(NotImplementedError): @@ -18,3 +47,96 @@ def test_destroy(self): # test that destroy works even when no control self.widget.destroy() + + def test_show(self): + with self.assertTraitChanges(self.widget, 'visible', count=1): + self.widget.show(False) + + self.assertFalse(self.widget.visible) + + def test_visible(self): + with self.assertTraitChanges(self.widget, 'visible', count=1): + self.widget.visible = False + + self.assertFalse(self.widget.visible) + + def test_enable(self): + with self.assertTraitChanges(self.widget, 'enabled', count=1): + self.widget.enable(False) + + self.assertFalse(self.widget.enabled) + + def test_enabled(self): + with self.assertTraitChanges(self.widget, 'enabled', count=1): + self.widget.enabled = False + + self.assertFalse(self.widget.enabled) + + +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestConcreteWidget(unittest.TestCase, GuiTestAssistant): + def setUp(self): + GuiTestAssistant.setUp(self) + self.widget = ConcreteWidget() + + def tearDown(self): + if self.widget.control is not None: + with self.delete_widget(self.widget.control): + self.widget.destroy() + del self.widget + GuiTestAssistant.tearDown(self) + + def test_lifecycle(self): + with self.event_loop(): + self.widget._create() + with self.event_loop(): + self.widget.destroy() + + def test_initialize(self): + self.widget.visible = False + self.widget.enabled = False + with self.event_loop(): + self.widget._create() + + self.assertFalse(self.widget.control.isVisible()) + self.assertFalse(self.widget.control.isEnabled()) + + def test_show(self): + with self.event_loop(): + self.widget._create() + + with self.assertTraitChanges(self.widget, 'visible', count=1): + with self.event_loop(): + self.widget.show(False) + + self.assertFalse(self.widget.control.isVisible()) + + def test_visible(self): + with self.event_loop(): + self.widget._create() + + with self.assertTraitChanges(self.widget, 'visible', count=1): + with self.event_loop(): + self.widget.visible = False + + self.assertFalse(self.widget.control.isVisible()) + + def test_enable(self): + with self.event_loop(): + self.widget._create() + + with self.assertTraitChanges(self.widget, 'enabled', count=1): + with self.event_loop(): + self.widget.enable(False) + + self.assertFalse(self.widget.control.isEnabled()) + + def test_enabled(self): + with self.event_loop(): + self.widget._create() + + with self.assertTraitChanges(self.widget, 'enabled', count=1): + with self.event_loop(): + self.widget.enabled = False + + self.assertFalse(self.widget.control.isEnabled()) diff -Nru python-pyface-4.5.2/pyface/tests/test_window.py python-pyface-6.1.2/pyface/tests/test_window.py --- python-pyface-4.5.2/pyface/tests/test_window.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/tests/test_window.py 2019-06-14 12:22:56.000000000 +0000 @@ -1,170 +1,277 @@ from __future__ import absolute_import -from traits.testing.unittest_tools import unittest, UnittestTools +import platform +import unittest from ..constant import CANCEL, NO, OK, YES -from ..gui import GUI from ..toolkit import toolkit_object from ..window import Window -ModalDialogTester = toolkit_object('util.modal_dialog_tester:ModalDialogTester') +is_qt = toolkit_object.toolkit == 'qt4' +if is_qt: + from pyface.qt import qt_api + +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') + +ModalDialogTester = toolkit_object( + 'util.modal_dialog_tester:ModalDialogTester' +) no_modal_dialog_tester = (ModalDialogTester.__name__ == 'Unimplemented') +is_pyqt5 = (is_qt and qt_api == 'pyqt5') +is_pyqt4_linux = (is_qt and qt_api == 'pyqt' and platform.system() == 'Linux') -class TestWindow(unittest.TestCase, UnittestTools): +@unittest.skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestWindow(unittest.TestCase, GuiTestAssistant): def setUp(self): - self.gui = GUI() + GuiTestAssistant.setUp(self) self.window = Window() + def tearDown(self): + if self.window.control is not None: + with self.delete_widget(self.window.control): + self.window.destroy() + self.window = None + GuiTestAssistant.tearDown(self) + def test_destroy(self): # test that destroy works even when no control - self.window.destroy() + with self.event_loop(): + self.window.destroy() def test_open_close(self): # test that opening and closing works as expected with self.assertTraitChanges(self.window, 'opening', count=1): with self.assertTraitChanges(self.window, 'opened', count=1): - self.window.open() - self.gui.process_events() + with self.event_loop(): + self.window.open() + with self.assertTraitChanges(self.window, 'closing', count=1): with self.assertTraitChanges(self.window, 'closed', count=1): - self.window.close() - self.gui.process_events() + with self.event_loop(): + self.window.close() def test_show(self): # test that showing works as expected - self.window._create() - self.window.show(True) - self.gui.process_events() - self.window.show(False) - self.gui.process_events() - self.window.destroy() + with self.event_loop(): + self.window._create() + with self.event_loop(): + self.window.show(True) + with self.event_loop(): + self.window.show(False) + with self.event_loop(): + self.window.destroy() def test_activate(self): # test that activation works as expected - self.window.open() - self.gui.process_events() - self.window.activate() - self.gui.process_events() - self.window.close() + with self.event_loop(): + self.window.open() + with self.event_loop(): + self.window.activate() + with self.event_loop(): + self.window.close() def test_position(self): # test that default position works as expected self.window.position = (100, 100) - self.window.open() - self.gui.process_events() - self.window.close() + with self.event_loop(): + self.window.open() + with self.event_loop(): + self.window.close() def test_reposition(self): # test that changing position works as expected - self.window.open() - self.gui.process_events() - self.window.position = (100, 100) - self.gui.process_events() - self.window.close() + with self.event_loop(): + self.window.open() + with self.event_loop(): + self.window.position = (100, 100) + with self.event_loop(): + self.window.close() def test_size(self): # test that default size works as expected self.window.size = (100, 100) - self.window.open() - self.gui.process_events() - self.window.close() + with self.event_loop(): + self.window.open() + with self.event_loop(): + self.window.close() def test_resize(self): # test that changing size works as expected - self.window.open() - self.gui.process_events() - self.window.size = (100, 100) - self.gui.process_events() - self.window.close() + with self.event_loop(): + self.window.open() + with self.event_loop(): + self.window.size = (100, 100) + with self.event_loop(): + self.window.close() def test_title(self): # test that default title works as expected self.window.title = "Test Title" - self.window.open() - self.gui.process_events() - self.window.close() + with self.event_loop(): + self.window.open() + with self.event_loop(): + self.window.close() def test_retitle(self): # test that changing title works as expected - self.window.open() - self.gui.process_events() - self.window.title = "Test Title" - self.gui.process_events() - self.window.close() + with self.event_loop(): + self.window.open() + with self.event_loop(): + self.window.title = "Test Title" + with self.event_loop(): + self.window.close() + + def test_show_event(self): + with self.event_loop(): + self.window.open() + with self.event_loop(): + self.window.visible = False + + with self.assertTraitChanges(self.window, 'visible', count=1): + with self.event_loop(): + self.window.control.show() + + self.assertTrue(self.window.visible) + + def test_hide_event(self): + with self.event_loop(): + self.window.open() + + with self.assertTraitChanges(self.window, 'visible', count=1): + with self.event_loop(): + self.window.control.hide() + + self.assertFalse(self.window.visible) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) def test_confirm_reject(self): # test that cancel works as expected tester = ModalDialogTester( - lambda: self.window.confirm("message", cancel=True)) + lambda: self.window.confirm("message", cancel=True) + ) tester.open_and_run(when_opened=lambda x: x.close(accept=False)) + self.assertEqual(tester.result, CANCEL) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) def test_confirm_yes(self): # test that yes works as expected tester = ModalDialogTester(lambda: self.window.confirm("message")) tester.open_and_wait(when_opened=lambda x: x.click_button(YES)) - self.gui.process_events() + self.assertEqual(tester.result, YES) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) def test_confirm_no(self): # test that no works as expected tester = ModalDialogTester(lambda: self.window.confirm("message")) tester.open_and_wait(when_opened=lambda x: x.click_button(NO)) - self.gui.process_events() + self.assertEqual(tester.result, NO) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') + @unittest.skipIf( + is_pyqt5, "Confirmation dialog click tests don't work on pyqt5." + ) + @unittest.skipIf( + is_pyqt4_linux, + "Confirmation dialog click tests don't work reliably on linux. Issue #282." + ) def test_confirm_cancel(self): # test that cncel works as expected tester = ModalDialogTester( - lambda: self.window.confirm("message", cancel=True)) + lambda: self.window.confirm("message", cancel=True) + ) tester.open_and_wait(when_opened=lambda x: x.click_button(CANCEL)) - self.gui.process_events() + self.assertEqual(tester.result, CANCEL) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_information_accept(self): - # test that information works as expected - tester = ModalDialogTester(lambda: self.window.information("message")) - tester.open_and_run(when_opened=lambda x: x.close(accept=True)) - self.assertIsNone(tester.result) + self._check_message_dialog_accept(self.window.information) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') + @unittest.skipIf( + is_pyqt5, "Message dialog click tests don't work on pyqt5." + ) + @unittest.skipIf( + is_pyqt4_linux, + "Message dialog click tests don't work reliably on linux. Issue #282." + ) def test_information_ok(self): - # test that information works as expected - tester = ModalDialogTester(lambda: self.window.information("message")) - tester.open_and_wait(when_opened=lambda x: x.click_button(OK)) - self.assertIsNone(tester.result) + self._check_message_dialog_ok(self.window.information) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_warning_accept(self): - # test that warning works as expected - tester = ModalDialogTester(lambda: self.window.warning("message")) - tester.open_and_run(when_opened=lambda x: x.close(accept=True)) - self.assertIsNone(tester.result) + self._check_message_dialog_accept(self.window.warning) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') + @unittest.skipIf( + is_pyqt5, "Message dialog click tests don't work on pyqt5." + ) + @unittest.skipIf( + is_pyqt4_linux, + "Message dialog click tests don't work reliably on linux. Issue #282." + ) def test_warning_ok(self): - # test that warning works as expected - tester = ModalDialogTester(lambda: self.window.warning("message")) - tester.open_and_wait(when_opened=lambda x: x.click_button(OK)) - self.assertIsNone(tester.result) + self._check_message_dialog_ok(self.window.warning) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') def test_error_accept(self): - # test that error works as expected - tester = ModalDialogTester(lambda: self.window.error("message")) - tester.open_and_run(when_opened=lambda x: x.close(accept=True)) - self.assertIsNone(tester.result) + self._check_message_dialog_accept(self.window.error) @unittest.skipIf(no_modal_dialog_tester, 'ModalDialogTester unavailable') + @unittest.skipIf( + is_pyqt5, "Message dialog click tests don't work on pyqt5." + ) + @unittest.skipIf( + is_pyqt4_linux, + "Message dialog click tests don't work reliably on linux. Issue #282." + ) def test_error_ok(self): - # test that error works as expected - tester = ModalDialogTester(lambda: self.window.error("message")) + self._check_message_dialog_ok(self.window.error) + + def _check_message_dialog_ok(self, method): + tester = self._setup_tester(method) tester.open_and_wait(when_opened=lambda x: x.click_button(OK)) + + self.assertIsNone(tester.result) + + def _check_message_dialog_accept(self, method): + tester = self._setup_tester(method) + tester.open_and_run(when_opened=lambda x: x.close(accept=True)) + self.assertIsNone(tester.result) + + def _setup_tester(self, method): + kwargs = { + 'title': 'Title', + 'detail': 'Detail', + 'informative': 'Informative' + } + tester = ModalDialogTester(lambda: method("message", **kwargs)) + return tester diff -Nru python-pyface-4.5.2/pyface/timer/api.py python-pyface-6.1.2/pyface/timer/api.py --- python-pyface-4.5.2/pyface/timer/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/timer/api.py 2019-05-03 08:18:49.000000000 +0000 @@ -11,5 +11,9 @@ # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ -from timer import Timer -from do_later import do_later, do_after, DoLaterTimer + +from __future__ import absolute_import + +from .do_later import do_later, do_after, DoLaterTimer +from .i_timer import ICallbackTimer, IEventTimer, ITimer +from .timer import CallbackTimer, EventTimer, Timer diff -Nru python-pyface-4.5.2/pyface/timer/do_later.py python-pyface-6.1.2/pyface/timer/do_later.py --- python-pyface-4.5.2/pyface/timer/do_later.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/timer/do_later.py 2019-06-03 10:58:47.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2005-18, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -10,42 +9,58 @@ # # Author: Enthought, Inc. # Description: -#------------------------------------------------------------------------------ -#------------------------------------------------------------------------------- -# -# Provides a simple function for scheduling some code to run at some time in -# the future (assumes application is wxPython based). -# -# Written by: David C. Morrill -# -# Date: 05/18/2005 -# -# (c) Copyright 2005 by Enthought, Inc. -# -#------------------------------------------------------------------------------- -#------------------------------------------------------------------------------- -# Imports: -#------------------------------------------------------------------------------- +from pyface.timer.timer import CallbackTimer, Timer + -# Import the toolkit specific version. -from pyface.toolkit import toolkit_object -DoLaterTimer = toolkit_object('timer.do_later:DoLaterTimer') +class DoLaterTimer(Timer): + """ Performs a callback once at a later time. -#------------------------------------------------------------------------------- -# Does something 50 milliseconds from now: -#------------------------------------------------------------------------------- + This is not used by the `do_later` functions and is only provided for + backwards compatibility of the API. + """ + + #: The perform the callback once. + repeat = 1 + + def __init__(self, interval, callable, args, kw_args): + # Adapt the old DoLaterTimer initializer to the Timer initializer. + super(DoLaterTimer, self).__init__(interval, callable, *args, **kw_args) -def do_later ( callable, *args, **kw_args ): + +def do_later(callable, *args, **kwargs): """ Does something 50 milliseconds from now. + + Parameters + ---------- + callable : callable + The callable to call in 50ms time. + *args, **kwargs : + Arguments to be passed through to the callable. """ - DoLaterTimer( 50, callable, args, kw_args ) + return CallbackTimer.single_shot( + interval=0.05, + callback=callable, + args=args, + kwargs=kwargs, + ) -#------------------------------------------------------------------------------- -# Does something after some specified time interval: -#------------------------------------------------------------------------------- -def do_after ( interval, callable, *args, **kw_args ): +def do_after(interval, callable, *args, **kwargs): """ Does something after some specified time interval. + + Parameters + ---------- + interval : float + The time interval in milliseconds to wait before calling. + callable : callable + The callable to call. + *args, **kwargs : + Arguments to be passed through to the callable. """ - DoLaterTimer( interval, callable, args, kw_args ) + return CallbackTimer.single_shot( + interval=interval / 1000.0, + callback=callable, + args=args, + kwargs=kwargs, + ) diff -Nru python-pyface-4.5.2/pyface/timer/i_timer.py python-pyface-6.1.2/pyface/timer/i_timer.py --- python-pyface-4.5.2/pyface/timer/i_timer.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/timer/i_timer.py 2019-07-20 11:46:59.000000000 +0000 @@ -0,0 +1,294 @@ +# Copyright (c) 2018, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# +# Thanks for using Enthought open source! +# +# Author: Corran Webster +""" +Interfaces and base classes for cross-toolkit timers + +This module defines interfaces for toolkit event-loop based timers. It also +provides a base implementation that can be easily specialized for a particular +back-end, and mixins that provide additional capabilities. +""" +from abc import abstractmethod +import sys +import time + +from traits.api import ( + ABCHasTraits, Bool, Callable, Dict, Either, Event, Float, HasTraits, Int, + Interface, Property, Range, Tuple, provides +) + +if sys.version_info[:2] < (3, 3): + import timeit + perf_counter = timeit.default_timer +else: + perf_counter = time.perf_counter + + +class ITimer(Interface): + """ Interface for timer classes. + + This is a base interface which doesn't specify any particular notification + mechanism. + """ + + # ITimer interface ------------------------------------------------------- + + #: The interval at which to call the callback in seconds. + interval = Range(low=0.0) + + #: The number of times to repeat the callback, or None if no limit. + repeat = Either(None, Int) + + #: The maximum length of time to run in seconds, or None if no limit. + expire = Either(None, Float) + + #: Whether or not the timer is currently running. + active = Bool + + # ------------------------------------------------------------------------- + # ITimer interface + # ------------------------------------------------------------------------- + + @classmethod + def timer(cls, **traits): + """ Convenience method that creates and starts a timer. + """ + pass + + @classmethod + def single_shot(cls, **traits): + """ Convenience method that creates and starts a single-shot timer. + """ + pass + + def start(self): + """ Start the timer. """ + pass + + def stop(self): + """ Stop the timer. """ + pass + + def perform(self): + """ The method that will be called by the timer. """ + pass + + +class IEventTimer(ITimer): + """ Interface for timers which fire a trait event periodically. """ + + # IEventTimer interface -------------------------------------------------- + + #: A traits Event to fire when the callback happens. + timeout = Event + + +class ICallbackTimer(ITimer): + """ Interface for timers which call a callback periodically. """ + + # ICallbackTimer interface ----------------------------------------------- + + #: The callback to make, or None if no callback. + callback = Callable + + #: Positional arguments to give the callback. + args = Tuple + + #: Keyword arguments to give the callback. + kwargs = Dict + + +@provides(ITimer) +class BaseTimer(ABCHasTraits): + """ Base class for timer classes. + + This class has a class variable which tracks active timers to prevent + failures caused by garbage collection. A timer is added to this tracker + when it is started if the repeat value is not None. + """ + + # BaseTimer interface ---------------------------------------------------- + + #: Class variable tracking all active timers. + _active_timers = set() + + # ITimer interface ------------------------------------------------------- + + #: The interval at which to call the callback in seconds. + interval = Range(low=0.0, value=0.05) + + #: The number of times to repeat the callback, or None if no limit. + repeat = Either(None, Int) + + #: The maximum length of time to run in seconds, or None if no limit. + expire = Either(None, Float) + + #: Property that controls the state of the timer. + active = Property(Bool, depends_on='_active') + + # Private interface ------------------------------------------------------ + + #: Whether or not the timer is currently running. + _active = Bool + + #: The most recent start time. + _start_time = Float + + # ------------------------------------------------------------------------- + # ITimer interface + # ------------------------------------------------------------------------- + + @classmethod + def timer(cls, **traits): + """ Convenience method that creates and starts a timer. + """ + timer = cls(**traits) + timer.start() + return timer + + @classmethod + def single_shot(cls, **traits): + timer = cls(repeat=1, **traits) + timer.start() + return timer + + def start(self): + """ Start the timer. """ + if not self._active: + if self.repeat is not None: + self._active_timers.add(self) + if self.expire is not None: + self._start_time = perf_counter() + self._active = True + self._start() + + def stop(self): + """ Stop the timer. """ + if self._active: + self._active_timers.discard(self) + self._stop() + self._active = False + + def perform(self): + """ Perform the callback. + + The timer will stop if repeats is not None and less than 1, or if + the `_perform` method raises StopIteration. + """ + if self.expire is not None: + if perf_counter() - self._start_time > self.expire: + self.stop() + return + + if self.repeat is not None: + self.repeat -= 1 + + try: + self._perform() + except StopIteration: + self.stop() + except: + self.stop() + raise + else: + if self.repeat is not None and self.repeat <= 0: + self.stop() + self.repeat = 0 + + # BaseTimer Protected methods + + def _start(self): + """ Start the toolkit timer. + + Subclasses should overrided this method. + """ + raise NotImplementedError() + + def _stop(self): + """ Stop the toolkit timer. + + Subclasses should overrided this method. + """ + raise NotImplementedError() + + @abstractmethod + def _perform(self): + """ perform the appropriate action. + + Subclasses should overrided this method. + """ + raise NotImplementedError() + + # ------------------------------------------------------------------------- + # Private interface + # ------------------------------------------------------------------------- + + # Trait property handlers ------------------------------------------------ + + def _get_active(self): + return self._active + + def _set_active(self, value): + if value: + self.start() + else: + self.stop() + + +@provides(IEventTimer) +class MEventTimer(HasTraits): + """ Mixin for event timer classes. + + Other code can listen to the `timeout` event using standard traits + listeners. + """ + + # IEventTimer interface -------------------------------------------------- + + #: A traits Event to fire when the callback happens. + timeout = Event + + # ------------------------------------------------------------------------- + # ITimer interface + # ------------------------------------------------------------------------- + + # ITimer Protected methods ----------------------------------------------- + + def _perform(self): + """ Fire the event. """ + self.timeout = True + + +@provides(ITimer) +class MCallbackTimer(HasTraits): + """ Mixin for callback timer classes. + """ + + # ICallbackTimer interface ----------------------------------------------- + + #: The callback to make. + callback = Callable + + #: Positional arguments to give the callback. + args = Tuple + + #: Keyword arguments to give the callback. + kwargs = Dict + + # ------------------------------------------------------------------------- + # ITimer interface + # ------------------------------------------------------------------------- + + # ITimer Protected methods ----------------------------------------------- + + def _perform(self): + """ Perform the callback. """ + self.callback(*self.args, **self.kwargs) diff -Nru python-pyface-4.5.2/pyface/timer/tests/test_do_later.py python-pyface-6.1.2/pyface/timer/tests/test_do_later.py --- python-pyface-4.5.2/pyface/timer/tests/test_do_later.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/timer/tests/test_do_later.py 2019-06-20 08:48:12.000000000 +0000 @@ -0,0 +1,129 @@ +from __future__ import print_function + +import time +from unittest import TestCase, skipIf + +from pyface.toolkit import toolkit_object +from ..i_timer import perf_counter +from ..do_later import DoLaterTimer, do_after, do_later + +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') + + +class ConditionHandler(object): + def __init__(self): + self.count = 0 + self.times = [] + + def callback(self): + self.times.append(perf_counter()) + self.count += 1 + + +@skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestDoLaterTimer(TestCase, GuiTestAssistant): + """ Test the DoLaterTimer. """ + + def setUp(self): + GuiTestAssistant.setUp(self) + + def tearDown(self): + GuiTestAssistant.tearDown(self) + + def test_basic(self): + handler = ConditionHandler() + start_time = perf_counter() + length = 500 + timer = DoLaterTimer(length, handler.callback, (), {}) + + try: + self.assertTrue(timer.active) + self.event_loop_helper.event_loop_until_condition( + lambda: not timer.active + ) + self.assertFalse(timer.active) + finally: + timer.stop() + + self.assertEqual(handler.count, 1) + + # should take no less than 85% of time requested + expected_length = (length / 1000.0) * 0.85 + expected_time = start_time + expected_length + + self.assertLessEqual( + expected_time, + handler.times[0], + "Expected call after {} seconds, took {} seconds)".format( + expected_length, + handler.times[0] - start_time + ) + ) + + +@skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestDoLater(TestCase, GuiTestAssistant): + """ Test do_later. """ + + def setUp(self): + GuiTestAssistant.setUp(self) + + def tearDown(self): + GuiTestAssistant.tearDown(self) + + def test_basic(self): + handler = ConditionHandler() + timer = do_later(handler.callback) + + try: + self.assertTrue(timer.active) + self.event_loop_helper.event_loop_until_condition( + lambda: not timer.active + ) + self.assertFalse(timer.active) + finally: + timer.stop() + + self.assertEqual(handler.count, 1) + + +@skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestDoAfter(TestCase, GuiTestAssistant): + """ Test do_after. """ + + def setUp(self): + GuiTestAssistant.setUp(self) + + def tearDown(self): + GuiTestAssistant.tearDown(self) + + def test_basic(self): + handler = ConditionHandler() + start_time = perf_counter() + length = 500 + timer = do_after(length, handler.callback) + + try: + self.assertTrue(timer.active) + self.event_loop_helper.event_loop_until_condition( + lambda: not timer.active + ) + self.assertFalse(timer.active) + finally: + timer.stop() + + self.assertEqual(handler.count, 1) + + # should take no less than 85% of time requested + expected_length = (length / 1000.0) * 0.85 + expected_time = start_time + expected_length + + self.assertLessEqual( + expected_time, + handler.times[0], + "Expected call after {} seconds, took {} seconds)".format( + expected_length, + handler.times[0] - start_time + ) + ) diff -Nru python-pyface-4.5.2/pyface/timer/tests/test_timer.py python-pyface-6.1.2/pyface/timer/tests/test_timer.py --- python-pyface-4.5.2/pyface/timer/tests/test_timer.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/timer/tests/test_timer.py 2019-07-20 11:46:59.000000000 +0000 @@ -0,0 +1,429 @@ +from __future__ import print_function +import time +from unittest import TestCase, skipIf + +from pyface.toolkit import toolkit_object +from ..i_timer import perf_counter +from ..timer import CallbackTimer, EventTimer, Timer + +GuiTestAssistant = toolkit_object('util.gui_test_assistant:GuiTestAssistant') +no_gui_test_assistant = (GuiTestAssistant.__name__ == 'Unimplemented') + + +class ConditionHandler(object): + def __init__(self): + self.count = 0 + self.times = [] + self.called = False + + def callback(self): + self.times.append(perf_counter()) + self.count += 1 + self.called = True + + def is_called(self): + return self.called + + def called_n(self, repeat): + return lambda: self.count >= repeat + + +@skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestEventTimer(TestCase, GuiTestAssistant): + """ Test the EventTimer. """ + + def setUp(self): + GuiTestAssistant.setUp(self) + + def tearDown(self): + GuiTestAssistant.tearDown(self) + + def test_basic(self): + timer = EventTimer() + + self.assertIsNone(timer.repeat) + self.assertFalse(timer.active) + timer.start() + try: + self.assertTrue(timer.active) + self.event_loop_helper.event_loop() + self.assertTrue(timer.active) + finally: + timer.stop() + self.assertFalse(timer.active) + + def test_timer_method(self): + timer = EventTimer.timer() + try: + self.assertTrue(timer.active) + self.event_loop_helper.event_loop() + self.assertTrue(timer.active) + finally: + timer.stop() + self.assertFalse(timer.active) + + def test_single_shot_method(self): + timer = EventTimer.single_shot() + handler = ConditionHandler() + timer.on_trait_change(handler.callback, 'timeout') + try: + self.assertTrue(timer.active) + self.event_loop_helper.event_loop_until_condition( + lambda: not timer.active + ) + self.assertFalse(timer.active) + finally: + timer.stop() + self.assertFalse(timer.active) + self.assertEqual(handler.count, 1) + + def test_set_active(self): + timer = EventTimer() + + self.assertIsNone(timer.repeat) + self.assertFalse(timer.active) + timer.active = True + try: + self.assertTrue(timer.active) + self.event_loop_helper.event_loop() + self.assertTrue(timer.active) + finally: + timer.active = False + self.assertFalse(timer.active) + + def test_timeout_event(self): + timer = EventTimer() + handler = ConditionHandler() + timer.on_trait_change(handler.callback, 'timeout') + + timer.start() + try: + self.event_loop_helper.event_loop_until_condition( + handler.is_called + ) + finally: + timer.stop() + + def test_repeat(self): + timer = EventTimer(repeat=4) + handler = ConditionHandler() + timer.on_trait_change(handler.callback, 'timeout') + + timer.start() + try: + self.event_loop_helper.event_loop_until_condition( + lambda: not timer.active + ) + self.assertFalse(timer.active) + finally: + timer.stop() + self.assertEqual(handler.count, 4) + + def test_interval(self): + timer = EventTimer(repeat=4, interval=0.1) + handler = ConditionHandler() + timer.on_trait_change(handler.callback, 'timeout') + + timer.start() + try: + self.event_loop_helper.event_loop_until_condition( + lambda: not timer.active + ) + self.assertFalse(timer.active) + finally: + timer.stop() + self.assertEqual(handler.count, 4) + + expected_times = [timer._start_time + 0.1 * i + 0.1 for i in range(4)] + + # give feedback in case of failure + if not all( + expected <= actual + for expected, actual in zip(expected_times, handler.times) + ): + print(handler.times) + + self.assertTrue( + all( + expected <= actual + for expected, actual in zip(expected_times, handler.times) + ) + ) + + def test_expire(self): + timer = EventTimer(expire=1.0, interval=0.1) + handler = ConditionHandler() + timer.on_trait_change(handler.callback, 'timeout') + + timer.start() + try: + self.event_loop_helper.event_loop_until_condition( + lambda: not timer.active + ) + self.assertFalse(timer.active) + finally: + timer.stop() + + # give feedback in case of failure + if not all( + t < timer._start_time + timer.expire + 0.01 for t in handler.times + ): + print(handler.times[-1], timer._start_time + timer.expire) + + self.assertTrue( + all( + t < timer._start_time + timer.expire + 0.01 + for t in handler.times + ) + ) + + +@skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestCallbackTimer(TestCase, GuiTestAssistant): + """ Test the CallbackTimer. """ + + def setUp(self): + GuiTestAssistant.setUp(self) + + def tearDown(self): + GuiTestAssistant.tearDown(self) + + def test_basic(self): + handler = ConditionHandler() + timer = CallbackTimer(callback=handler.callback) + + self.assertIsNone(timer.repeat) + self.assertFalse(timer.active) + timer.start() + try: + self.assertTrue(timer.active) + self.event_loop_helper.event_loop() + self.assertTrue(timer.active) + finally: + timer.stop() + self.assertFalse(timer.active) + + def test_timer_method(self): + handler = ConditionHandler() + + timer = CallbackTimer.timer(callback=handler.callback) + try: + self.assertTrue(timer.active) + self.event_loop_helper.event_loop() + self.assertTrue(timer.active) + finally: + timer.stop() + self.assertFalse(timer.active) + + def test_single_shot_method(self): + handler = ConditionHandler() + + timer = CallbackTimer.single_shot(callback=handler.callback) + try: + self.assertTrue(timer.active) + self.event_loop_helper.event_loop_until_condition( + lambda: not timer.active + ) + self.assertFalse(timer.active) + finally: + timer.stop() + self.assertFalse(timer.active) + self.assertEqual(handler.count, 1) + + def test_set_active(self): + handler = ConditionHandler() + timer = CallbackTimer(callback=handler.callback) + + self.assertIsNone(timer.repeat) + self.assertFalse(timer.active) + timer.active = True + try: + self.assertTrue(timer.active) + self.event_loop_helper.event_loop() + self.assertTrue(timer.active) + finally: + timer.active = False + self.assertFalse(timer.active) + + def test_timeout_event(self): + handler = ConditionHandler() + timer = CallbackTimer(callback=handler.callback) + + timer.start() + try: + self.event_loop_helper.event_loop_until_condition( + handler.is_called + ) + finally: + timer.stop() + + def test_repeat(self): + handler = ConditionHandler() + timer = CallbackTimer(callback=handler.callback, repeat=4) + + timer.start() + try: + self.event_loop_helper.event_loop_until_condition( + lambda: not timer.active + ) + self.assertFalse(timer.active) + finally: + timer.stop() + self.assertEqual(handler.count, 4) + + def test_interval(self): + handler = ConditionHandler() + timer = CallbackTimer( + callback=handler.callback, repeat=4, interval=0.1 + ) + + timer.start() + try: + self.event_loop_helper.event_loop_until_condition( + lambda: not timer.active + ) + self.assertFalse(timer.active) + finally: + timer.stop() + self.assertEqual(handler.count, 4) + + expected_times = [timer._start_time + 0.1 * i + 0.1 for i in range(4)] + + # give feedback in case of failure + if not all( + expected <= actual + for expected, actual in zip(expected_times, handler.times) + ): + print(handler.times) + + self.assertTrue( + all( + expected <= actual + for expected, actual in zip(expected_times, handler.times) + ) + ) + + def test_expire(self): + handler = ConditionHandler() + timer = CallbackTimer( + callback=handler.callback, interval=0.1, expire=1.0 + ) + + timer.start() + try: + self.event_loop_helper.event_loop_until_condition( + lambda: not timer.active + ) + self.assertFalse(timer.active) + finally: + timer.stop() + + # give feedback in case of failure + if not all( + t < timer._start_time + timer.expire + 0.01 for t in handler.times + ): + print(handler.times[-1], timer._start_time + timer.expire) + + self.assertTrue( + all( + t < timer._start_time + timer.expire + 0.01 + for t in handler.times + ) + ) + + def test_stop_iteration(self): + def do_stop_iteration(): + raise StopIteration() + + timer = CallbackTimer(callback=do_stop_iteration) + + timer.start() + try: + self.event_loop_helper.event_loop_until_condition( + lambda: not timer.active + ) + self.assertFalse(timer.active) + finally: + timer.stop() + + +@skipIf(no_gui_test_assistant, 'No GuiTestAssistant') +class TestTimer(TestCase, GuiTestAssistant): + """ Test the CallbackTimer. """ + + def setUp(self): + GuiTestAssistant.setUp(self) + + def tearDown(self): + GuiTestAssistant.tearDown(self) + + def test_basic(self): + handler = ConditionHandler() + + timer = Timer(250, handler.callback) + try: + self.assertTrue(timer.IsRunning()) + self.event_loop_helper.event_loop() + self.assertTrue(timer.IsRunning()) + finally: + timer.Stop() + + self.assertFalse(timer.IsRunning()) + + def test_restart(self): + handler = ConditionHandler() + + timer = Timer(20, handler.callback) + timer.Stop() + + # Ensure that it is indeed stopped. + self.assertFalse(timer.IsRunning()) + count = handler.count + + # Wait to see if the timer has indeed stopped. + self.event_loop_helper.event_loop() + time.sleep(0.1) + self.assertEqual(handler.count, count) + + timer.Start() + try: + self.assertTrue(timer.IsRunning()) + self.event_loop_helper.event_loop_until_condition( + lambda: handler.count > count + ) + self.assertTrue(timer.IsRunning()) + finally: + timer.Stop() + + self.assertFalse(timer.IsRunning()) + + def test_repeat(self): + handler = ConditionHandler() + + start_time = perf_counter() + timer = Timer(250, handler.callback) + try: + self.assertTrue(timer.IsRunning()) + self.event_loop_helper.event_loop_until_condition( + handler.called_n(4) + ) + self.assertTrue(timer.IsRunning()) + finally: + timer.Stop() + + self.assertFalse(timer.IsRunning()) + + self.assertEqual(handler.count, 4) + + expected_times = [start_time + 0.2 * i + 0.2 for i in range(4)] + + self.assertTrue( + all( + actual >= expected + for actual, expected in zip(handler.times, expected_times) + ), + "Expected calls after {} times, got {})".format( + expected_times, + handler.times + ) + ) diff -Nru python-pyface-4.5.2/pyface/timer/timer.py python-pyface-6.1.2/pyface/timer/timer.py --- python-pyface-4.5.2/pyface/timer/timer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/timer/timer.py 2019-07-20 11:46:59.000000000 +0000 @@ -1,9 +1,66 @@ -"""A timer that invokes a specified callback periodically. -""" -# Author: Prabhu Ramachandran -# Copyright (c) 2006-2007, Enthought, Inc. +# Author: Prabhu Ramachandran +# Copyright (c) 2006-2018, Enthought, Inc. # License: BSD Style. +""" +Event-loop based timers that perform actions periodically. + +Note that if a timer goes out of scope without a reference to being saved, +there is nothing keeping the underlying toolkit timer alive and it will be +garbage collected, meaning that the timer will stop firing (or indeed, may +never fire). +""" -# Import the toolkit specific version. from pyface.toolkit import toolkit_object -Timer = toolkit_object('timer.timer:Timer') +from pyface.timer.i_timer import MCallbackTimer, MEventTimer + +PyfaceTimer = toolkit_object('timer.timer:PyfaceTimer') + + +class EventTimer(MEventTimer, PyfaceTimer): + pass + + +class CallbackTimer(MCallbackTimer, PyfaceTimer): + pass + + +class Timer(CallbackTimer): + """ Subclass of CallbackTimer that matches the old API """ + + def __init__(self, millisecs, callable, *args, **kwargs): + """ Initialize and start the timer. + + Initialize instance to invoke the given `callable` with given + arguments and keyword args after every `millisecs` (milliseconds). + """ + interval = millisecs / 1000.0 + super(Timer, self).__init__( + interval=interval, + callback=callable, + args=args, + kwargs=kwargs, + ) + self.start() + + def Notify(self): + """ Alias for `perform` to match old API. + """ + self.perform() + + def Start(self, millisecs=None): + """ Alias for `start` to match old API. + """ + if millisecs is not None: + self.interval = millisecs / 1000.0 + + self.start() + + def Stop(self): + """ Alias for `stop` to match old API. + """ + self.stop() + + def IsRunning(self): + """ Alias for is_running property to match old API. + """ + return self._active diff -Nru python-pyface-4.5.2/pyface/toolkit.py python-pyface-6.1.2/pyface/toolkit.py --- python-pyface-4.5.2/pyface/toolkit.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/toolkit.py 2019-05-03 08:18:49.000000000 +0000 @@ -2,124 +2,26 @@ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # +# Copyright (c) 2015-2017, Enthought, Inc. +# All rights reserved. +# # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # +# Thanks for using Enthought open source! +# #------------------------------------------------------------------------------ +""" +This module provides the toolkit object for the current backend toolkit -# Standard library imports. -import os -import sys - -# Enthought library imports. -from traits.etsconfig.api import ETSConfig - - -# This is set to the root part of the module path for the selected backend. -_toolkit_backend = None - - -def _init_toolkit(): - """ Initialise the current toolkit. """ - - def import_toolkit(tk): - try: - # Try and import the toolkit's pyface backend init module. - be = 'pyface.ui.%s.' % tk - __import__(be + 'init') - except: - raise - return be - - # Get the toolkit. - if ETSConfig.toolkit: - be = import_toolkit(ETSConfig.toolkit) - else: - # Toolkits to check for if none is explicitly specified. - import warnings - warnings.warn("Default toolkit will change to 'qt4' in PyFace 5.0", - DeprecationWarning) - - known_toolkits = ('wx', 'qt4', 'null') - - for tk in known_toolkits: - try: - be = import_toolkit(tk) - - # In case we have just decided on a toolkit, tell everybody else. - ETSConfig.toolkit = tk - break - except (SystemExit, ImportError): - import traceback - print >>sys.stderr, ('Warning: Unable to import the %s backend ' - 'for pyface due to traceback: %s\n') % (tk, - traceback.format_exc().strip().replace('\n', '\n\t')) - - else: - # Try to import the null toolkit but don't set the ETSConfig toolkit - try: - be = import_toolkit('null') - print >>sys.stderr, ("Info: Unable to import any backend (%s) " - "for pyface; using the 'null' toolkit instead.\n") % ", ".join(known_toolkits) - except: - raise ImportError("Unable to import a pyface backend for any " - "of the %s toolkits" % ", ".join(known_toolkits)) - - - # Save the imported toolkit module. - global _toolkit_backend - _toolkit_backend = be - - -# Do this once then disappear. -_init_toolkit() -del _init_toolkit - - -def toolkit_object(name): - """ Return the toolkit specific object with the given name. The name - consists of the relative module path and the object name separated by a - colon. - """ - - mname, oname = name.split(':') - be_mname = _toolkit_backend + mname - - class Unimplemented(object): - """ This is returned if an object isn't implemented by the selected - toolkit. It raises an exception if it is ever instantiated. - """ - - def __init__(self, *args, **kwargs): - raise NotImplementedError("the %s pyface backend doesn't implement %s" % (ETSConfig.toolkit, oname)) - - be_obj = Unimplemented - - try: - __import__(be_mname) - - try: - be_obj = getattr(sys.modules[be_mname], oname) - except AttributeError: - pass - except ImportError as exc: - # is the error while trying to import be_mname or not? - if not exc.message.endswith(mname): - # something else went wrong - let the exception be raised - raise +See :py_func:`pyface.base_toolkit.find_toolkit` for details on the loading +algorithm. +""" - # Ignore *ANY* errors unless a debug ENV variable is set. - if 'ETS_DEBUG' in os.environ: +from .base_toolkit import find_toolkit - # Attempt to only skip errors in importing the backend modules. - # The idea here is that this only happens when the last entry in - # the traceback's stack frame mentions the toolkit in question. - import traceback - frames = traceback.extract_tb(sys.exc_traceback) - filename, lineno, function, text = frames[-1] - if not _toolkit_backend in filename: - raise - return be_obj +# The toolkit function. +toolkit = toolkit_object = find_toolkit('pyface.toolkits') diff -Nru python-pyface-4.5.2/pyface/tree/api.py python-pyface-6.1.2/pyface/tree/api.py --- python-pyface-4.5.2/pyface/tree/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tree/api.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2005-2011, Enthought, Inc. +# Copyright (c) 2005-2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -12,19 +12,17 @@ # Description: #------------------------------------------------------------------------------ -from node_event import NodeEvent -from node_monitor import NodeMonitor -from node_manager import NodeManager -from node_tree import NodeTree -from node_tree_model import NodeTreeModel -from node_type import NodeType -from trait_dict_node_type import TraitDictNodeType -from trait_list_node_type import TraitListNodeType -from tree_model import TreeModel +from __future__ import absolute_import -from traits.etsconfig.api import ETSConfig -if ETSConfig.toolkit == 'wx': - # Tree has not yet been ported to qt - from tree import Tree +from .node_event import NodeEvent +from .node_monitor import NodeMonitor +from .node_manager import NodeManager +from .node_tree import NodeTree +from .node_tree_model import NodeTreeModel +from .node_type import NodeType +from .trait_dict_node_type import TraitDictNodeType +from .trait_list_node_type import TraitListNodeType +from .tree_model import TreeModel -del ETSConfig +# Tree has not yet been ported to qt +from .tree import Tree diff -Nru python-pyface-4.5.2/pyface/tree/node_manager.py python-pyface-6.1.2/pyface/tree/node_manager.py --- python-pyface-4.5.2/pyface/tree/node_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tree/node_manager.py 2019-05-03 08:18:49.000000000 +0000 @@ -20,7 +20,7 @@ from traits.api import HasPrivateTraits, List # Local imports -from node_type import NodeType +from .node_type import NodeType # Create a logger for this module. diff -Nru python-pyface-4.5.2/pyface/tree/node_monitor.py python-pyface-6.1.2/pyface/tree/node_monitor.py --- python-pyface-4.5.2/pyface/tree/node_monitor.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tree/node_monitor.py 2019-05-03 08:18:49.000000000 +0000 @@ -20,7 +20,7 @@ from traits.api import Any, Event, HasTraits # Local imports. -from node_event import NodeEvent +from .node_event import NodeEvent # Create a logger for this module. diff -Nru python-pyface-4.5.2/pyface/tree/node_tree_model.py python-pyface-6.1.2/pyface/tree/node_tree_model.py --- python-pyface-4.5.2/pyface/tree/node_tree_model.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tree/node_tree_model.py 2019-05-03 08:18:49.000000000 +0000 @@ -18,8 +18,8 @@ from traits.api import Dict, Instance # Local imports. -from node_manager import NodeManager -from tree_model import TreeModel +from .node_manager import NodeManager +from .tree_model import TreeModel class NodeTreeModel(TreeModel): diff -Nru python-pyface-4.5.2/pyface/tree/node_tree.py python-pyface-6.1.2/pyface/tree/node_tree.py --- python-pyface-4.5.2/pyface/tree/node_tree.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tree/node_tree.py 2019-05-03 08:18:49.000000000 +0000 @@ -15,17 +15,22 @@ # Standard library imports. -import inspect +import six +if six.PY2: + from inspect import getargspec +else: + # avoid deprecation warning + from inspect import getfullargspec as getargspec # Enthought library imports. from pyface.action.api import ActionEvent from traits.api import Instance, List, Property # Local imports. -from node_manager import NodeManager -from node_type import NodeType -from node_tree_model import NodeTreeModel -from tree import Tree +from .node_manager import NodeManager +from .node_type import NodeType +from .node_tree_model import NodeTreeModel +from .tree import Tree class NodeTree(Tree): @@ -91,7 +96,7 @@ return - def _node_right_clicked_changed(self, (obj, point)): + def _node_right_clicked_changed(self, obj, point): """ Called when the right mouse button is clicked on the tree. """ # Add the node that the right-click occurred on to the selection. @@ -135,7 +140,7 @@ event.context = self._context # fixme: the 'perform' method without taking an event is deprecated! - args, varargs, varkw, defaults = inspect.getargspec(action.perform) + args, varargs, varkw, defaults = getargspec(action.perform) # If the only argument is 'self' then this is the DEPRECATED # interface. diff -Nru python-pyface-4.5.2/pyface/tree/trait_dict_node_type.py python-pyface-6.1.2/pyface/tree/trait_dict_node_type.py --- python-pyface-4.5.2/pyface/tree/trait_dict_node_type.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tree/trait_dict_node_type.py 2019-05-03 08:18:49.000000000 +0000 @@ -5,7 +5,7 @@ from traits.api import Any, Str # Local imports. -from node_type import NodeType +from .node_type import NodeType class TraitDictNodeType(NodeType): @@ -49,7 +49,7 @@ def get_children(self, node): """ Returns the children of a node. """ - return node.values() + return list(node.values()) def get_text(self, node): """ Returns the label text for a node. """ diff -Nru python-pyface-4.5.2/pyface/tree/trait_list_node_type.py python-pyface-6.1.2/pyface/tree/trait_list_node_type.py --- python-pyface-4.5.2/pyface/tree/trait_list_node_type.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tree/trait_list_node_type.py 2019-05-03 08:18:49.000000000 +0000 @@ -5,7 +5,7 @@ from traits.api import Any, Str # Local imports. -from node_type import NodeType +from .node_type import NodeType class TraitListNodeType(NodeType): diff -Nru python-pyface-4.5.2/pyface/tree/tree_model.py python-pyface-6.1.2/pyface/tree/tree_model.py --- python-pyface-4.5.2/pyface/tree/tree_model.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tree/tree_model.py 2019-05-03 08:18:49.000000000 +0000 @@ -18,7 +18,7 @@ from traits.api import Any, HasTraits, Event # Local imports. -from node_event import NodeEvent +from .node_event import NodeEvent class TreeModel(HasTraits): diff -Nru python-pyface-4.5.2/pyface/tree/tree.py python-pyface-6.1.2/pyface/tree/tree.py --- python-pyface-4.5.2/pyface/tree/tree.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/tree/tree.py 2019-05-03 08:18:49.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,1276 +6,11 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -""" A tree control with a model/ui architecture. """ - - -# Standard library imports. -import logging -import os - -# Major package imports. -import wx - -# Enthought library imports. -from pyface.api import Filter, GUI, KeyPressedEvent, Sorter, Widget -from pyface.image_list import ImageList -from traits.api import Any, Bool, Callable, Enum, Event, Instance -from traits.api import List, Property, Callable, Str, Trait, Tuple -from pyface.wx.drag_and_drop import PythonDropSource, PythonDropTarget - -# Local imports. -from tree_model import TreeModel - - -# Create a logger for this module. -logger = logging.getLogger(__name__) - - -class _Tree(wx.TreeCtrl): - """ The wx tree control that we delegate to. - - We use this derived class so that we can detect the destruction of the - tree and remove model listeners etc. - - """ - - ########################################################################### - # 'object' interface. - ########################################################################### - - def __init__(self, tree, parent, wxid, style): - """ Creates a new tree. """ - - # Base class constructor. - wx.TreeCtrl.__init__(self, parent, wxid, style=style) - - # The tree that we are the toolkit-specific delegate for. - self._tree = tree - - return - - def __del__(self): - """ Destructor. """ - - # Stop listenting to the model! - self._tree._remove_model_listeners(self._tree.model) - - return - - -class Tree(Widget): - """ A tree control with a model/ui architecture. """ - - # The default tree style. - STYLE = wx.TR_EDIT_LABELS | wx.TR_HAS_BUTTONS | wx.CLIP_CHILDREN - - #### 'Tree' interface ##################################################### - - # The tree's filters (empty if no filtering is required). - filters = List(Filter) - - # Mode for lines connecting tree nodes which emphasize hierarchy: - # 'appearance' - only on when lines look good, - # 'on' - always on, 'off' - always off - # NOTE: on and off are ignored in favor of show_lines for now - lines_mode = Enum('appearance', 'on', 'off') - - # The model that provides the data for the tree. - model = Instance(TreeModel, ()) - - # The root of the tree (this is for convenience, it just delegates to - # the tree's model). - root = Property(Any) - - # The objects currently selected in the tree. - selection = List - - # Selection mode. - selection_mode = Enum('single', 'extended') - - # Should an image be shown for each node? - show_images = Bool(True) - - # Should lines be drawn between levels in the tree. - show_lines = Bool(True) - - # Should the root of the tree be shown? - show_root = Bool(True) - - # The tree's sorter (None if no sorting is required). - sorter = Instance(Sorter) - - #### Events #### - - # A right-click occurred on the control (not a node!). - control_right_clicked = Event#(Point) - - # A key was pressed while the tree has focus. - key_pressed = Event(KeyPressedEvent) - - # A node has been activated (ie. double-clicked). - node_activated = Event#(Any) - - # A drag operation was started on a node. - node_begin_drag = Event#(Any) - - # A (non-leaf) node has been collapsed. - node_collapsed = Event#(Any) - - # A (non-leaf) node has been expanded. - node_expanded = Event#(Any) - - # A left-click occurred on a node. - # - # Tuple(node, point). - node_left_clicked = Event#(Tuple) - - # A right-click occurred on a node. - # - # Tuple(node, point) - node_right_clicked = Event#(Tuple) - - #### Private interface #################################################### - - # A name to distinguish the tree for debugging! - # - # fixme: This turns out to be kinda useful... Should 'Widget' have a name - # trait? - _name = Str('Anonymous tree') - - # An optional callback to detect the end of a label edit. This is - # useful because the callback will be invoked even if the node label was - # not actually changed. - _label_edit_callback = Trait(None, Callable, None) - - # Flag for allowing selection events to be ignored - _ignore_selection_events = Bool(False) - - ########################################################################### - # 'object' interface. - ########################################################################### - - def __init__(self, parent, image_size=(16, 16), **traits): - """ Creates a new tree. - - 'parent' is the toolkit-specific control that is the tree's parent. - - 'image_size' is a tuple in the form (int width, int height) that - specifies the size of the images (if required) displayed in the tree. - - """ - - # Base class constructors. - super(Tree, self).__init__(**traits) - - # Get our wx Id. - wxid = wx.NewId() - - # Create the toolkit-specific control. - self.control = tree = _Tree(self, parent, wxid,style=self._get_style()) - - # Wire up the wx tree events. - wx.EVT_CHAR(tree, self._on_char) - wx.EVT_LEFT_DOWN(tree, self._on_left_down) - # fixme: This is not technically correct as context menus etc should - # appear on a right up (or right click). Unfortunately, if we - # change this to 'EVT_RIGHT_UP' wx does not fire the event unless the - # right mouse button is double clicked 8^() Sad, but true! - wx.EVT_RIGHT_DOWN(tree, self._on_right_down) - # fixme: This is not technically correct as we would really like to use - # 'EVT_TREE_ITEM_ACTIVATED'. Unfortunately, (in 2.6 at least), it - # throws an exception when the 'Enter' key is pressed as the wx tree - # item Id in the event seems to be invalid. It also seems to cause - # any child frames that my be created in response to the event to - # appear *behind* the parent window, which is, errrr, not great ;^) - wx.EVT_LEFT_DCLICK(tree, self._on_tree_item_activated) - #wx.EVT_TREE_ITEM_ACTIVATED(tree, wxid, self._on_tree_item_activated) - wx.EVT_TREE_ITEM_COLLAPSING(tree, wxid, self._on_tree_item_collapsing) - wx.EVT_TREE_ITEM_COLLAPSED(tree, wxid, self._on_tree_item_collapsed) - wx.EVT_TREE_ITEM_EXPANDING(tree, wxid, self._on_tree_item_expanding) - wx.EVT_TREE_ITEM_EXPANDED(tree, wxid, self._on_tree_item_expanded) - wx.EVT_TREE_BEGIN_LABEL_EDIT(tree, wxid,self._on_tree_begin_label_edit) - wx.EVT_TREE_END_LABEL_EDIT(tree, wxid, self._on_tree_end_label_edit) - wx.EVT_TREE_BEGIN_DRAG(tree, wxid, self._on_tree_begin_drag) - wx.EVT_TREE_SEL_CHANGED(tree, wxid, self._on_tree_sel_changed) - wx.EVT_TREE_DELETE_ITEM(tree, wxid, self._on_tree_delete_item) - - # Enable the tree as a drag and drop target. - self.control.SetDropTarget(PythonDropTarget(self)) - - # The image list is a wxPython-ism that caches all images used in the - # control. - self._image_list = ImageList(image_size[0], image_size[1]) - if self.show_images: - tree.AssignImageList(self._image_list) - - # Mapping from node to wx tree item Ids. - self._node_to_id_map = {} - - # Add the root node. - if self.root is not None: - self._add_root_node(self.root) - - # Listen for changes to the model. - self._add_model_listeners(self.model) - - return - - ########################################################################### - # 'Tree' interface. - ########################################################################### - - #### Properties ########################################################### - - def _get_root(self): - """ Returns the root node of the tree. """ - - return self.model.root - - def _set_root(self, root): - """ Sets the root node of the tree. """ - - self.model.root = root - - return - - #### Methods ############################################################## - - def collapse(self, node): - """ Collapses the specified node. """ - - wxid = self._get_wxid(node) - if wxid is not None: - self.control.Collapse(wxid) - - return - - def edit_label(self, node, callback=None): - """ Edits the label of the specified node. - - If a callback is specified it will be called when the label edit - completes WHETHER OR NOT the label was actually changed. - - The callback must take exactly 3 arguments:- (tree, node, label) - - """ - - wxid = self._get_wxid(node) - if wxid is not None: - self._label_edit_callback = callback - self.control.EditLabel(wxid) - - return - - def expand(self, node): - """ Expands the specified node. """ - - wxid = self._get_wxid(node) - if wxid is not None: - self.control.Expand(wxid) - - return - - def expand_all(self): - """ Expands every node in the tree. """ - - if self.show_root: - self._expand_item(self._get_wxid(self.root)) - - else: - for child in self._get_children(self.root): - self._expand_item(self._get_wxid(child)) - - return - - def get_parent(self, node): - """ Returns the parent of a node. - - This will only work iff the node has been displayed in the tree. If it - hasn't then None is returned. - - """ - - # Has the node actually appeared in the tree yet? - wxid = self._get_wxid(node) - if wxid is not None: - pid = self.control.GetItemParent(wxid) - - # The item data is a tuple. The first element indicates whether or - # not we have already populated the item with its children. The - # second element is the actual item data. - populated, parent = self.control.GetPyData(pid) - - else: - parent = None - - return parent - - def is_expanded(self, node): - """ Returns True if the node is expanded, otherwise False. """ - - wxid = self._get_wxid(node) - if wxid is not None: - # If the root node is hidden then it is always expanded! - if node is self.root and not self.show_root: - is_expanded = True - - else: - is_expanded = self.control.IsExpanded(wxid) - - else: - is_expanded = False - - return is_expanded - - def is_selected(self, node): - """ Returns True if the node is selected, otherwise False. """ - - wxid = self._get_wxid(node) - if wxid is not None: - is_selected = self.control.IsSelected(wxid) - - else: - is_selected = False - - return is_selected - - def refresh(self, node): - """ Refresh the tree starting from the specified node. - - Call this when the structure of the content has changed DRAMATICALLY. - - """ - - # Has the node actually appeared in the tree yet? - pid = self._get_wxid(node) - if pid is not None: - # Delete all of the node's children and re-add them. - self.control.DeleteChildren(pid) - self.control.SetPyData(pid, (False, node)) - - # Does the node have any children? - has_children = self._has_children(node) - self.control.SetItemHasChildren(pid, has_children) - - # fixme: At least on Windows, wx does not fire an expanding - # event for a hidden root node, so we have to populate the node - # manually. - if node is self.root and not self.show_root: - # Add the child nodes. - for child in self._get_children(node): - self._add_node(pid, child) - - else: - # Expand it. - if self.control.IsExpanded(pid): - self.control.Collapse(pid) - - self.control.Expand(pid) - - return - - def select(self, node): - """ Selects the specified node. """ - - wxid = self._get_wxid(node) - if wxid is not None: - self.control.SelectItem(wxid) - - return - - def set_selection(self, list): - """ Selects the specified list of nodes. """ - logger.debug('Setting selection to [%s] within Tree [%s]', list, self) - - # Update the control to reflect the target list by unselecting - # everything and then selecting each item in the list. During this - # process, we want to avoid changing our own selection. - self._ignore_selection_events = True - self.control.UnselectAll() - for node in list: - try: - self.select(node) - except: - logger.exception('Unable to select node [%s]', node) - - self._ignore_selection_events = False - - # Update our selection to reflect the final selection state. - self.selection = self._get_selection() - - ########################################################################### - # 'PythonDropTarget' interface. - ########################################################################### - - def on_drag_over(self, x, y, obj, default_drag_result): - """ Called when a node is dragged over the tree. """ - - result = wx.DragNone - - # Find the node that we are dragging over... - node = self._get_drag_drop_node(x, y) - if node is not None: - # Ask the model if the node allows the object to be dropped onto - # it. - if self.model.can_drop(node, obj): - result = default_drag_result - - return result - - def on_drop(self, x, y, obj, default_drag_result): - """ Called when a node is dropped on the tree. """ - - # Find the node that we are dragging over... - node = self._get_drag_drop_node(x, y) - if node is not None: - self.model.drop(node, obj) - - return default_drag_result - - ########################################################################### - # Private interface. - ########################################################################### - - def _get_wxid(self, node): - """ Returns the wxid for the specified node. - - Returns None if the node has not yet appeared in the tree. - - """ - - # The model must generate a unique key for each node (unique within the - # model). - key = self.model.get_key(node) - - return self._node_to_id_map.get(key, None) - - def _set_wxid(self, node, wxid): - """ Sets the wxid for the specified node. """ - - # The model must generate a unique key for each node (unique within the - # model). - key = self.model.get_key(node) - - self._node_to_id_map[key] = wxid - - return - - def _remove_wxid(self, node): - """ Removes the wxid for the specified node. """ - - # The model must generate a unique key for each node (unique within the - # model). - key = self.model.get_key(node) - - try: - del self._node_to_id_map[key] - - except KeyError: - # fixme: No, really, this is a serious one... How do we get in this - # situation. It came up when using the canvas stuff... - logger.warn('removing node: %s' % str(node)) - - return - - def _get_style(self): - """ Returns the wx style flags for creating the tree control. """ - - # Start with the default flags. - style = self.STYLE - - # Turn lines off for appearance on *nix. - # ...for now, show_lines determines if lines are on or off, but - # eventually lines_mode may eliminate the need for show_lines - if self.lines_mode == 'appearance' and os.name == 'posix': - self.show_lines = False - - if not self.show_lines: - style = style | wx.TR_NO_LINES - - if not self.show_root: - # fixme: It looks a little weird, but it we don't have the - # 'lines at root' style then wx won't draw the expand/collapse - # image on non-leaf nodes at the root level 8^() - style = style | wx.TR_HIDE_ROOT | wx.TR_LINES_AT_ROOT - - if self.selection_mode != 'single': - style = style | wx.TR_MULTIPLE | wx.TR_EXTENDED - - return style - - def _add_model_listeners(self, model): - """ Adds listeners for model changes. """ - - # Listen for changes to the model. - model.on_trait_change(self._on_root_changed, 'root') - model.on_trait_change(self._on_nodes_changed, 'nodes_changed') - model.on_trait_change(self._on_nodes_inserted, 'nodes_inserted') - model.on_trait_change(self._on_nodes_removed, 'nodes_removed') - model.on_trait_change(self._on_nodes_replaced, 'nodes_replaced') - model.on_trait_change(self._on_structure_changed, 'structure_changed') - - return - - def _remove_model_listeners(self, model): - """ Removes listeners for model changes. """ - - # Unhook the model event listeners. - model.on_trait_change( - self._on_root_changed, 'root', remove=True - ) - - model.on_trait_change( - self._on_nodes_changed, 'nodes_changed', remove=True - ) - - model.on_trait_change( - self._on_nodes_inserted, 'nodes_inserted', remove=True - ) - - model.on_trait_change( - self._on_nodes_removed, 'nodes_removed', remove=True - ) - - model.on_trait_change( - self._on_nodes_replaced, 'nodes_replaced', remove=True - ) - - model.on_trait_change( - self._on_structure_changed, 'structure_changed', remove=True - ) - - return - - def _add_root_node(self, node): - """ Adds the root node. """ - - # Get the tree item image index and the label text. - image_index = self._get_image_index(node) - text = self._get_text(node) - - # Add the node. - wxid = self.control.AddRoot(text, image_index, image_index) - - # This gives the model a chance to wire up trait handlers etc. - self.model.add_listener(node) - - # If the root node is hidden, get its children. - if not self.show_root: - # Add the child nodes. - for child in self._get_children(node): - self._add_node(wxid, child) - - # Does the node have any children? - has_children = self._has_children(node) - self.control.SetItemHasChildren(wxid, has_children) - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data (which in our case is an arbitrary - # Python object provided by the tree model). - if self.show_root: - self.control.SetPyData(wxid, (not self.show_root, node)) - - # Make sure that we can find the node's Id. - self._set_wxid(node, wxid) - - # Automatically expand the root. - if self.show_root: - self.control.Expand(wxid) - - return - - def _add_node(self, pid, node): - """ Adds 'node' as a child of the node identified by 'pid'. - - If 'pid' is None then we are adding the root node. - - """ - - # Get the tree item image index and the label text. - image_index = self._get_image_index(node) - text = self._get_text(node) - - # Add the node. - wxid = self.control.AppendItem(pid, text, image_index, image_index) - - # This gives the model a chance to wire up trait handlers etc. - self.model.add_listener(node) - - # Does the node have any children? - has_children = self._has_children(node) - self.control.SetItemHasChildren(wxid, has_children) - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data (which in our case is an arbitrary - # Python object provided by the tree model). - self.control.SetPyData(wxid, (False, node)) - - # Make sure that we can find the node's Id. - self._set_wxid(node, wxid) - - return - - def _insert_node(self, pid, node, index): - """ Inserts 'node' as a child of the node identified by 'pid'. - - If 'pid' is None then we are adding the root node. - - """ - - # Get the tree item image index and the label text. - image_index = self._get_image_index(node) - text = self._get_text(node) - - # Add the node. - wxid = self.control.InsertItemBefore( - pid, index, text, image_index, image_index - ) - - # This gives the model a chance to wire up trait handlers etc. - self.model.add_listener(node) - - # Does the node have any children? - has_children = self._has_children(node) - self.control.SetItemHasChildren(wxid, has_children) - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data (which in our case is an arbitrary - # Python object provided by the tree model). - self.control.SetPyData(wxid, (False, node)) - - # Make sure that we can find the node's Id. - self._set_wxid(node, wxid) - - return - - def _remove_node(self, wxid, node): - """ Removes a node from the tree. """ - - # This gives the model a chance to remove trait handlers etc. - self.model.remove_listener(node) - - # Remove the reference to the item's data. - self._remove_wxid(node) - self.control.SetPyData(wxid, None) - - return - - def _update_node(self, wxid, node): - """ Updates the image and text of the specified node. """ - - # Get the tree item image index. - image_index = self._get_image_index(node) - self.control.SetItemImage(wxid, image_index, wx.TreeItemIcon_Normal) - self.control.SetItemImage(wxid, image_index, wx.TreeItemIcon_Selected) - - # Get the tree item text. - text = self._get_text(node) - self.control.SetItemText(wxid, text) - - return - - def _has_children(self, node): - """ Returns True if a node has children. """ - - # fixme: To be correct we *should* apply filtering here, but that - # seems to blow a hole throught models that have some efficient - # mechanism for determining whether or not they have children. There - # is also a precedent for doing it this way in Windoze, where a node - # gets marked as though it can be expanded, even thought when the - # expansion occurs, no children are present! - return self.model.has_children(node) - - def _get_children(self, node): - """ Get the children of a node. """ - - children = self.model.get_children(node) - - # Filtering.... - filtered_children = [] - for child in children: - for filter in self.filters: - if not filter.select(self, node, child): - break - - else: - filtered_children.append(child) - - # Sorting... - if self.sorter is not None: - self.sorter.sort(self, node, filtered_children) - - return filtered_children - - def _get_image_index(self, node): - """ Returns the tree item image index for a node. """ - - expanded = self.is_expanded(node) - selected = self.is_selected(node) - - # Get the image used to represent the node. - image = self.model.get_image(node, selected, expanded) - if image is not None: - image_index = self._image_list.GetIndex(image) - - else: - image_index = -1 - - return image_index - - def _get_drag_drop_node(self, x, y): - """ Returns the node that is being dragged/dropped on. - - Returns None if the cursor is not over the icon or label of a node. - - """ - - data, wxid, flags, point = self._hit_test((x, y)) - if data is not None: - populated, node = data - - else: - node = None - - return node - - def _get_text(self, node): - """ Returns the tree item text for a node. """ - - text = self.model.get_text(node) - if text is None: - text = '' - - return text - - def _unpack_event(self, event, wxid=None): - """ Unpacks the event to see whether a tree item was involved. """ - - try: - point = event.GetPosition() - - except: - point = event.GetPoint() - - return self._hit_test(point, wxid) - - def _hit_test(self, point, wxid=None): - """ Determines whether a point is within a node's label or icon. """ - - flags = wx.TREE_HITTEST_ONITEMLABEL - if (wxid is None) or (not wxid.IsOk()): - wxid, flags = self.control.HitTest(point) - - # Warning: On GTK we have to check the flags before we call 'GetPyData' - # because if we call it when the hit test returns 'nowhere' it will - # barf (on Windows it simply returns 'None' 8^() - if flags & wx.TREE_HITTEST_NOWHERE: - data = None - - elif flags & wx.TREE_HITTEST_ONITEMICON \ - or flags & wx.TREE_HITTEST_ONITEMLABEL: - - data = self.control.GetPyData(wxid) - - # fixme: Not sure why 'TREE_HITTEST_NOWHERE' doesn't catch everything! - else: - data = None - - return data, wxid, flags, point - - def _get_selection(self): - """ Returns a list of the selected nodes """ - - selection = [] - for wxid in self.control.GetSelections(): - data = self.control.GetPyData(wxid) - if data is not None: - populated, node = data - selection.append(self.model.get_selection_value(node)) - - return selection - - def _expand_item(self, wxid): - """ Recursively expand a tree item. """ - - self.control.Expand(wxid) - - cid, cookie = self.control.GetFirstChild(wxid) - while cid.IsOk(): - self._expand_item(cid) - cid, cookie = self.control.GetNextChild(wxid, cookie) - - return - - #### Trait event handlers ################################################# - - def _on_root_changed(self, root): - """ Called when the root of the model has changed. """ - - # Delete everything... - if self.control is not None: - self.control.DeleteAllItems() - - self._node_to_id_map = {} - - # ... and then add the root item back in. - if root is not None: - self._add_root_node(root) - - return - - def _on_nodes_changed(self, event): - """ Called when nodes have been changed. """ - - self._update_node(self._get_wxid(event.node), event.node) - - for child in event.children: - cid = self._get_wxid(child) - if cid is not None: - self._update_node(cid, child) - - return - - def _on_nodes_inserted(self, event): - """ Called when nodes have been inserted. """ - - parent = event.node - children = event.children - index = event.index - - # Has the node actually appeared in the tree yet? - pid = self._get_wxid(parent) - if pid is not None: - # The item data is a tuple. The first element indicates whether or - # not we have already populated the item with its children. The - # second element is the actual item data. - if self.show_root or parent is not self.root: - populated, node = self.control.GetPyData(pid) - - else: - populated = True - - # If the node is not yet populated then just get the children and - # add them. - if not populated: - for child in self._get_children(parent): - self._add_node(pid, child) - - # Otherwise, insert them. - else: - # An index of -1 means append! - if index == -1: - index = self.control.GetChildrenCount(pid, False) - - for child in children: - self._insert_node(pid, child, index) - index += 1 - - # The element is now populated! - if self.show_root or parent is not self.root: - self.control.SetPyData(pid, (True, parent)) - - # Does the node have any children now? - has_children = self.control.GetChildrenCount(pid) > 0 - self.control.SetItemHasChildren(pid, has_children) - - # If the node is not expanded then expand it. - if not self.is_expanded(parent): - self.expand(parent) - - return - - def _on_nodes_removed(self, event): - """ Called when nodes have been removed. """ - - parent = event.node - children = event.children - - # Has the node actually appeared in the tree yet? - pid = self._get_wxid(parent) - if pid is not None: - for child in event.children: - cid = self._get_wxid(child) - if cid is not None: - self.control.Delete(cid) - - # Does the node have any children left? - has_children = self.control.GetChildrenCount(pid) > 0 - self.control.SetItemHasChildren(pid, has_children) - - return - - def _on_nodes_replaced(self, event): - """ Called when nodes have been replaced. """ - - for old_child, new_child in zip(event.old_children, event.children): - cid = self._get_wxid(old_child) - if cid is not None: - # Remove listeners from the old node. - self.model.remove_listener(old_child) - - # Delete all of the node's children. - self.control.DeleteChildren(cid) - - # Update the visual appearance of the node. - self._update_node(cid, new_child) - - # Update the node data. - # - # The item data is a tuple. The first element indicates - # whether or not we have already populated the item with its - # children. The second element is the actual item data (which - # in our case is an arbitrary Python object provided by the - # tree model). - self.control.SetPyData(cid, (False, new_child)) - - # Remove the old node from the node to Id map. - self._remove_wxid(old_child) - - # Add the new node to the node to Id map. - self._set_wxid(new_child, cid) - - # Add listeners to the new node. - self.model.add_listener(new_child) - - # Does the new node have any children? - has_children = self._has_children(new_child) - self.control.SetItemHasChildren(cid, has_children) - - # Update the tree's selection (in case the old node that was replaced - # was selected, the selection should now include the new node). - self.selection = self._get_selection() - return - - def _on_structure_changed(self, event): - """ Called when the structure of a node has changed drastically. """ - - self.refresh(event.node) - - return - - #### wx event handlers #################################################### - - def _on_char(self, event): - """ Called when a key is pressed when the tree has focus. """ - - self.key_pressed = KeyPressedEvent( - alt_down = event.m_altDown == 1, - control_down = event.m_controlDown == 1, - shift_down = event.m_shiftDown == 1, - key_code = event.m_keyCode - ) - - event.Skip() - - return - - def _on_left_down(self, event): - """ Called when the left mouse button is clicked on the tree. """ - - data, id, flags, point = self._unpack_event(event) - - # Save point for tree_begin_drag method to workaround a bug in ?? when - # wx.TreeEvent.GetPoint returns only (0,0). This happens under linux - # when using wx-2.4.2.4, for instance. - self._point_left_clicked = point - - # Did the left click occur on a tree item? - if data is not None: - populated, node = data - - # Trait event notification. - self.node_left_clicked = node, point - - # Give other event handlers a chance. - event.Skip() - - return - - def _on_right_down(self, event): - """ Called when the right mouse button is clicked on the tree. """ - - data, id, flags, point = self._unpack_event(event) - - # Did the right click occur on a tree item? - if data is not None: - populated, node = data - - # Trait event notification. - self.node_right_clicked = node, point - - # Otherwise notify that the control itself was clicked - else: - self.control_right_clicked = point - - # Give other event handlers a chance. - event.Skip() - - return - - def _on_tree_item_activated(self, event): - """ Called when a tree item is activated (i.e., double clicked). """ - - # fixme: See the comment where the events are wired up for more - # information. - -## # Which item was activated? -## wxid = event.GetItem() - - # Which item was activated. - point = event.GetPosition() - wxid, flags = self.control.HitTest(point) - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - populated, node = self.control.GetPyData(wxid) - - # Trait event notiification. - self.node_activated = node - - return - - def _on_tree_item_collapsing(self, event): - """ Called when a tree item is about to collapse. """ - - # Which item is collapsing? - wxid = event.GetItem() - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - populated, node = self.control.GetPyData(wxid) - - # Give the model a chance to veto the collapse. - if not self.model.is_collapsible(node): - event.Veto() - - return - - def _on_tree_item_collapsed(self, event): - """ Called when a tree item has been collapsed. """ - - # Which item was collapsed? - wxid = event.GetItem() - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - populated, node = self.control.GetPyData(wxid) - - # Make sure that the item's 'closed' icon is displayed etc. - self._update_node(wxid, node) - - # Trait event notification. - self.node_collapsed = node - - return - - def _on_tree_item_expanding(self, event): - """ Called when a tree item is about to expand. """ - - # Which item is expanding? - wxid = event.GetItem() - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - populated, node = self.control.GetPyData(wxid) - - # Give the model a chance to veto the expansion. - if self.model.is_expandable(node): - # Lazily populate the item's children. - if not populated: - # Add the child nodes. - for child in self._get_children(node): - self._add_node(wxid, child) - - # The element is now populated! - self.control.SetPyData(wxid, (True, node)) - - else: - event.Veto() - - return - - def _on_tree_item_expanded(self, event): - """ Called when a tree item has been expanded. """ - - # Which item was expanded? - wxid = event.GetItem() - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - populated, node = self.control.GetPyData(wxid) - - # Make sure that the node's 'open' icon is displayed etc. - self._update_node(wxid, node) - - # Trait event notification. - self.node_expanded = node - - return - - def _on_tree_begin_label_edit(self, event): - """ Called when the user has started editing an item's label. """ - - wxid = event.GetItem() - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - populated, node = self.control.GetPyData(wxid) - - # Give the model a chance to veto the edit. - if not self.model.is_editable(node): - event.Veto() - - return - - def _on_tree_end_label_edit(self, event): - """ Called when the user has finished editing am item's label. """ - - wxid = event.GetItem() - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - populated, node = self.control.GetPyData(wxid) - - # Give the model a chance to veto the edit. - label = event.GetLabel() - - # Making sure the new label is not an empty string - - if label is not None and len(label) > 0 and \ - self.model.can_set_text(node, label): - def end_label_edit(): - """ Called to complete the label edit. """ - - # Set the node's text. - self.model.set_text(node, label) - - # If a label edit callback was specified (in the call to - # 'edit_label'), then call it). - if self._label_edit_callback is not None: - self._label_edit_callback(self, node, label) - - return - - # We use a deffered call here, because a name change can trigger - # the structure of a node to change, and hence the actual tree - # nodes might get moved/deleted before the label edit operation has - # completed. When this happens wx gets very confused! By using - # 'invoke_later' we allow the label edit to complete. - GUI.invoke_later(end_label_edit) - - else: - event.Veto() - - # If a label edit callback was specified (in the call to - # 'edit_label'), then call it). - if self._label_edit_callback is not None: - self._label_edit_callback(self, node, label) - - return - - def _on_tree_begin_drag(self, event): - """ Called when a drag operation is starting on a tree item. """ - - # Get the node, its id and the point where the event occurred. - data, wxid, flags, point = self._unpack_event(event, event.GetItem()) - - if point == (0,0): - # Apply workaround for GTK. - point = self.point_left_clicked - wxid, flags = self.HitTest(point) - data = self.control.GetPyData(wxid) - - if data is not None: - populated, node = data - - # Give the model a chance to veto the drag. - if self.model.is_draggable(node): - # We ask the model for the actual value to drag. - drag_value = self.model.get_drag_value(node) - - # fixme: This is a terrible hack to get the binding x passed - # during a drag operation. Bindings should probably *always* - # be dragged and our drag and drop mechanism should allow - # extendable ways to extract the actual data. - from pyface.wx.drag_and_drop import clipboard - clipboard.node = [node] - - # Make sure that the tree selection is updated before we start - # the drag. If we don't do this then if the first thing a - # user does is drag a tree item (i.e., without a separate click - # to select it first) then the selection appears empty. - self.selection = self._get_selection() - - # Start the drag. - PythonDropSource(self.control, drag_value, self) - - # Trait event notification. - self.node_begin_drag = node - - else: - event.Veto() - - return - - # fixme: This is part of the drag and drop hack... - def on_dropped(self): - """ Callback invoked when a drag/drop operation has completed. """ - - from pyface.wx.drag_and_drop import clipboard - clipboard.node = None - - return - - def _on_tree_sel_changed(self, event): - """ Called when the selection is changed. """ - - # Update our record of the selection to whatever was selected in the - # tree UNLESS we are ignoring selection events. - if not self._ignore_selection_events: - - # Trait notification. - self.selection = self._get_selection() - - return - - def _on_tree_delete_item(self, event): - """ Called when a tree item is being been deleted. """ - - # Which item is being deleted? - wxid = event.GetItem() - - # Check if GetPyData() returned a valid to tuple to unpack - # ...if so, remove the node from the tree, otherwise just return - # - # fixme: Whoever addeed this code (and the comment above) didn't say - # when this was occurring. This is method is called in response to a wx - # event to delete an item and hence the item data should never be None - # surely?!? Was it happening just on one platform?!? - data = self.control.GetPyData(wxid) - if data is not None: - # The item data is a tuple. The first element indicates whether or - # not we have already populated the item with its children. The - # second element is the actual item data. - populated, node = data - - # Remove the node. - self._remove_node(wxid, node) +""" The implementation of a tree control with a model/ui architecture. +""" - return +# Import the toolkit specific version. +from __future__ import absolute_import -#### EOF ###################################################################### +from pyface.toolkit import toolkit_object +Tree = toolkit_object('tree.tree:Tree') diff -Nru python-pyface-4.5.2/pyface/ui/null/action/tool_palette_manager.py python-pyface-6.1.2/pyface/ui/null/action/tool_palette_manager.py --- python-pyface-4.5.2/pyface/ui/null/action/tool_palette_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/null/action/tool_palette_manager.py 2019-05-03 08:18:50.000000000 +0000 @@ -20,7 +20,7 @@ # Local imports. from pyface.image_cache import ImageCache from pyface.action.action_manager import ActionManager -from tool_palette import ToolPalette +from .tool_palette import ToolPalette class ToolPaletteManager(ActionManager): diff -Nru python-pyface-4.5.2/pyface/ui/null/init.py python-pyface-6.1.2/pyface/ui/null/init.py --- python-pyface-4.5.2/pyface/ui/null/init.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/null/init.py 2019-05-03 08:18:50.000000000 +0000 @@ -10,7 +10,6 @@ """ Initialize this backend. """ -# There is nothing for us to initialize, but the toolkit switching code depends -# on the existence of this module. +from pyface.base_toolkit import Toolkit -#### EOF ###################################################################### +toolkit_object = Toolkit('pyface', 'null', 'pyface.ui.null') diff -Nru python-pyface-4.5.2/pyface/ui/null/window.py python-pyface-6.1.2/pyface/ui/null/window.py --- python-pyface-4.5.2/pyface/ui/null/window.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/null/window.py 2019-05-03 08:18:50.000000000 +0000 @@ -20,7 +20,7 @@ # Local imports. from pyface.i_window import IWindow, MWindow from pyface.key_pressed_event import KeyPressedEvent -from widget import Widget +from .widget import Widget @provides(IWindow) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/about_dialog.py python-pyface-6.1.2/pyface/ui/qt4/about_dialog.py --- python-pyface-4.5.2/pyface/ui/qt4/about_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/about_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -10,8 +10,8 @@ # Description: #------------------------------------------------------------------------------ - # Standard library imports. +import platform import sys # Major package imports. @@ -23,8 +23,7 @@ # Local imports. from pyface.i_about_dialog import IAboutDialog, MAboutDialog from pyface.image_resource import ImageResource -from dialog import Dialog - +from .dialog import Dialog # The HTML displayed in the QLabel. _DIALOG_TEXT = ''' @@ -62,7 +61,6 @@ IAboutDialog interface for the API documentation. """ - #### 'IAboutDialog' interface ############################################# additions = List(Unicode) @@ -76,13 +74,14 @@ def _create_contents(self, parent): label = QtGui.QLabel() - if parent.parent() is not None: - title = parent.parent().windowTitle() - else: - title = "" + if self.title == "": + if parent.parent() is not None: + title = parent.parent().windowTitle() + else: + title = "" - # Set the title. - self.title = "About %s" % title + # Set the title. + self.title = "About %s" % title # Load the image to be displayed in the about box. image = self.image.create_image() @@ -92,7 +91,7 @@ additions = '
'.join(self.additions) # Get the version numbers. - py_version = sys.version[0:sys.version.find("(")] + py_version = platform.python_version() qt_version = QtCore.__version__ # Set the page contents. @@ -106,12 +105,10 @@ else: buttons.addButton(QtGui.QDialogButtonBox.Ok) - buttons.connect(buttons, QtCore.SIGNAL('accepted()'), parent, QtCore.SLOT('accept()')) + buttons.accepted.connect(parent.accept) lay = QtGui.QVBoxLayout() lay.addWidget(label) lay.addWidget(buttons) parent.setLayout(lay) - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/qt4/action/action_item.py python-pyface-6.1.2/pyface/ui/qt4/action/action_item.py --- python-pyface-4.5.2/pyface/ui/qt4/action/action_item.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/action/action_item.py 2019-06-18 10:52:41.000000000 +0000 @@ -1,19 +1,24 @@ -#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited +# Copyright (c) 2019, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. -# However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply - +# However, when used with the GPL version of PyQt the additional terms described +# in the PyQt GPL exception also apply. # # Author: Riverbank Computing Limited # Description: -#------------------------------------------------------------------------------ + """ The PyQt specific implementations the action manager internal classes. """ # Standard library imports. -from inspect import getargspec +import six +if six.PY2: + from inspect import getargspec +else: + # avoid deprecation warning + from inspect import getfullargspec as getargspec # Major package imports. from pyface.qt import QtGui, QtCore @@ -25,6 +30,18 @@ from pyface.action.action_event import ActionEvent +class PyfaceWidgetAction(QtGui.QWidgetAction): + + def __init__(self, parent, action): + super(PyfaceWidgetAction, self).__init__(parent) + self.action = action + + def createWidget(self, parent): + widget = self.action.create_control(parent) + widget._action = self.action + return widget + + class _MenuItem(HasTraits): """ A menu item representation of an action item. """ @@ -49,6 +66,9 @@ # The toolkit control. control = Any() + # The toolkit control id. + control_id = None + ########################################################################### # 'object' interface. ########################################################################### @@ -62,7 +82,10 @@ # FIXME v3: This is a wx'ism and should be hidden in the toolkit code. self.control_id = None - if action.image is None: + if action.style == 'widget': + self.control = PyfaceWidgetAction(parent, action) + menu.addAction(self.control) + elif action.image is None: self.control = menu.addAction(action.name, self._qt4_on_triggered, action.accelerator) else: @@ -152,11 +175,11 @@ # contains information about the time the event occurred etc), so # we only pass it if the perform method requires it. This is also # useful as Traits UI controllers *never* require the event. - args, varargs, varkw, dflts = getargspec(self.controller.perform) + argspec = getargspec(self.controller.perform) # If the only arguments are 'self' and 'action' then don't pass # the event! - if len(args) == 2: + if len(argspec.args) == 2: self.controller.perform(action) else: @@ -169,10 +192,10 @@ # Most of the time, action's do no care about the event (it # contains information about the time the event occurred etc), so # we only pass it if the perform method requires it. - args, varargs, varkw, dflts = getargspec(action.perform) + argspec = getargspec(action.perform) # If the only argument is 'self' then don't pass the event! - if len(args) == 1: + if len(argspec.args) == 1: action.perform() else: @@ -245,6 +268,9 @@ # The toolkit control. control = Any() + # The toolkit control id. + control_id = None + ########################################################################### # 'object' interface. ########################################################################### @@ -257,18 +283,17 @@ self.tool_bar = tool_bar action = item.action - # FIXME v3: This is a wx'ism and should be hidden in the toolkit code. - self.control_id = None - - if action.image is None: + if action.style == 'widget': + widget = action.create_control(tool_bar) + self.control = tool_bar.addWidget(widget) + elif action.image is None: self.control = tool_bar.addAction(action.name) else: size = tool_bar.iconSize() image = action.image.create_icon((size.width(), size.height())) self.control = tool_bar.addAction(image, action.name) - QtCore.QObject.connect(self.control, QtCore.SIGNAL('triggered()'), - self._qt4_on_triggered) + self.control.triggered.connect(self._qt4_on_triggered) self.control.setToolTip(action.tooltip) self.control.setWhatsThis(action.description) @@ -335,11 +360,11 @@ # contains information about the time the event occurred etc), so # we only pass it if the perform method requires it. This is also # useful as Traits UI controllers *never* require the event. - args, varargs, varkw, dflts = getargspec(self.controller.perform) + argspec = getargspec(self.controller.perform) # If the only arguments are 'self' and 'action' then don't pass # the event! - if len(args) == 2: + if len(argspec.args) == 2: self.controller.perform(action) else: @@ -351,10 +376,10 @@ # Most of the time, action's do no care about the event (it # contains information about the time the event occurred etc), so # we only pass it if the perform method requires it. - args, varargs, varkw, dflts = getargspec(action.perform) + argspec = getargspec(action.perform) # If the only argument is 'self' then don't pass the event! - if len(args) == 1: + if len(argspec.args) == 1: action.perform() else: @@ -425,6 +450,10 @@ action = self.item.action label = action.name + if action.style == "widget": + raise NotImplementedError( + "Qt does not support widgets in palettes") + # Tool palette tools never have '...' at the end. if label.endswith('...'): label = label[:-3] @@ -501,5 +530,3 @@ action.perform(action_event) return - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/qt4/action/status_bar_manager.py python-pyface-6.1.2/pyface/ui/qt4/action/status_bar_manager.py --- python-pyface-4.5.2/pyface/ui/qt4/action/status_bar_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/action/status_bar_manager.py 2019-05-03 08:18:50.000000000 +0000 @@ -52,6 +52,12 @@ return self.status_bar + def destroy_status_bar(self): + """ Destroys the status bar. """ + if self.status_bar is not None: + self.status_bar.deleteLater() + self.status_bar = None + ########################################################################### # Property handlers. ########################################################################### @@ -117,4 +123,5 @@ # widget - depends on what wx is capable of. self.status_bar.showMessage(" ".join(self.messages)) + #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/qt4/application_window.py python-pyface-6.1.2/pyface/ui/qt4/application_window.py --- python-pyface-4.5.2/pyface/ui/qt4/application_window.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/application_window.py 2019-05-03 08:18:50.000000000 +0000 @@ -10,6 +10,8 @@ # Description: #------------------------------------------------------------------------------ +import sys + # Major package imports. from pyface.qt import QtGui @@ -19,10 +21,11 @@ from traits.api import Instance, List, on_trait_change, provides, Unicode # Local imports. -from pyface.i_application_window import IApplicationWindow, \ - MApplicationWindow +from pyface.i_application_window import ( + IApplicationWindow, MApplicationWindow +) from pyface.image_resource import ImageResource -from window import Window +from .window import Window @provides(IApplicationWindow) @@ -31,21 +34,26 @@ IApplicationWindow interface for the API documentation. """ - #### 'IApplicationWindow' interface ####################################### + #: The icon to display in the application window title bar. icon = Instance(ImageResource) + #: The menu bar manager for the window. menu_bar_manager = Instance(MenuBarManager) + #: The status bar manager for the window. status_bar_manager = Instance(StatusBarManager) + #: DEPRECATED: The tool bar manager for the window. tool_bar_manager = Instance(ToolBarManager) + #: The collection of tool bar managers for the window. tool_bar_managers = List(ToolBarManager) #### 'IWindow' interface ################################################## + #: The window title. title = Unicode("Pyface") ########################################################################### @@ -89,10 +97,11 @@ if len(tool_bar.objectName()) == 0: tool_bar.setObjectName(tool_bar_manager.name) - # Work around bug in Qt on OS X where creating a tool bar with a - # QMainWindow parent hides the window. See - # http://bugreports.qt.nokia.com/browse/QTBUG-5069 for more info. - self.control.setVisible(visible) + if sys.platform == 'darwin': + # Work around bug in Qt on OS X where creating a tool bar with a + # QMainWindow parent hides the window. See + # http://bugreports.qt.nokia.com/browse/QTBUG-5069 for more info. + self.control.setVisible(visible) def _set_window_icon(self): if self.icon is None: @@ -158,8 +167,10 @@ if self.control is not None: self._create_menu_bar(self.control) - def _status_bar_manager_changed(self): + def _status_bar_manager_changed(self, old, new): if self.control is not None: + if old is not None: + old.destroy_status_bar() self._create_status_bar(self.control) @on_trait_change('tool_bar_manager, tool_bar_managers') @@ -176,4 +187,3 @@ def _icon_changed(self): self._set_window_icon() - diff -Nru python-pyface-4.5.2/pyface/ui/qt4/clipboard.py python-pyface-6.1.2/pyface/ui/qt4/clipboard.py --- python-pyface-4.5.2/pyface/ui/qt4/clipboard.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/clipboard.py 2019-05-03 08:18:50.000000000 +0000 @@ -13,8 +13,8 @@ #------------------------------------------------------------------------------ # Standard library imports -from cStringIO import StringIO -from cPickle import dumps, load, loads +from io import BytesIO +from six.moves.cPickle import dumps, load, loads # System library imports from pyface.qt import QtCore, QtGui @@ -22,6 +22,7 @@ # ETS imports from traits.api import provides from pyface.i_clipboard import IClipboard, BaseClipboard +import six # Shortcuts cb = QtGui.QApplication.clipboard() @@ -33,7 +34,6 @@ @provides(IClipboard) class Clipboard(BaseClipboard): - #--------------------------------------------------------------------------- # 'data' property methods: #--------------------------------------------------------------------------- @@ -49,7 +49,7 @@ obj = None mime_data = cb.mimeData() if mime_data.hasFormat(PYTHON_TYPE): - serialized_data = StringIO(str(mime_data.data(PYTHON_TYPE))) + serialized_data = BytesIO(mime_data.data(PYTHON_TYPE).data()) klass = load(serialized_data) obj = load(serialized_data) return obj @@ -69,7 +69,7 @@ if mime_data.hasFormat(PYTHON_TYPE): try: # We may not be able to load the required class: - result = loads(str(mime_data.data(PYTHON_TYPE))) + result = loads(mime_data.data(PYTHON_TYPE).data()) except: pass return result @@ -79,7 +79,7 @@ #--------------------------------------------------------------------------- def _get_text_data(self): - return str(cb.text()) + return cb.text() def _set_text_data(self, data): cb.setText(data) @@ -94,15 +94,15 @@ def _get_file_data(self): mime_data = cb.mimeData() if mime_data.hasUrls(): - return [ str(url.toString()) for url in mime_data.urls() ] + return [url.toString() for url in mime_data.urls()] else: return [] def _set_file_data(self, data): - if isinstance(data, basestring): - data = [ data ] + if isinstance(data, six.string_types): + data = [data] mime_data = QtCore.QMimeData() - mime_data.setUrls([ QtCore.QUrl(path) for path in data ]) + mime_data.setUrls([QtCore.QUrl(path) for path in data]) cb.setMimeData(mime_data) def _get_has_file_data (self): diff -Nru python-pyface-4.5.2/pyface/ui/qt4/code_editor/code_widget.py python-pyface-6.1.2/pyface/ui/qt4/code_editor/code_widget.py --- python-pyface-4.5.2/pyface/ui/qt4/code_editor/code_widget.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/code_editor/code_widget.py 2019-05-03 08:18:50.000000000 +0000 @@ -17,10 +17,11 @@ from pyface.qt import QtCore, QtGui # Local imports -from find_widget import FindWidget -from gutters import LineNumberWidget, StatusGutterWidget -from replace_widget import ReplaceWidget -from pygments_highlighter import PygmentsHighlighter +from .find_widget import FindWidget +from .gutters import LineNumberWidget, StatusGutterWidget +from .replace_widget import ReplaceWidget +from .pygments_highlighter import PygmentsHighlighter +import six class CodeWidget(QtGui.QPlainTextEdit): @@ -30,6 +31,7 @@ ########################################################################### # CodeWidget interface ########################################################################### + focus_lost = QtCore.Signal() def __init__(self, parent, should_highlight_current_line=True, font=None, lexer=None): @@ -128,7 +130,7 @@ def get_selected_text(self): """ Return the currently selected text. """ - return unicode(self.textCursor().selectedText()) + return six.text_type(self.textCursor().selectedText()) def set_font(self, font): """ Set the new QFont. @@ -357,7 +359,7 @@ """ cursor = self.textCursor() cursor.select(QtGui.QTextCursor.WordUnderCursor) - return unicode(cursor.selectedText()) + return six.text_type(cursor.selectedText()) ########################################################################### # QWidget interface @@ -370,6 +372,9 @@ pass def keyPressEvent(self, event): + if self.isReadOnly(): + return super(CodeWidget, self).keyPressEvent(event) + key_sequence = QtGui.QKeySequence(event.key() + int(event.modifiers())) self.keyPressEvent_action(event) # FIXME: see above @@ -426,6 +431,11 @@ contents.top(), self.status_widget.sizeHint().width(), contents.height())) + def focusOutEvent(self, event): + QtGui.QPlainTextEdit.focusOutEvent(self, event) + self.focus_lost.emit() + + def sizeHint(self): # Suggest a size that is 80 characters wide and 40 lines tall. style = self.style() @@ -649,7 +659,7 @@ def find_next(self): if not self.active_find_widget: self.enable_find() - search_text = unicode(self.active_find_widget.line_edit.text()) + search_text = six.text_type(self.active_find_widget.line_edit.text()) cursor = self.find_in_document(search_text=search_text) if cursor: @@ -659,7 +669,7 @@ def find_prev(self): if not self.active_find_widget: self.enable_find() - search_text = unicode(self.active_find_widget.line_edit.text()) + search_text = six.text_type(self.active_find_widget.line_edit.text()) cursor = self.find_in_document(search_text=search_text, direction='backward') if cursor: @@ -680,8 +690,8 @@ return 0 def replace_all(self): - search_text = unicode(self.replace.line_edit.text()) - replace_text = unicode(self.replace.replace_edit.text()) + search_text = six.text_type(self.replace.line_edit.text()) + replace_text = six.text_type(self.replace.replace_edit.text()) count = 0 cursor = self.code.textCursor() @@ -709,11 +719,11 @@ def keyPressEvent(self, event): key_sequence = QtGui.QKeySequence(event.key() + int(event.modifiers())) - if key_sequence.matches(QtGui.QKeySequence.Find): self.enable_find() elif key_sequence.matches(QtGui.QKeySequence.Replace): - self.enable_replace() + if not self.code.isReadOnly(): + self.enable_replace() elif key_sequence.matches(QtGui.QKeySequence(QtCore.Qt.Key_Escape)): if self.active_find_widget: self.find.hide() @@ -759,4 +769,3 @@ window.resize(640, 640) window.show() sys.exit(app.exec_()) - diff -Nru python-pyface-4.5.2/pyface/ui/qt4/code_editor/pygments_highlighter.py python-pyface-6.1.2/pyface/ui/qt4/code_editor/pygments_highlighter.py --- python-pyface-4.5.2/pyface/ui/qt4/code_editor/pygments_highlighter.py 2015-07-21 14:05:50.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/code_editor/pygments_highlighter.py 2019-05-03 08:18:50.000000000 +0000 @@ -15,6 +15,7 @@ from pygments.lexers import CLexer, CppLexer, PythonLexer, get_lexer_by_name from pygments.styles.default import DefaultStyle from pygments.token import Comment +import six def get_tokens_unprocessed(self, text, stack=('root',)): @@ -118,7 +119,7 @@ def __init__(self, **kwds): QtGui.QTextBlockUserData.__init__(self) - for key, value in kwds.iteritems(): + for key, value in kwds.items(): setattr(self, key, value) def __repr__(self): @@ -147,7 +148,7 @@ def highlightBlock(self, qstring): """ Highlight a block of text. """ - qstring = unicode(qstring) + qstring = six.text_type(qstring) prev_data = self.previous_block_data() if prev_data is not None: @@ -186,7 +187,7 @@ if token in self._formats: return self._formats[token] result = None - for key, value in self._style.style_for_token(token) .items(): + for key, value in self._style.style_for_token(token).items(): if value: if result is None: result = QtGui.QTextCharFormat() diff -Nru python-pyface-4.5.2/pyface/ui/qt4/code_editor/replace_widget.py python-pyface-6.1.2/pyface/ui/qt4/code_editor/replace_widget.py --- python-pyface-4.5.2/pyface/ui/qt4/code_editor/replace_widget.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/code_editor/replace_widget.py 2019-05-03 08:18:50.000000000 +0000 @@ -13,7 +13,7 @@ from pyface.qt import QtGui, QtCore -from find_widget import FindWidget +from .find_widget import FindWidget class ReplaceWidget(FindWidget): @@ -54,4 +54,3 @@ control.setLayout(layout) return control - diff -Nru python-pyface-4.5.2/pyface/ui/qt4/code_editor/tests/test_code_widget.py python-pyface-6.1.2/pyface/ui/qt4/code_editor/tests/test_code_widget.py --- python-pyface-4.5.2/pyface/ui/qt4/code_editor/tests/test_code_widget.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/code_editor/tests/test_code_widget.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,105 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2016, Enthought Inc +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD license. +# +# Author: Enthought Inc +# Description: +#------------------------------------------------------------------------------ + +# Standard library imports. +import unittest +import mock + +# System library imports. +from pyface.qt import QtCore, QtGui +from pyface.qt.QtTest import QTest + +# Enthought library imports. + + +# Local imports. +from pyface.ui.qt4.code_editor.code_widget import CodeWidget, AdvancedCodeWidget + + +class TestCodeWidget(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.qapp = QtGui.QApplication.instance() or QtGui.QApplication([]) + + def tearDown(self): + self.qapp.processEvents() + + def test_readonly_editor(self): + cw = CodeWidget(None) + text = 'Some\nText' + cw.setPlainText(text) + + def check(typed, expected): + cursor = cw.textCursor() + cursor.setPosition(0) + cw.setTextCursor(cursor) + QTest.keyClicks(cw, typed) + self.assertEqual(cw.toPlainText(), expected) + + cw.setReadOnly(True) + check('More', text) + + cw.setReadOnly(False) + check('Extra', 'Extra' + text) + + def test_readonly_replace_widget(self): + acw = AdvancedCodeWidget(None) + text = 'Some\nText' + acw.code.setPlainText(text) + acw.show() + + # On some platforms, Find/Replace do not have default keybindings + FindKey = QtGui.QKeySequence('Ctrl+F') + ReplaceKey = QtGui.QKeySequence('Ctrl+H') + patcher_find = mock.patch('pyface.qt.QtGui.QKeySequence.Find', FindKey) + patcher_replace = mock.patch('pyface.qt.QtGui.QKeySequence.Replace', + ReplaceKey) + patcher_find.start() + patcher_replace.start() + self.addCleanup(patcher_find.stop) + self.addCleanup(patcher_replace.stop) + + def click_key_seq(widget, key_seq): + if not isinstance(key_seq, QtGui.QKeySequence): + key_seq = QtGui.QKeySequence(key_seq) + try: + # QKeySequence on python3-pyside does not have `len` + first_key = key_seq[0] + except IndexError: + return False + key = QtCore.Qt.Key(first_key & ~QtCore.Qt.KeyboardModifierMask) + modifier = QtCore.Qt.KeyboardModifier( + first_key & QtCore.Qt.KeyboardModifierMask) + QTest.keyClick(widget, key, modifier) + return True + + acw.code.setReadOnly(True) + if click_key_seq(acw, FindKey): + self.assertTrue(acw.find.isVisible()) + acw.find.hide() + + acw.code.setReadOnly(False) + if click_key_seq(acw, FindKey): + self.assertTrue(acw.find.isVisible()) + acw.find.hide() + + acw.code.setReadOnly(True) + if click_key_seq(acw, ReplaceKey): + self.assertFalse(acw.replace.isVisible()) + + acw.code.setReadOnly(False) + if click_key_seq(acw, ReplaceKey): + self.assertTrue(acw.replace.isVisible()) + acw.replace.hide() + self.assertFalse(acw.replace.isVisible()) + + +if __name__ == '__main__': + unittest.main() diff -Nru python-pyface-4.5.2/pyface/ui/qt4/confirmation_dialog.py python-pyface-6.1.2/pyface/ui/qt4/confirmation_dialog.py --- python-pyface-4.5.2/pyface/ui/qt4/confirmation_dialog.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/confirmation_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -21,7 +21,7 @@ from pyface.i_confirmation_dialog import IConfirmationDialog, MConfirmationDialog from pyface.constant import CANCEL, YES, NO from pyface.image_resource import ImageResource -from dialog import Dialog, _RESULT_MAP +from .dialog import Dialog, _RESULT_MAP @provides(IConfirmationDialog) @@ -76,6 +76,12 @@ dlg.setInformativeText(self.informative) dlg.setDetailedText(self.detail) + if self.size != (-1, -1): + dlg.resize(*self.size) + + if self.position != (-1, -1): + dlg.move(*self.position) + if self.image is None: dlg.setIcon(QtGui.QMessageBox.Warning) else: diff -Nru python-pyface-4.5.2/pyface/ui/qt4/console/api.py python-pyface-6.1.2/pyface/ui/qt4/console/api.py --- python-pyface-4.5.2/pyface/ui/qt4/console/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/console/api.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,5 +1,5 @@ -from bracket_matcher import BracketMatcher -from call_tip_widget import CallTipWidget -from completion_lexer import CompletionLexer -from console_widget import ConsoleWidget -from history_console_widget import HistoryConsoleWidget +from .bracket_matcher import BracketMatcher +from .call_tip_widget import CallTipWidget +from .completion_lexer import CompletionLexer +from .console_widget import ConsoleWidget +from .history_console_widget import HistoryConsoleWidget diff -Nru python-pyface-4.5.2/pyface/ui/qt4/console/console_widget.py python-pyface-6.1.2/pyface/ui/qt4/console/console_widget.py --- python-pyface-4.5.2/pyface/ui/qt4/console/console_widget.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/console/console_widget.py 2019-05-03 08:18:50.000000000 +0000 @@ -34,11 +34,11 @@ #----------------------------------------------------------------------------- class ConsoleWidget(QtGui.QWidget): - """ An abstract base class for console-type widgets. This class has + """ An abstract base class for console-type widgets. This class has functionality for: * Maintaining a prompt and editing region - * Providing the traditional Unix-style console keyboard shortcuts + * Providing the traditional Unix-style console keyboard shortcuts * Performing tab completion * Paging text @@ -104,9 +104,8 @@ # The shortcuts defined by this widget. We need to keep track of these to # support 'override_shortcuts' above. - _shortcuts = set(_ctrl_down_remap.keys() + - [ QtCore.Qt.Key_C, QtCore.Qt.Key_G, QtCore.Qt.Key_O, - QtCore.Qt.Key_V ]) + _shortcuts = set(_ctrl_down_remap.keys()) | set([ + QtCore.Qt.Key_C, QtCore.Qt.Key_G, QtCore.Qt.Key_O, QtCore.Qt.Key_V]) #--------------------------------------------------------------------------- # 'QObject' interface @@ -188,7 +187,7 @@ action.triggered.connect(self.export) self.addAction(action) self._export_action = action - + action = QtGui.QAction('Select All', None) action.setEnabled(True) action.setShortcut(QtGui.QKeySequence.SelectAll) @@ -207,7 +206,7 @@ key = event.key() if self._control_key_down(event.modifiers()) and \ key in self._ctrl_down_remap: - new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, + new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, self._ctrl_down_remap[key], QtCore.Qt.NoModifier) QtGui.QApplication.sendEvent(obj, new_event) @@ -321,10 +320,10 @@ """ Returns whether text can be cut to the clipboard. """ cursor = self._control.textCursor() - return (cursor.hasSelection() and - self._in_buffer(cursor.anchor()) and + return (cursor.hasSelection() and + self._in_buffer(cursor.anchor()) and self._in_buffer(cursor.position())) - + def can_paste(self): """ Returns whether text can be pasted from the clipboard. """ @@ -339,7 +338,7 @@ return self.kind == "rich" def clear(self, keep_input=True): - """ Clear the console. + """ Clear the console. Parameters: ----------- @@ -374,7 +373,7 @@ input. Parameters: - ----------- + ----------- source : str, optional The source to execute. If not specified, the input buffer will be @@ -416,7 +415,7 @@ source += '\n' elif not hidden: self.input_buffer = source - + # Execute the source or show a continuation prompt if it is incomplete. complete = self._is_complete(source, interactive) if hidden: @@ -424,7 +423,7 @@ self._execute(source, hidden) else: error = 'Incomplete noninteractive input: "%s"' - raise RuntimeError(error % source) + raise RuntimeError(error % source) else: if complete: self._append_plain_text('\n') @@ -443,7 +442,7 @@ # Perform actual execution. self._execute(source, hidden) - + else: # Do this inside an edit block so continuation prompts are # removed seamlessly via undo/redo. @@ -454,7 +453,7 @@ cursor.endEditBlock() # Do not do this inside the edit block. It works as expected - # when using a QPlainTextEdit control, but does not have an + # when using a QPlainTextEdit control, but does not have an # effect when using a QTextEdit. I believe this is a Qt bug. self._control.moveCursor(QtGui.QTextCursor.End) @@ -571,10 +570,10 @@ try: return exporter(filename) - except Exception, e: + except Exception as e: title = self.window().windowTitle() msg = "Error while saving to: %s\n"%filename+str(e) - reply = QtGui.QMessageBox.warning(self, title, msg, + QtGui.QMessageBox.warning(self, title, msg, QtGui.QMessageBox.Ok, QtGui.QMessageBox.Ok) return None @@ -650,7 +649,7 @@ f.write(img_re.sub( lambda x: self.image_tag(x, path = path, format = "png"), html)) - except Exception, e: + except Exception as e: f.close() raise e else: @@ -678,7 +677,7 @@ f.write(img_re.sub( lambda x: self.image_tag(x, path = None, format = "svg"), html)) - except Exception, e: + except Exception as e: f.close() raise e else: @@ -713,7 +712,7 @@ Parameters ---------- - match : re.SRE_Match + match : re.SRE_Match A match to an HTML image tag as exported by Qt, with match.group("Name") containing the matched image ID. @@ -740,7 +739,7 @@ if self._get_cursor().blockNumber() < prompt_cursor.blockNumber(): self._set_cursor(prompt_cursor) self._set_top_cursor(prompt_cursor) - + def redo(self): """ Redo the last operation. If there is no operation to redo, nothing happens. @@ -927,7 +926,7 @@ self._cancel_text_completion() if len(items) == 1: - cursor.setPosition(self._control.textCursor().position(), + cursor.setPosition(self._control.textCursor().position(), QtGui.QTextCursor.KeepAnchor) cursor.insertText(items[0]) @@ -1074,7 +1073,7 @@ elif key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter): intercepted = True - + # Special handling when tab completing in text mode. self._cancel_text_completion() @@ -1161,7 +1160,7 @@ if key == QtCore.Qt.Key_B: self._set_cursor(self._get_word_start_cursor(position)) intercepted = True - + elif key == QtCore.Qt.Key_F: self._set_cursor(self._get_word_end_cursor(position)) intercepted = True @@ -1184,7 +1183,7 @@ elif key == QtCore.Qt.Key_Greater: self._control.moveCursor(QtGui.QTextCursor.End) intercepted = True - + elif key == QtCore.Qt.Key_Less: self._control.setTextCursor(self._get_prompt_cursor()) intercepted = True @@ -1196,7 +1195,7 @@ anchormode=QtGui.QTextCursor.KeepAnchor else: anchormode=QtGui.QTextCursor.MoveAnchor - + if key == QtCore.Qt.Key_Escape: self._keyboard_quit() intercepted = True @@ -1225,19 +1224,19 @@ line, col = cursor.blockNumber(), cursor.columnNumber() if line > self._get_prompt_cursor().blockNumber() and \ col == len(self._continuation_prompt): - self._control.moveCursor(QtGui.QTextCursor.PreviousBlock, + self._control.moveCursor(QtGui.QTextCursor.PreviousBlock, mode=anchormode) - self._control.moveCursor(QtGui.QTextCursor.EndOfBlock, + self._control.moveCursor(QtGui.QTextCursor.EndOfBlock, mode=anchormode) intercepted = True # Regular left movement else: intercepted = not self._in_buffer(position - 1) - + elif key == QtCore.Qt.Key_Right: original_block_number = cursor.blockNumber() - cursor.movePosition(QtGui.QTextCursor.Right, + cursor.movePosition(QtGui.QTextCursor.Right, mode=anchormode) if cursor.blockNumber() != original_block_number: cursor.movePosition(QtGui.QTextCursor.Right, @@ -1313,7 +1312,7 @@ return intercepted def _event_filter_page_keypress(self, event): - """ Filter key events for the paging widget to create console-like + """ Filter key events for the paging widget to create console-like interface. """ key = event.key() @@ -1323,16 +1322,16 @@ if ctrl_down: if key == QtCore.Qt.Key_O: self._control.setFocus() - intercept = True + return True elif alt_down: if key == QtCore.Qt.Key_Greater: self._page_control.moveCursor(QtGui.QTextCursor.End) - intercepted = True - + return True + elif key == QtCore.Qt.Key_Less: self._page_control.moveCursor(QtGui.QTextCursor.Start) - intercepted = True + return True elif key in (QtCore.Qt.Key_Q, QtCore.Qt.Key_Escape): if self._splitter: @@ -1342,15 +1341,15 @@ return True elif key in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return): - new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, - QtCore.Qt.Key_PageDown, + new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, + QtCore.Qt.Key_PageDown, QtCore.Qt.NoModifier) QtGui.QApplication.sendEvent(self._page_control, new_event) return True elif key == QtCore.Qt.Key_Backspace: new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, - QtCore.Qt.Key_PageUp, + QtCore.Qt.Key_PageUp, QtCore.Qt.NoModifier) QtGui.QApplication.sendEvent(self._page_control, new_event) return True @@ -1382,7 +1381,7 @@ # Some degenerate cases. size = len(items) - if size == 0: + if size == 0: return '\n' elif size == 1: return '%s\n' % items[0] @@ -1403,9 +1402,9 @@ colwidth = max(colwidth, len(x)) colwidths.append(colwidth) totwidth += colwidth + len(separator) - if totwidth > displaywidth: + if totwidth > displaywidth: break - if totwidth <= displaywidth: + if totwidth <= displaywidth: break # The smallest number of rows computed and the max widths for each @@ -1431,7 +1430,7 @@ """ cursor = QtGui.QTextCursor(block) cursor.movePosition(QtGui.QTextCursor.StartOfBlock) - cursor.movePosition(QtGui.QTextCursor.EndOfBlock, + cursor.movePosition(QtGui.QTextCursor.EndOfBlock, QtGui.QTextCursor.KeepAnchor) return cursor.selection().toPlainText() @@ -1439,7 +1438,7 @@ """ Convenience method that returns a cursor for the current position. """ return self._control.textCursor() - + def _get_end_cursor(self): """ Convenience method that returns a cursor for the last character. """ @@ -1644,7 +1643,7 @@ self._cancel_text_completion() else: self.input_buffer = '' - + def _page(self, text, html=False): """ Displays text using the pager if it exceeds the height of the viewport. @@ -1690,7 +1689,7 @@ def _prompt_started(self): """ Called immediately after a new prompt is displayed. """ - # Temporarily disable the maximum block count to permit undo/redo and + # Temporarily disable the maximum block count to permit undo/redo and # to ensure that the prompt position does not change due to truncation. self._control.document().setMaximumBlockCount(0) self._control.setUndoRedoEnabled(True) @@ -1701,7 +1700,7 @@ self._prompt_started_hook() def _readline(self, prompt='', callback=None): - """ Reads one line of input from the user. + """ Reads one line of input from the user. Parameters ---------- @@ -1757,7 +1756,7 @@ else: self._continuation_prompt = prompt self._continuation_prompt_html = None - + def _set_cursor(self, cursor): """ Convenience method to set the current cursor. """ @@ -1787,14 +1786,14 @@ as plain text, though ANSI color codes will be handled. newline : bool, optional (default True) - If set, a new line will be written before showing the prompt if + If set, a new line will be written before showing the prompt if there is not already a newline at the end of the buffer. """ # Insert a preliminary newline, if necessary. if newline: cursor = self._get_end_cursor() if cursor.position() > 0: - cursor.movePosition(QtGui.QTextCursor.Left, + cursor.movePosition(QtGui.QTextCursor.Left, QtGui.QTextCursor.KeepAnchor) if cursor.selection().toPlainText() != '\n': self._append_plain_text('\n') diff -Nru python-pyface-4.5.2/pyface/ui/qt4/console/history_console_widget.py python-pyface-6.1.2/pyface/ui/qt4/console/history_console_widget.py --- python-pyface-4.5.2/pyface/ui/qt4/console/history_console_widget.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/console/history_console_widget.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,15 +1,27 @@ +# Copyright (c) 2011-18, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. # System library imports + from pyface.qt import QtGui # Local imports -from console_widget import ConsoleWidget +from .console_widget import ConsoleWidget class HistoryConsoleWidget(ConsoleWidget): """ A ConsoleWidget that keeps a history of the commands that have been executed and provides a readline-esque interface to this history. """ - + #--------------------------------------------------------------------------- # 'object' interface #--------------------------------------------------------------------------- @@ -36,7 +48,7 @@ source, hidden, interactive) if executed and not hidden: - # Save the command unless it was an empty string or was identical + # Save the command unless it was an empty string or was identical # to the previous command. history = history.rstrip() if history and (not self._history or self._history[-1] != history): @@ -74,7 +86,7 @@ # search. cursor = self._get_prompt_cursor() if self._history_prefix: - cursor.movePosition(QtGui.QTextCursor.Right, + cursor.movePosition(QtGui.QTextCursor.Right, n=len(self._history_prefix)) else: cursor.movePosition(QtGui.QTextCursor.EndOfLine) @@ -100,7 +112,7 @@ # input buffer is set.) if self._history_prefix: cursor = self._get_prompt_cursor() - cursor.movePosition(QtGui.QTextCursor.Right, + cursor.movePosition(QtGui.QTextCursor.Right, n=len(self._history_prefix)) self._set_cursor(cursor) @@ -128,7 +140,7 @@ break else: history = None - + if history is not None: self._history_index = index self.input_buffer = history @@ -156,8 +168,11 @@ # 'HistoryConsoleWidget' protected interface #--------------------------------------------------------------------------- - def _set_history(self, history): + def _set_history(self, history, history_index=None): """ Replace the current history with a sequence of history items. """ + if history_index is None: + history_index = len(history) + self._history = list(history) - self._history_index = len(self._history) + self._history_index = history_index diff -Nru python-pyface-4.5.2/pyface/ui/qt4/dialog.py python-pyface-6.1.2/pyface/ui/qt4/dialog.py --- python-pyface-4.5.2/pyface/ui/qt4/dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -20,7 +20,7 @@ # Local imports. from pyface.i_dialog import IDialog, MDialog from pyface.constant import OK, CANCEL, YES, NO -from window import Window +from .window import Window # Map PyQt dialog related constants to the pyface equivalents. @@ -76,8 +76,7 @@ btn = buttons.addButton(QtGui.QDialogButtonBox.Ok) btn.setDefault(True) - QtCore.QObject.connect(btn, QtCore.SIGNAL('clicked()'), - self.control, QtCore.SLOT('accept()')) + btn.clicked.connect(self.control.accept) # 'Cancel' button. if self.cancel_label: @@ -86,8 +85,7 @@ else: btn = buttons.addButton(QtGui.QDialogButtonBox.Cancel) - QtCore.QObject.connect(btn, QtCore.SIGNAL('clicked()'), - self.control, QtCore.SLOT('reject()')) + btn.clicked.connect(self.control.reject) # 'Help' button. # FIXME v3: In the original code the only possible hook into the help @@ -139,12 +137,14 @@ # Setting return code and firing close events is handled for 'modal' in # MDialog's open method. For 'nonmodal', we do it here. if self.style == 'nonmodal': - QtCore.QObject.connect(dlg, QtCore.SIGNAL('finished(int)'), - self._finished_fired) + dlg.finished.connect(self._finished_fired) if self.size != (-1, -1): dlg.resize(*self.size) + if self.position != (-1, -1): + dlg.move(*self.position) + dlg.setWindowTitle(self.title) return dlg @@ -158,5 +158,3 @@ self.return_code = _RESULT_MAP[result] self.close() - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/qt4/directory_dialog.py python-pyface-6.1.2/pyface/ui/qt4/directory_dialog.py --- python-pyface-4.5.2/pyface/ui/qt4/directory_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/directory_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -19,7 +19,8 @@ # Local imports. from pyface.i_directory_dialog import IDirectoryDialog, MDirectoryDialog -from dialog import Dialog +from .dialog import Dialog +import six @provides(IDirectoryDialog) @@ -56,7 +57,7 @@ files = self.control.selectedFiles() if files: - self.path = unicode(files[0]) + self.path = six.text_type(files[0]) else: self.path = '' @@ -74,7 +75,7 @@ dlg.setFileMode(QtGui.QFileDialog.DirectoryOnly) if not self.new_directory: - dlg.setReadOnly(True) + dlg.setOptions(QtGui.QFileDialog.ReadOnly) if self.message: dlg.setLabelText(QtGui.QFileDialog.LookIn, self.message) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/fields/combo_field.py python-pyface-6.1.2/pyface/ui/qt4/fields/combo_field.py --- python-pyface-4.5.2/pyface/ui/qt4/fields/combo_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/fields/combo_field.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,105 @@ +# Copyright (c) 2019, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: + +""" The Qt-specific implementation of the combo field class """ + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +from traits.api import provides + +from pyface.fields.i_combo_field import IComboField, MComboField +from pyface.qt.QtCore import Qt +from pyface.qt.QtGui import QComboBox +from .field import Field + + +@provides(IComboField) +class ComboField(MComboField, Field): + """ The Qt-specific implementation of the combo field class """ + + # ------------------------------------------------------------------------ + # IWidget interface + # ------------------------------------------------------------------------ + + def _create_control(self, parent): + """ Create the toolkit-specific control that represents the widget. """ + control = QComboBox(parent) + control.setInsertPolicy(QComboBox.NoInsert) + control.setEditable(False) + return control + + # ------------------------------------------------------------------------ + # Private interface + # ------------------------------------------------------------------------ + + def _update_value(self, value): + """ Handle a change to the value from user interaction + """ + self.value = self._get_control_value() + + # Toolkit control interface --------------------------------------------- + + def _get_control_value(self): + """ Toolkit specific method to get the control's value. """ + index = self.control.currentIndex() + if index != -1: + return self.control.itemData(index) + else: + raise IndexError("no value selected") + + def _get_control_text(self): + """ Toolkit specific method to get the control's value. """ + index = self.control.currentIndex() + if index != -1: + return self.control.itemData(index, Qt.DisplayRole) + else: + raise IndexError("no value selected") + + def _set_control_value(self, value): + """ Toolkit specific method to set the control's value. """ + index = self.values.index(value) + self.control.setCurrentIndex(index) + self.control.activated.emit(index) + + def _observe_control_value(self, remove=False): + """ Toolkit specific method to change the control value observer. """ + if remove: + self.control.activated.disconnect(self._update_value) + else: + self.control.activated.connect(self._update_value) + + def _get_control_text_values(self): + """ Toolkit specific method to get the control's values. """ + model = self.control.model() + values = [] + for i in range(model.rowCount()): + values.append(model.item(i)) + return values + + def _set_control_values(self, values): + """ Toolkit specific method to set the control's values. """ + current_value = self.value + self.control.clear() + for value in self.values: + item = self.formatter(value) + if isinstance(item, tuple): + image, text = item + icon = image.create_icon() + self.control.addItem(icon, text, userData=value) + else: + self.control.addItem(item, userData=value) + if current_value in values: + self._set_control_value(current_value) + else: + self._set_control_value(self.value) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/fields/field.py python-pyface-6.1.2/pyface/ui/qt4/fields/field.py --- python-pyface-4.5.2/pyface/ui/qt4/fields/field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/fields/field.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,70 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2017-19, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" The Qt-specific implementation of the text field class """ + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +from traits.api import Any, Instance, Unicode, provides + +from pyface.qt.QtCore import Qt +from pyface.fields.i_field import IField, MField +from pyface.ui.qt4.widget import Widget + + +@provides(IField) +class Field(MField, Widget): + """ The Qt-specific implementation of the field class + + This is an abstract class which is not meant to be instantiated. + """ + + #: The value held by the field. + value = Any + + #: A tooltip for the field. + tooltip = Unicode + + #: An optional context menu for the field. + context_menu = Instance('pyface.action.menu_manager.MenuManager') + + # ------------------------------------------------------------------------ + # Private interface + # ------------------------------------------------------------------------ + + def _get_control_tooltip(self): + """ Toolkit specific method to get the control's tooltip. """ + return self.control.toolTip() + + def _set_control_tooltip(self, tooltip): + """ Toolkit specific method to set the control's tooltip. """ + self.control.setToolTip(tooltip) + + def _observe_control_context_menu(self, remove=False): + """ Toolkit specific method to change the control menu observer. """ + if remove: + self.control.setContextMenuPolicy(Qt.DefaultContextMenu) + self.control.customContextMenuRequested.disconnect( + self._handle_control_context_menu) + else: + self.control.customContextMenuRequested.connect( + self._handle_control_context_menu) + self.control.setContextMenuPolicy(Qt.CustomContextMenu) + + def _handle_control_context_menu(self, pos): + """ Signal handler for displaying context menu. """ + if self.control is not None and self.context_menu is not None: + menu = self.context_menu.create_menu(self.control) + menu.show(pos.x(), pos.y()) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/fields/spin_field.py python-pyface-6.1.2/pyface/ui/qt4/fields/spin_field.py --- python-pyface-4.5.2/pyface/ui/qt4/fields/spin_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/fields/spin_field.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,65 @@ +# Copyright (c) 2017-19, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: + +""" The Qt-specific implementation of the spin field class """ + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +from traits.api import provides + +from pyface.fields.i_spin_field import ISpinField, MSpinField +from pyface.qt.QtGui import QSpinBox +from .field import Field + + +@provides(ISpinField) +class SpinField(MSpinField, Field): + """ The Qt-specific implementation of the spin field class """ + + # ------------------------------------------------------------------------ + # IWidget interface + # ------------------------------------------------------------------------ + + def _create_control(self, parent): + """ Create the toolkit-specific control that represents the widget. """ + + control = QSpinBox(parent) + return control + + # ------------------------------------------------------------------------ + # Private interface + # ------------------------------------------------------------------------ + + def _get_control_value(self): + """ Toolkit specific method to get the control's value. """ + return self.control.value() + + def _set_control_value(self, value): + """ Toolkit specific method to set the control's value. """ + self.control.setValue(value) + + def _observe_control_value(self, remove=False): + """ Toolkit specific method to change the control value observer. """ + if remove: + self.control.valueChanged[int].disconnect(self._update_value) + else: + self.control.valueChanged[int].connect(self._update_value) + + def _get_control_bounds(self): + """ Toolkit specific method to get the control's bounds. """ + return (self.control.minimum(), self.control.maximum()) + + def _set_control_bounds(self, bounds): + """ Toolkit specific method to set the control's bounds. """ + self.control.setRange(*bounds) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/fields/text_field.py python-pyface-6.1.2/pyface/ui/qt4/fields/text_field.py --- python-pyface-4.5.2/pyface/ui/qt4/fields/text_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/fields/text_field.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,113 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2017-19, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" The Qt-specific implementation of the text field class """ + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +from traits.api import Trait, provides + +from pyface.fields.i_text_field import ITextField, MTextField +from pyface.qt.QtGui import QLineEdit +from .field import Field + + +ECHO_TO_QT_ECHO_MODE = { + 'normal': QLineEdit.Normal, + 'password': QLineEdit.Password, + 'none': QLineEdit.NoEcho, + 'when_editing': QLineEdit.PasswordEchoOnEdit, +} +QT_ECHO_MODE_TO_ECHO = { + value: key for key, value in ECHO_TO_QT_ECHO_MODE.items() +} + +# mapped trait for Qt line edit echo modes +Echo = Trait( + 'normal', + ECHO_TO_QT_ECHO_MODE, +) + + +@provides(ITextField) +class TextField(MTextField, Field): + """ The Qt-specific implementation of the text field class """ + + #: Display typed text, or one of several hidden "password" modes. + echo = Echo + + # ------------------------------------------------------------------------ + # IWidget interface + # ------------------------------------------------------------------------ + + def _create_control(self, parent): + """ Create the toolkit-specific control that represents the widget. """ + control = QLineEdit(parent) + return control + + # ------------------------------------------------------------------------ + # Private interface + # ------------------------------------------------------------------------ + + def _get_control_value(self): + """ Toolkit specific method to get the control's value. """ + return self.control.text() + + def _set_control_value(self, value): + """ Toolkit specific method to set the control's value. """ + self.control.setText(value) + # fire update + if self.update_text == 'editing_finished': + self.control.editingFinished.emit() + else: + self.control.textEdited.emit(value) + + def _observe_control_value(self, remove=False): + """ Toolkit specific method to change the control value observer. """ + if remove: + self.control.textEdited.disconnect(self._update_value) + else: + self.control.textEdited.connect(self._update_value) + + def _get_control_placeholder(self): + """ Toolkit specific method to set the control's placeholder. """ + return self.control.placeholderText() + + def _set_control_placeholder(self, placeholder): + """ Toolkit specific method to set the control's placeholder. """ + self.control.setPlaceholderText(placeholder) + + def _get_control_echo(self): + """ Toolkit specific method to get the control's echo. """ + return QT_ECHO_MODE_TO_ECHO[self.control.echoMode()] + + def _set_control_echo(self, echo): + """ Toolkit specific method to set the control's echo. """ + self.control.setEchoMode(ECHO_TO_QT_ECHO_MODE[echo]) + + def _get_control_read_only(self): + """ Toolkit specific method to get the control's read_only state. """ + return self.control.isReadOnly() + + def _set_control_read_only(self, read_only): + """ Toolkit specific method to set the control's read_only state. """ + self.control.setReadOnly(read_only) + + def _observe_control_editing_finished(self, remove=False): + """ Change observation of whether editing is finished. """ + if remove: + self.control.editingFinished.disconnect(self._editing_finished) + else: + self.control.editingFinished.connect(self._editing_finished) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/file_dialog.py python-pyface-6.1.2/pyface/ui/qt4/file_dialog.py --- python-pyface-4.5.2/pyface/ui/qt4/file_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/file_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -22,7 +22,8 @@ # Local imports. from pyface.i_file_dialog import IFileDialog, MFileDialog -from dialog import Dialog +from .dialog import Dialog +import six @provides(IFileDialog) @@ -65,7 +66,7 @@ def create_wildcard(cls, description, extension): """ Creates a wildcard for a given extension. """ - if isinstance(extension, basestring): + if isinstance(extension, six.string_types): pattern = extension else: @@ -90,8 +91,8 @@ files = self.control.selectedFiles() if files: - self.path = unicode(files[0]) - self.paths = [unicode(file) for file in files] + self.path = six.text_type(files[0]) + self.paths = [six.text_type(file) for file in files] else: self.path = '' self.paths = [''] diff -Nru python-pyface-4.5.2/pyface/ui/qt4/gui.py python-pyface-6.1.2/pyface/ui/qt4/gui.py --- python-pyface-4.5.2/pyface/ui/qt4/gui.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/gui.py 2019-07-20 11:46:59.000000000 +0000 @@ -59,26 +59,23 @@ # 'GUI' class interface. ########################################################################### + @classmethod def invoke_after(cls, millisecs, callable, *args, **kw): _FutureCall(millisecs, callable, *args, **kw) - invoke_after = classmethod(invoke_after) - + @classmethod def invoke_later(cls, callable, *args, **kw): _FutureCall(0, callable, *args, **kw) - invoke_later = classmethod(invoke_later) - + @classmethod def set_trait_after(cls, millisecs, obj, trait_name, new): _FutureCall(millisecs, setattr, obj, trait_name, new) - set_trait_after = classmethod(set_trait_after) - + @classmethod def set_trait_later(cls, obj, trait_name, new): _FutureCall(0, setattr, obj, trait_name, new) - set_trait_later = classmethod(set_trait_later) - + @staticmethod def process_events(allow_user_events=True): if allow_user_events: events = QtCore.QEventLoop.AllEvents @@ -87,16 +84,13 @@ QtCore.QCoreApplication.processEvents(events) - process_events = staticmethod(process_events) - + @staticmethod def set_busy(busy=True): if busy: QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) else: QtGui.QApplication.restoreOverrideCursor() - set_busy = staticmethod(set_busy) - ########################################################################### # 'GUI' interface. ########################################################################### @@ -159,8 +153,10 @@ # Save the instance. self._calls_mutex.lock() - self._calls.append(self) - self._calls_mutex.unlock() + try: + self._calls.append(self) + finally: + self._calls_mutex.unlock() # Move to the main GUI thread. self.moveToThread(QtGui.QApplication.instance().thread()) @@ -170,14 +166,23 @@ # that only works on QThreads. We want regular Python threads to work. event = QtCore.QEvent(self._pyface_event) QtGui.QApplication.postEvent(self, event) - QtGui.QApplication.sendPostedEvents() def event(self, event): """ QObject event handler. """ if event.type() == self._pyface_event: - # Invoke the callable (puts it at the end of the event queue) - QtCore.QTimer.singleShot(self._ms, self._dispatch) + if self._ms == 0: + # Invoke the callable now + try: + self._callable(*self._args, **self._kw) + finally: + # We cannot remove from self._calls here. QObjects don't like being + # garbage collected during event handlers (there are tracebacks, + # plus maybe a memory leak, I think). + QtCore.QTimer.singleShot(0, self._finished) + else: + # Invoke the callable (puts it at the end of the event queue) + QtCore.QTimer.singleShot(self._ms, self._dispatch) return True return super(_FutureCall, self).event(event) @@ -198,5 +203,3 @@ self._calls.remove(self) finally: self._calls_mutex.unlock() - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/qt4/heading_text.py python-pyface-6.1.2/pyface/ui/qt4/heading_text.py --- python-pyface-4.5.2/pyface/ui/qt4/heading_text.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/heading_text.py 2019-05-03 08:18:50.000000000 +0000 @@ -19,7 +19,7 @@ # Local imports. from pyface.i_heading_text import IHeadingText, MHeadingText -from widget import Widget +from .widget import Widget @provides(IHeadingText) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/image_cache.py python-pyface-6.1.2/pyface/ui/qt4/image_cache.py --- python-pyface-4.5.2/pyface/ui/qt4/image_cache.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/image_cache.py 2019-05-03 08:18:50.000000000 +0000 @@ -41,9 +41,9 @@ ########################################################################### def get_image(self, filename): - image = QtGui.QPixmap(self._width, self._height) + image = QtGui.QPixmapCache.find(filename) - if QtGui.QPixmapCache.find(filename, image): + if image is not None: scaled = self._qt4_scale(image) if scaled is not image: @@ -53,7 +53,7 @@ QtGui.QPixmapCache.insert(filename, scaled) else: # Load the image from the file and add it to the cache. - image.load(filename) + image = QtGui.QPixmap(filename) scaled = self._qt4_scale(image) QtGui.QPixmapCache.insert(filename, scaled) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/image_resource.py python-pyface-6.1.2/pyface/ui/qt4/image_resource.py --- python-pyface-4.5.2/pyface/ui/qt4/image_resource.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/image_resource.py 2019-05-03 08:18:50.000000000 +0000 @@ -62,6 +62,22 @@ return QtGui.QIcon(image) + def image_size(cls, image): + """ Get the size of a toolkit image + + Parameters + ---------- + image : toolkit image + A toolkit image to compute the size of. + + Returns + ------- + size : tuple + The (width, height) tuple giving the size of the image. + """ + size = image.size() + return (size.width(), size.height()) + ########################################################################### # Private interface. ########################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/qt4/init.py python-pyface-6.1.2/pyface/ui/qt4/init.py --- python-pyface-4.5.2/pyface/ui/qt4/init.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/init.py 2019-05-03 08:18:50.000000000 +0000 @@ -2,28 +2,36 @@ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # -# This software is provided without warranty under the terms of the BSD license. -# However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply - +# Copyright (c) 2017, Enthought, Inc. +# All rights reserved. # -# Author: Riverbank Computing Limited -# Description: +# This software is provided without warranty under the terms of the BSD +# license. However, when used with the GPL version of PyQt the additional +# terms described in the PyQt GPL exception also apply. +# +# Author: Riverbank Computing Limited and Enthought developers #------------------------------------------------------------------------------ -# Standard library imports. import sys -# Major package imports. +from traits.trait_notifiers import set_ui_handler, ui_handler + from pyface.qt import QtCore, QtGui, qt_api +from pyface.base_toolkit import Toolkit +from .gui import GUI if qt_api == 'pyqt': # Check the version numbers are late enough. if QtCore.QT_VERSION < 0x040200: - raise RuntimeError, "Need Qt v4.2 or higher, but got v%s" % QtCore.QT_VERSION_STR + raise RuntimeError( + "Need Qt v4.2 or higher, but got v%s" % QtCore.QT_VERSION_STR + ) if QtCore.PYQT_VERSION < 0x040100: - raise RuntimeError, "Need PyQt v4.1 or higher, but got v%s" % QtCore.PYQT_VERSION_STR + raise RuntimeError( + "Need PyQt v4.1 or higher, but got v%s" % QtCore.PYQT_VERSION_STR + ) # It's possible that it has already been initialised. _app = QtGui.QApplication.instance() @@ -31,4 +39,12 @@ if _app is None: _app = QtGui.QApplication(sys.argv) -#### EOF ###################################################################### + +# create the toolkit object +toolkit_object = Toolkit('pyface', 'qt4', 'pyface.ui.qt4') + + +# ensure that Traits has a UI handler appropriate for the toolkit. +if ui_handler is None: + # Tell the traits notification handlers to use this UI handler + set_ui_handler(GUI.invoke_later) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/message_dialog.py python-pyface-6.1.2/pyface/ui/qt4/message_dialog.py --- python-pyface-4.5.2/pyface/ui/qt4/message_dialog.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/message_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -19,7 +19,7 @@ # Local imports. from pyface.i_message_dialog import IMessageDialog, MMessageDialog -from dialog import Dialog +from .dialog import Dialog # Map the ETS severity to the corresponding PyQt standard icon. @@ -65,6 +65,11 @@ self.title, self.message, QtGui.QMessageBox.Ok, parent) message_box.setInformativeText(self.informative) message_box.setDetailedText(self.detail) - return message_box -#### EOF ###################################################################### + if self.size != (-1, -1): + message_box.resize(*self.size) + + if self.position != (-1, -1): + message_box.move(*self.position) + + return message_box diff -Nru python-pyface-4.5.2/pyface/ui/qt4/mimedata.py python-pyface-6.1.2/pyface/ui/qt4/mimedata.py --- python-pyface-4.5.2/pyface/ui/qt4/mimedata.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/mimedata.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,140 @@ + +from six.moves.cPickle import dumps, load, loads, PickleError +import warnings +import io +import sys + +from pyface.qt import QtCore + + +#------------------------------------------------------------------------------- +# 'PyMimeData' class: +#------------------------------------------------------------------------------- + +if sys.version_info[0] < 3: + def str2bytes(s): + return s +else: + def str2bytes(s): + return bytes(s,'ascii') + + +class PyMimeData(QtCore.QMimeData): + """ The PyMimeData wraps a Python instance as MIME data. + """ + # The MIME type for instances. + MIME_TYPE = u'application/x-ets-qt4-instance' + NOPICKLE_MIME_TYPE = u'application/x-ets-qt4-instance-no-pickle' + + def __init__(self, data=None, pickle=True): + """ Initialise the instance. + """ + QtCore.QMimeData.__init__(self) + + # Keep a local reference to be returned if possible. + self._local_instance = data + + if pickle: + if data is not None: + # We may not be able to pickle the data. + try: + pdata = dumps(data) + # This format (as opposed to using a single sequence) allows + # the type to be extracted without unpickling the data. + self.setData(self.MIME_TYPE, dumps(data.__class__) + pdata) + except (PickleError, TypeError, AttributeError): + # if pickle fails, still try to create a draggable + warnings.warn(("Could not pickle dragged object %s, " + + "using %s mimetype instead") % (repr(data), + self.NOPICKLE_MIME_TYPE), RuntimeWarning) + self.setData(self.NOPICKLE_MIME_TYPE, str2bytes(str(id(data)))) + + else: + self.setData(self.NOPICKLE_MIME_TYPE, str2bytes(str(id(data)))) + + @classmethod + def coerce(cls, md): + """ Wrap a QMimeData or a python object to a PyMimeData. + """ + # See if the data is already of the right type. If it is then we know + # we are in the same process. + if isinstance(md, cls): + return md + + if isinstance(md, PyMimeData): + # if it is a PyMimeData, migrate all its data, subclasses should + # override this method if it doesn't do thgs correctly for them + data = md.instance() + nmd = cls() + nmd._local_instance = data + for format in md.formats(): + nmd.setData(format, md.data(format)) + elif isinstance(md, QtCore.QMimeData): + # if it is a QMimeData, migrate all its data + nmd = cls() + for format in md.formats(): + nmd.setData(format, md.data(format)) + else: + # by default, try to pickle the coerced object + pickle = True + + # See if the data is a list, if so check for any items which are + # themselves of the right type. If so, extract the instance and + # track whether we should pickle. + # XXX lists should suffice for now, but may want other containers + if isinstance(md, list): + pickle = not any(item.hasFormat(cls.NOPICKLE_MIME_TYPE) + for item in md if isinstance(item, QtCore.QMimeData)) + md = [item.instance() if isinstance(item, PyMimeData) else item + for item in md] + + # Arbitrary python object, wrap it into PyMimeData + nmd = cls(md, pickle) + + return nmd + + def instance(self): + """ Return the instance. + """ + if self._local_instance is not None: + return self._local_instance + + if not self.hasFormat(self.MIME_TYPE): + # We have no pickled python data defined. + return None + + stream = io.BytesIO(self.data(self.MIME_TYPE).data()) + + try: + # Skip the type. + load(stream) + + # Recreate the instance. + return load(stream) + except PickleError: + pass + + return None + + def instanceType(self): + """ Return the type of the instance. + """ + if self._local_instance is not None: + return self._local_instance.__class__ + + try: + if self.hasFormat(self.MIME_TYPE): + return loads(self.data(self.MIME_TYPE).data()) + except PickleError: + pass + + return None + + def localPaths(self): + """ The list of local paths from url list, if any. + """ + ret = [] + for url in self.urls(): + if url.scheme() == 'file': + ret.append(url.toLocalFile()) + return ret diff -Nru python-pyface-4.5.2/pyface/ui/qt4/progress_dialog.py python-pyface-6.1.2/pyface/ui/qt4/progress_dialog.py --- python-pyface-4.5.2/pyface/ui/qt4/progress_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/progress_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -17,28 +17,38 @@ from pyface.qt import QtGui, QtCore +from traits.api import Bool, Instance, Int, Unicode, provides -# Enthought library imports -from traits.api import Bool, Enum, Instance, Int, provides, Unicode - -# Local imports -from widget import Widget from pyface.i_progress_dialog import IProgressDialog, MProgressDialog -from window import Window +from .window import Window + +@provides(IProgressDialog) class ProgressDialog(MProgressDialog, Window): """ A simple progress dialog window which allows itself to be updated - FIXME: buttons are not set up correctly yet - """ + # FIXME: buttons are not set up correctly yet + #: The progress bar widget progress_bar = Instance(QtGui.QProgressBar) + + #: The window title title = Unicode + + #: The text message to display in the dialog message = Unicode + + #: The minimum value of the progress range min = Int + + #: The minimum value of the progress range max = Int + + #: The margin around the progress bar margin = Int(5) + + #: Whether or not the progress dialog can be cancelled can_cancel = Bool(False) # The IProgressDialog interface doesn't declare this, but since this is a @@ -46,34 +56,63 @@ # offer an option to disable it. can_ok = Bool(False) + #: Whether or not to show the time taken (not implemented in Qt) show_time = Bool(False) + + #: Whether or not to show the percent completed show_percent = Bool(False) - _user_cancelled = Bool(False) + #: The size of the dialog dialog_size = Instance(QtCore.QRect) - # Label for the 'cancel' button + #: Label for the 'cancel' button cancel_button_label = Unicode('Cancel') + #: Whether or not the dialog was cancelled by the user + _user_cancelled = Bool(False) + + #: The widget showing the message text + _message_control = Instance(QtGui.QLabel) + + #: The widget showing the time elapsed + _elapsed_control = Instance(QtGui.QLabel) + + #: The widget showing the estimated time to completion + _estimated_control = Instance(QtGui.QLabel) + + #: The widget showing the estimated time remaining + _remaining_control = Instance(QtGui.QLabel) + + #------------------------------------------------------------------------- + # IWindow Interface + #------------------------------------------------------------------------- + def open(self): + """ Opens the window. """ super(ProgressDialog, self).open() self._start_time = time.time() def close(self): + """ Closes the window. """ self.progress_bar.destroy() self.progress_bar = None super(ProgressDialog, self).close() - def change_message(self, message): - self.message = message + #------------------------------------------------------------------------- + # IProgressDialog Interface + #------------------------------------------------------------------------- def update(self, value): - """ - updates the progress bar to the desired value. If the value is >= - the maximum and the progress bar is not contained in another panel - the parent window will be closed + """ Update the progress bar to the desired value + + If the value is >= the maximum and the progress bar is not contained + in another panel the parent window will be closed. + Parameters + ---------- + value : + The progress value to set. """ if self.progress_bar is None: @@ -93,15 +132,9 @@ estimated = elapsed/percent remaining = estimated - elapsed - self._set_time_label(elapsed, - self._elapsed_control) - self._set_time_label(estimated, - self._estimated_control) - self._set_time_label(remaining, - self._remaining_control) - - if self.show_percent: - self._percent_control = "%3f" % ((percent * 100) % 1) + self._set_time_label(elapsed, self._elapsed_control) + self._set_time_label(estimated, self._estimated_control) + self._set_time_label(remaining, self._remaining_control) if value >= self.max or self._user_cancelled: self.close() @@ -115,18 +148,21 @@ return (not self._user_cancelled, False) + #------------------------------------------------------------------------- + # Private Interface + #------------------------------------------------------------------------- + def reject(self, event): self._user_cancelled = True self.close() - def _set_time_label(self, value, control): hours = value / 3600 minutes = (value % 3600) / 60 seconds = value % 60 label = "%1u:%02u:%02u" % (hours, minutes, seconds) - control.setText(control.text()[:-7] + label) + control.setText(label) def _create_buttons(self, dialog, layout): """ Creates the buttons. """ @@ -145,9 +181,9 @@ # TODO: hookup the buttons to our methods, this may involve subclassing from QDialog if self.can_cancel: - buttons.connect(buttons, QtCore.SIGNAL('rejected()'), dialog, QtCore.SLOT('reject()')) + buttons.rejected.connect(dialog.reject) if self.can_ok: - buttons.connect(buttons, QtCore.SIGNAL('accepted()'), dialog, QtCore.SLOT('accept()')) + buttons.accepted.connect(dialog.accept) layout.addWidget(buttons) @@ -171,7 +207,6 @@ def _create_gauge(self, dialog, layout): self.progress_bar = QtGui.QProgressBar(dialog) -# self.progress_bar.setFrameStyle(QtGui.QFrame.Sunken | QtGui.QFrame.Panel) self.progress_bar.setRange(self.min, self.max) layout.addWidget(self.progress_bar) @@ -180,19 +215,18 @@ else: self.progress_bar.setFormat("%v") - - return - def _create_message(self, dialog, layout): label = QtGui.QLabel(self.message, dialog) label.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft) layout.addWidget(label) - + self._message_control = label return - def _create_percent(self, dialog, layout): - #not an option with the QT progress bar - return + def _create_percent(self, dialog, parent_sizer): + if not self.show_percent: + return + + raise NotImplementedError def _create_timer(self, dialog, layout): if not self.show_time: @@ -202,23 +236,22 @@ self._estimated_control = self._create_label(dialog, layout, "Estimated time : ") self._remaining_control = self._create_label(dialog, layout, "Remaining time : ") - return - def _create_control(self, parent): return QtGui.QDialog(parent) def _create(self): super(ProgressDialog, self)._create() - contents = self._create_contents(self.control) + self._create_contents(self.control) def _create_contents(self, parent): dialog = parent layout = QtGui.QVBoxLayout(dialog) + layout.setContentsMargins(self.margin, self.margin, + self.margin, self.margin) # The 'guts' of the dialog. self._create_message(dialog, layout) self._create_gauge(dialog, layout) - self._create_percent(dialog, layout) self._create_timer(dialog, layout) self._create_buttons(dialog, layout) @@ -226,6 +259,10 @@ parent.setLayout(layout) + #------------------------------------------------------------------------- + # Trait change handlers + #------------------------------------------------------------------------- + def _max_changed(self, new): if self.progress_bar is not None: self.progress_bar.setMaximum(new) @@ -233,3 +270,7 @@ def _min_changed(self, new): if self.progress_bar is not None: self.progress_bar.setMinimum(new) + + def _message_changed(self, new): + if self._message_control is not None: + self._message_control.setText(new) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/python_editor.py python-pyface-6.1.2/pyface/ui/qt4/python_editor.py --- python-pyface-4.5.2/pyface/ui/qt4/python_editor.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/python_editor.py 2019-05-03 08:18:50.000000000 +0000 @@ -53,8 +53,8 @@ ########################################################################### def __init__(self, parent, **traits): - super(PythonEditor, self).__init__(**traits) - self.control = self._create_control(parent) + super(PythonEditor, self).__init__(parent=parent, **traits) + self._create() ########################################################################### # 'PythonEditor' interface. @@ -83,7 +83,7 @@ if path is None: path = self.path - f = file(path, 'w') + f = open(path, 'w') f.write(self.control.code.toPlainText()) f.close() @@ -97,6 +97,33 @@ QtGui.QTextCursor.KeepAnchor) ########################################################################### + # 'Widget' interface. + ########################################################################### + + def _add_event_listeners(self): + super(PythonEditor, self)._add_event_listeners() + self.control.code.installEventFilter(self._event_filter) + + # Connect signals for text changes. + self.control.code.modificationChanged.connect(self._on_dirty_changed) + self.control.code.textChanged.connect(self._on_text_changed) + + def _remove_event_listeners(self): + if self.control is not None: + # Disconnect signals for text changes. + self.control.code.modificationChanged.disconnect( + self._on_dirty_changed) + self.control.code.textChanged.disconnect(self._on_text_changed) + + if self._event_filter is not None: + self.control.code.removeEventFilter(self._event_filter) + + super(PythonEditor, self)._remove_event_listeners() + + def __event_filter_default(self): + return PythonEditorEventFilter(self, self.control) + + ########################################################################### # Trait handlers. ########################################################################### @@ -119,15 +146,6 @@ self.control = control = AdvancedCodeWidget(parent) self._show_line_numbers_changed() - # Install event filter to trap key presses. - event_filter = PythonEditorEventFilter(self, self.control) - self.control.installEventFilter(event_filter) - self.control.code.installEventFilter(event_filter) - - # Connect signals for text changes. - control.code.modificationChanged.connect(self._on_dirty_changed) - control.code.textChanged.connect(self._on_text_changed) - # Load the editor's contents. self.load() @@ -160,7 +178,7 @@ if self.__editor.control and obj == self.__editor.control and \ event.type() == QtCore.QEvent.FocusOut: # Hack for Traits UI compatibility. - self.__editor.control.emit(QtCore.SIGNAL('lostFocus')) + self.__editor.control.lostFocus.emit() elif self.__editor.control and obj == self.__editor.control.code and \ event.type() == QtCore.QEvent.KeyPress: diff -Nru python-pyface-4.5.2/pyface/ui/qt4/python_shell.py python-pyface-6.1.2/pyface/ui/qt4/python_shell.py --- python-pyface-4.5.2/pyface/ui/qt4/python_shell.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/python_shell.py 2019-07-20 11:46:59.000000000 +0000 @@ -1,4 +1,3 @@ -#------------------------------------------------------------------------------ # Copyright (c) 2011, Enthought, Inc. # All rights reserved. # @@ -9,12 +8,12 @@ # Thanks for using Enthought open source! # # Author: Evan Patterson -#------------------------------------------------------------------------------ + # Standard library imports. -import __builtin__ +import six.moves.builtins from code import compile_command, InteractiveInterpreter -from cStringIO import StringIO +from six.moves import cStringIO as StringIO import sys from time import time @@ -27,16 +26,14 @@ from traits.util.clean_strings import python_name # Local imports. -from code_editor.pygments_highlighter import PygmentsHighlighter -from console.api import BracketMatcher, CallTipWidget, CompletionLexer, \ +from .code_editor.pygments_highlighter import PygmentsHighlighter +from .console.api import BracketMatcher, CallTipWidget, CompletionLexer, \ HistoryConsoleWidget from pyface.i_python_shell import IPythonShell, MPythonShell from pyface.key_pressed_event import KeyPressedEvent -from widget import Widget +from .widget import Widget +import six -#------------------------------------------------------------------------------- -# 'PythonShell' class: -#------------------------------------------------------------------------------- @provides(IPythonShell) class PythonShell(MPythonShell, Widget): @@ -58,16 +55,10 @@ # FIXME v3: Either make this API consistent with other Widget sub-classes # or make it a sub-class of HasTraits. def __init__(self, parent, **traits): - super(PythonShell, self).__init__(**traits) + super(PythonShell, self).__init__(parent=parent, **traits) # Create the toolkit-specific control that represents the widget. - self.control = self._create_control(parent) - - # Set up to be notified whenever a Python statement is executed: - self.control.executed.connect(self._on_command_executed) - - # Handle dropped objects. - _DropEventEmitter(self.control).signal.connect(self._on_obj_drop) + self._create() #-------------------------------------------------------------------------- # 'IPythonShell' interface @@ -82,6 +73,32 @@ def execute_file(self, path, hidden=True): self.control.execute_file(path, hidden=hidden) + def get_history(self): + """ Return the current command history and index. + + Returns + ------- + history : list of str + The list of commands in the new history. + history_index : int from 0 to len(history) + The current item in the command history navigation. + """ + return self.control._history, self.control._history_index + + def set_history(self, history, history_index): + """ Replace the current command history and index with new ones. + + Parameters + ---------- + history : list of str + The list of commands in the new history. + history_index : int + The current item in the command history navigation. + """ + if not 0 <= history_index <= len(history): + history_index = len(history) + self.control._set_history(history, history_index) + #-------------------------------------------------------------------------- # 'IWidget' interface. #-------------------------------------------------------------------------- @@ -89,6 +106,24 @@ def _create_control(self, parent): return PyfacePythonWidget(self, parent) + def _add_event_listeners(self): + super(PythonShell, self)._add_event_listeners() + + # Connect signals for events. + self.control.executed.connect(self._on_command_executed) + self._event_filter.signal.connect(self._on_obj_drop) + + def _remove_event_listeners(self): + if self.control is not None: + # Disconnect signals for events. + self.control.executed.connect(self._on_command_executed) + self._event_filter.signal.disconnect(self._on_obj_drop) + + super(PythonShell, self)._remove_event_listeners() + + def __event_filter_default(self): + return _DropEventEmitter(self.control) + #-------------------------------------------------------------------------- # 'Private' interface. #-------------------------------------------------------------------------- @@ -100,7 +135,7 @@ name = 'dragged' if hasattr(obj, 'name') \ - and isinstance(obj.name, basestring) and len(obj.name) > 0: + and isinstance(obj.name, six.string_types) and len(obj.name) > 0: py_name = python_name(obj.name) # Make sure that the name is actually a valid Python identifier. @@ -115,10 +150,6 @@ self.control._control.setFocus() -#------------------------------------------------------------------------------- -# 'PythonWidget' class: -#------------------------------------------------------------------------------- - class PythonWidget(HistoryConsoleWidget): """ A basic in-process Python interpreter. """ @@ -329,7 +360,8 @@ """ Attempts to execute file with 'path'. If 'hidden', no output is shown. """ - self.execute('execfile(%s)' % repr(path), hidden=hidden) + + self.execute("exec(open(%s).read())" % repr(path), hidden=hidden) def reset(self): """ Resets the widget to its initial state. Similar to ``clear``, but @@ -375,8 +407,8 @@ if len(leftover) == 1: leftover = leftover[0] if symbol is None: - names = self.interpreter.locals.keys() - names += __builtin__.__dict__.keys() + names = list(self.interpreter.locals.keys()) + names += list(six.moves.builtins.__dict__.keys()) else: names = dir(symbol) completions = [ n for n in names if n.startswith(leftover) ] @@ -408,14 +440,14 @@ """ Find a python object in the interpeter namespace from a context (a list of names). """ - context = map(str, context) + context = list(map(str, context)) if len(context) == 0: return None, context base_symbol_string = context[0] symbol = self.interpreter.locals.get(base_symbol_string, None) if symbol is None: - symbol = __builtin__.__dict__.get(base_symbol_string, None) + symbol = six.moves.builtins.__dict__.get(base_symbol_string, None) if symbol is None: return None, context @@ -554,10 +586,6 @@ super(PyfacePythonWidget, self).keyPressEvent(event) -#------------------------------------------------------------------------------- -# '_DropEventFilter' class: -#------------------------------------------------------------------------------- - class _DropEventEmitter(QtCore.QObject): """ Handle object drops on widget. """ signal = QtCore.Signal(object) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/single_choice_dialog.py python-pyface-6.1.2/pyface/ui/qt4/single_choice_dialog.py --- python-pyface-4.5.2/pyface/ui/qt4/single_choice_dialog.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/single_choice_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,115 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2016, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# +#------------------------------------------------------------------------------ + +from pyface.qt import QtCore, QtGui + +from traits.api import Any, List, Str, provides + +from pyface.constant import CANCEL +from pyface.i_single_choice_dialog import ISingleChoiceDialog, MSingleChoiceDialog +from .dialog import Dialog, _RESULT_MAP + + +@provides(ISingleChoiceDialog) +class SingleChoiceDialog(MSingleChoiceDialog, Dialog): + """ A dialog that allows the user to chose a single item from a list. + + Note that due to limitations of the QInputDialog class, the cancel trait + is ignored, and the list of displayed strings must be unique. + """ + + #### 'ISingleChoiceDialog' interface ###################################### + + #: List of objects to choose from. + choices = List(Any) + + #: The object chosen, if any. + choice = Any + + #: An optional attribute to use for the name of each object in the dialog. + name_attribute = Str + + #: The message to display to the user. + message = Str + + def set_dialog_choice(self, choice): + if self.control is not None: + if self.name_attribute != '': + choice = getattr(choice, self.name_attribute) + self.control.setTextValue(str(choice)) + + ########################################################################### + # Protected 'IDialog' interface. + ########################################################################### + + def _create_contents(self, parent): + """ Creates the window contents. """ + # In this case, Qt does it all for us in 'QInputDialog' + pass + + def _show_modal(self): + self.control.setWindowModality(QtCore.Qt.ApplicationModal) + retval = self.control.exec_() + if self.control is None: + # dialog window closed, treat as Cancel, nullify choice + retval = CANCEL + else: + retval = _RESULT_MAP[retval] + return retval + + ########################################################################### + # 'IWindow' interface. + ########################################################################### + + def close(self): + """ Closes the window. """ + + # Get the chosen object. + if self.control is not None and self.return_code != CANCEL: + text = self.control.textValue() + choices = self._choice_strings() + if text in choices: + idx = self._choice_strings().index(text) + self.choice = self.choices[idx] + else: + self.choice = None + + # Let the window close as normal. + super(SingleChoiceDialog, self).close() + + ########################################################################### + # Protected 'IWidget' interface. + ########################################################################### + + def _create_control(self, parent): + """ Create the toolkit-specific control that represents the window. """ + dialog = QtGui.QInputDialog(parent) + + dialog.setOption(QtGui.QInputDialog.UseListViewForComboBoxItems, True) + dialog.setWindowTitle(self.title) + dialog.setLabelText(self.message) + + # initialize choices: set initial value to first choice + choices = self._choice_strings() + dialog.setComboBoxItems(choices) + dialog.setTextValue(choices[0]) + + if self.size != (-1, -1): + self.resize(*self.size) + if self.position != (-1, -1): + self.move(*self.position) + + return dialog diff -Nru python-pyface-4.5.2/pyface/ui/qt4/splash_screen.py python-pyface-6.1.2/pyface/ui/qt4/splash_screen.py --- python-pyface-4.5.2/pyface/ui/qt4/splash_screen.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/splash_screen.py 2019-05-03 08:18:50.000000000 +0000 @@ -24,7 +24,7 @@ # Local imports. from pyface.i_splash_screen import ISplashScreen, MSplashScreen from pyface.image_resource import ImageResource -from window import Window +from .window import Window @provides(ISplashScreen) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/tasks/advanced_editor_area_pane.py python-pyface-6.1.2/pyface/ui/qt4/tasks/advanced_editor_area_pane.py --- python-pyface-4.5.2/pyface/ui/qt4/tasks/advanced_editor_area_pane.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/tasks/advanced_editor_area_pane.py 2019-05-03 08:18:50.000000000 +0000 @@ -10,10 +10,10 @@ # Local imports. from pyface.tasks.i_advanced_editor_area_pane import IAdvancedEditorAreaPane from pyface.tasks.i_editor_area_pane import MEditorAreaPane -from editor_area_pane import EditorAreaDropFilter -from main_window_layout import MainWindowLayout, PaneItem -from task_pane import TaskPane -from util import set_focus +from .editor_area_pane import EditorAreaDropFilter +from .main_window_layout import MainWindowLayout, PaneItem +from .task_pane import TaskPane +from .util import set_focus ############################################################################### # 'AdvancedEditorAreaPane' class. @@ -59,7 +59,7 @@ mod = 'Ctrl+' if sys.platform == 'darwin' else 'Alt+' mapper = QtCore.QSignalMapper(self.control) mapper.mapped.connect(self._activate_tab) - for i in xrange(1, 10): + for i in range(1, 10): sequence = QtGui.QKeySequence(mod + str(i)) shortcut = QtGui.QShortcut(sequence, self.control) shortcut.activated.connect(mapper.map) @@ -70,7 +70,7 @@ """ self.control.removeEventFilter(self._filter) self._filter = None - + for editor in self.editors: editor_widget = editor.control.parent() self.control.destroy_editor_widget(editor_widget) @@ -90,7 +90,7 @@ editor_widget.raise_() editor.control.setFocus() self.active_editor = editor - + def add_editor(self, editor): """ Adds an editor to the pane. """ @@ -192,7 +192,7 @@ #### 'MainWindowLayout' interface ######################################### control = DelegatesTo('editor_area') - + #### 'TaskWindowLayout' interface ######################################### editor_area = Instance(AdvancedEditorAreaPane) @@ -217,7 +217,7 @@ if editor.control == dock_widget.widget(): return PaneItem(id=i) return None - + class EditorAreaWidget(QtGui.QMainWindow): """ An auxillary widget for implementing AdvancedEditorAreaPane. @@ -285,7 +285,7 @@ """ return [ child for child in self.children() if isinstance(child, QtGui.QDockWidget) and child.isVisible() ] - + def get_dock_widgets_for_bar(self, tab_bar): """ Get the dock widgets, in order, attached to given tab bar. @@ -304,10 +304,6 @@ def get_dock_widgets_ordered(self, visible_only=False): """ Gets all dock widgets in left-to-right, top-to-bottom order. """ - def compare(one, two): - y = cmp(one.pos().y(), two.pos().y()) - return cmp(one.pos().x(), two.pos().x()) if y == 0 else y - children = [] for child in self.children(): if (child.isWidgetType() and child.isVisible() and @@ -315,8 +311,8 @@ (isinstance(child, QtGui.QDockWidget) and (visible_only or not self.tabifiedDockWidgets(child))))): children.append(child) - children.sort(cmp=compare) - + children.sort(key=lambda _child: (_child.pos().y(), _child.pos().x())) + widgets = [] for child in children: if isinstance(child, QtGui.QTabBar): @@ -368,7 +364,7 @@ """ old_widget = self._hover_widget self._hover_widget = widget - + if old_widget: if old_widget in self._tear_widgets: if len(self._tear_widgets) == 1: @@ -414,10 +410,10 @@ elif isinstance(obj, QtGui.QRubberBand): return self._filter_rubber_band(obj, event) - + elif isinstance(obj, QtGui.QTabBar): return self._filter_tab_bar(obj, event) - + return False def _filter_dock_widget(self, widget, event): @@ -524,11 +520,11 @@ editor_widget = self.get_dock_widgets_for_bar(self.sender())[index] editor_widget.editor.close() - + class EditorWidget(QtGui.QDockWidget): """ An auxillary widget for implementing AdvancedEditorAreaPane. """ - + def __init__(self, editor, parent=None): super(EditorWidget, self).__init__(parent) self.editor = editor @@ -552,7 +548,7 @@ def update_title(self): title = self.editor.editor_area._get_label(self.editor) self.setWindowTitle(title) - + title_bar = self.titleBarWidget() if isinstance(title_bar, EditorTitleBarWidget): title_bar.setTabText(0, title) @@ -576,12 +572,12 @@ self.setTitleBarWidget(EditorTitleBarWidget(self)) elif current is None or isinstance(current, EditorTitleBarWidget): self.setTitleBarWidget(QtGui.QWidget()) - + class EditorTitleBarWidget(QtGui.QTabBar): """ An auxillary widget for implementing AdvancedEditorAreaPane. """ - + def __init__(self, editor_widget): super(EditorTitleBarWidget, self).__init__(editor_widget) self.addTab(editor_widget.windowTitle()) @@ -598,6 +594,6 @@ def mouseMoveEvent(self, event): event.ignore() - + def mouseReleaseEvent(self, event): event.ignore() diff -Nru python-pyface-4.5.2/pyface/ui/qt4/tasks/dock_pane.py python-pyface-6.1.2/pyface/ui/qt4/tasks/dock_pane.py --- python-pyface-4.5.2/pyface/ui/qt4/tasks/dock_pane.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/tasks/dock_pane.py 2019-05-03 08:18:50.000000000 +0000 @@ -9,15 +9,15 @@ from pyface.qt import QtCore, QtGui # Local imports. -from task_pane import TaskPane -from util import set_focus +from .task_pane import TaskPane +from .util import set_focus # Constants. AREA_MAP = { 'left' : QtCore.Qt.LeftDockWidgetArea, 'right' : QtCore.Qt.RightDockWidgetArea, 'top' : QtCore.Qt.TopDockWidgetArea, 'bottom' : QtCore.Qt.BottomDockWidgetArea } -INVERSE_AREA_MAP = dict((int(v), k) for k, v in AREA_MAP.iteritems()) +INVERSE_AREA_MAP = dict((int(v), k) for k, v in AREA_MAP.items()) @provides(IDockPane) @@ -122,10 +122,10 @@ if main_window and self.task == self.task.window.active_task: # Qt will automatically remove the dock widget from its previous # area, if it had one. - main_window.addDockWidget(AREA_MAP[self.dock_area], + main_window.addDockWidget(AREA_MAP[self.dock_area], self.control) - @on_trait_change('closable', 'floatable', 'movable') + @on_trait_change('closable,floatable,movable') def _set_dock_features(self): if self.control is not None: features = QtGui.QDockWidget.NoDockWidgetFeatures diff -Nru python-pyface-4.5.2/pyface/ui/qt4/tasks/editor_area_pane.py python-pyface-6.1.2/pyface/ui/qt4/tasks/editor_area_pane.py --- python-pyface-4.5.2/pyface/ui/qt4/tasks/editor_area_pane.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/tasks/editor_area_pane.py 2019-05-03 08:18:50.000000000 +0000 @@ -10,8 +10,8 @@ from pyface.qt import QtCore, QtGui # Local imports. -from task_pane import TaskPane -from util import set_focus +from .task_pane import TaskPane +from .util import set_focus ############################################################################### # 'EditorAreaPane' class. @@ -59,7 +59,7 @@ mod = 'Ctrl+' if sys.platform == 'darwin' else 'Alt+' mapper = QtCore.QSignalMapper(self.control) mapper.mapped.connect(self.control.setCurrentIndex) - for i in xrange(1, 10): + for i in range(1, 10): sequence = QtGui.QKeySequence(mod + str(i)) shortcut = QtGui.QShortcut(sequence, self.control) shortcut.activated.connect(mapper.map) @@ -70,7 +70,7 @@ """ self.control.removeEventFilter(self._filter) self._filter = None - + for editor in self.editors: self.remove_editor(editor) @@ -84,7 +84,7 @@ """ Activates the specified editor in the pane. """ self.control.setCurrentWidget(editor.control) - + def add_editor(self, editor): """ Adds an editor to the pane. """ @@ -159,7 +159,7 @@ control = self.control.widget(index) editor = self._get_editor_with_control(control) editor.close() - + def _update_active_editor(self): index = self.control.currentIndex() if index == -1: diff -Nru python-pyface-4.5.2/pyface/ui/qt4/tasks/main_window_layout.py python-pyface-6.1.2/pyface/ui/qt4/tasks/main_window_layout.py --- python-pyface-4.5.2/pyface/ui/qt4/tasks/main_window_layout.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/tasks/main_window_layout.py 2019-05-03 08:18:50.000000000 +0000 @@ -9,9 +9,9 @@ from traits.api import Any, HasTraits # Local imports. -from dock_pane import AREA_MAP from pyface.tasks.task_layout import LayoutContainer, PaneItem, Tabbed, \ Splitter, HSplitter, VSplitter +from .dock_pane import AREA_MAP # Contants. ORIENTATION_MAP = { 'horizontal' : QtCore.Qt.Horizontal, @@ -37,7 +37,7 @@ def get_layout(self, layout, include_sizes=True): """ Get the layout by adding sublayouts to the specified DockLayout. """ - for name, q_dock_area in AREA_MAP.iteritems(): + for name, q_dock_area in AREA_MAP.items(): sublayout = self.get_layout_for_area(q_dock_area, include_sizes) setattr(layout, name, sublayout) @@ -119,7 +119,7 @@ # Perform the layout. This will assign fixed sizes to the dock widgets # to enforce size constraints specified in the PaneItems. - for name, q_dock_area in AREA_MAP.iteritems(): + for name, q_dock_area in AREA_MAP.items(): sublayout = getattr(layout, name) if sublayout: self.set_layout_for_area(sublayout, q_dock_area, diff -Nru python-pyface-4.5.2/pyface/ui/qt4/tasks/split_editor_area_pane.py python-pyface-6.1.2/pyface/ui/qt4/tasks/split_editor_area_pane.py --- python-pyface-4.5.2/pyface/ui/qt4/tasks/split_editor_area_pane.py 2015-03-16 14:33:12.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/tasks/split_editor_area_pane.py 2019-07-20 11:46:59.000000000 +0000 @@ -6,17 +6,16 @@ MEditorAreaPane from traits.api import Bool, cached_property, Callable, Dict, Instance, List, \ on_trait_change, Property, provides, Str -from pyface.qt import QtCore, QtGui -from pyface.action.api import Action, Group +from pyface.qt import is_qt4, QtCore, QtGui +from pyface.action.api import Action, Group, MenuManager from pyface.tasks.task_layout import PaneItem, Tabbed, Splitter -from traitsui.api import Menu -from traitsui.mimedata import PyMimeData +from pyface.mimedata import PyMimeData from pyface.api import FileDialog from pyface.constant import OK from pyface.drop_handler import IDropHandler, BaseDropHandler, FileDropHandler # Local imports. -from task_pane import TaskPane +from .task_pane import TaskPane ############################################################################### # 'SplitEditorAreaPane' class. @@ -113,8 +112,9 @@ def activate_editor(self, editor): """ Activates the specified editor in the pane. """ - self.active_tabwidget = editor.control.parent().parent() - self.active_tabwidget.setCurrentWidget(editor.control) + active_tabwidget = editor.control.parent().parent() + active_tabwidget.setCurrentWidget(editor.control) + self.active_tabwidget = active_tabwidget editor_widget = editor.control.parent() editor_widget.setVisible(True) editor_widget.raise_() @@ -178,7 +178,7 @@ pos : position (in global coordinates) where the context menu was requested """ - menu = Menu() + menu = MenuManager() splitter = None splitter = None @@ -209,12 +209,12 @@ # add collapse action (only show for collapsible splitters) if splitter.is_collapsible(): if splitter is splitter.parent().leftchild: - if splitter.parent().orientation() is QtCore.Qt.Horizontal: + if splitter.parent().orientation() == QtCore.Qt.Horizontal: text = 'Merge with right pane' else: text = 'Merge with bottom pane' else: - if splitter.parent().orientation() is QtCore.Qt.Horizontal: + if splitter.parent().orientation() == QtCore.Qt.Horizontal: text = 'Merge with left pane' else: text = 'Merge with top pane' @@ -269,7 +269,7 @@ mod = 'Ctrl+' if sys.platform == 'darwin' else 'Alt+' mapper = QtCore.QSignalMapper(self.control) mapper.mapped.connect(self._activate_tab) - for i in xrange(1, 10): + for i in range(1, 10): sequence = QtGui.QKeySequence(mod + str(i)) shortcut = QtGui.QShortcut(sequence, self.control) shortcut.activated.connect(mapper.map) @@ -330,7 +330,7 @@ """Set the active tabwidget after an application-level change in focus. """ - if new: + if new is not None: if isinstance(new, DraggableTabWidget): if new.editor_area == self: self.active_tabwidget = new @@ -344,14 +344,24 @@ for editor in self.editors: control = editor.control if control is not None and control.isAncestorOf(new): - self.active_tabwidget = \ + active_tabwidget = \ self._find_ancestor_draggable_tab_widget(control) - self.active_tabwidget.setCurrentWidget(control) - # Set active_editor at the end so that the notification - # occurs when everything is ready. - self.active_editor = editor + active_tabwidget.setCurrentWidget(control) + self.active_tabwidget = active_tabwidget break + def _active_tabwidget_changed(self, new): + """Set the active editor whenever the active tabwidget updates. + """ + + if new is None or new.parent().is_empty(): + active_editor = None + else: + active_editor = self._get_editor(new.currentWidget()) + + self.active_editor = active_editor + + ############################################################################### # Auxiliary classes. ############################################################################### @@ -804,10 +814,15 @@ def contextMenuEvent(self, event): """ To show collapse context menu even on empty tabwidgets """ - global_pos = self.mapToGlobal(event.pos()) - menu = self.editor_area.get_context_menu(pos=global_pos) - qmenu = menu.create_menu(self) - qmenu.exec_(global_pos) + local_pos = event.pos() + if (self.empty_widget is not None or + self.tabBar().rect().contains(local_pos)): + # Only display if we are in the tab bar region or the whole area if + # we are displaying the default empty widget. + global_pos = self.mapToGlobal(local_pos) + menu = self.editor_area.get_context_menu(pos=global_pos) + qmenu = menu.create_menu(self) + qmenu.exec_(global_pos) def dragEnterEvent(self, event): """ Re-implemented to highlight the tabwidget on drag enter @@ -919,16 +934,23 @@ painter.fillRect(result_pixmap.rect(), QtCore.Qt.lightGray) painter.setCompositionMode(QtGui.QPainter.CompositionMode_SourceOver) - optTabBase = QtGui.QStyleOptionTabBarBaseV2() + optTabBase = QtGui.QStyleOptionTabBarBase() optTabBase.initFrom(tabBar) painter.drawPrimitive(QtGui.QStyle.PE_FrameTabBarBase, optTabBase) # region of active tab - pixmap1 = QtGui.QPixmap.grabWidget(tabBar, tab_rect) - painter.drawPixmap(0,0,pixmap1) #tab_rect.topLeft(), pixmap1) + if is_qt4: # grab wasn't introduced until Qt5 + pixmap1 = QtGui.QPixmap.grabWidget(tabBar, tab_rect) + else: + pixmap1 = tabBar.grab(tab_rect) + + painter.drawPixmap(0, 0, pixmap1) # region of the page widget - pixmap2 = QtGui.QPixmap.grabWidget(self.widget) + if is_qt4: + pixmap2 = QtGui.QPixmap.grabWidget(self.widget) + else: + pixmap2 = self.widget.grab() painter.drawPixmap(0, tab_rect.height(), size.width(), size.height(), pixmap2) # finish painting diff -Nru python-pyface-4.5.2/pyface/ui/qt4/tasks/task_pane.py python-pyface-6.1.2/pyface/ui/qt4/tasks/task_pane.py --- python-pyface-4.5.2/pyface/ui/qt4/tasks/task_pane.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/tasks/task_pane.py 2019-05-03 08:18:50.000000000 +0000 @@ -6,7 +6,7 @@ from pyface.qt import QtGui # Local imports. -from util import set_focus +from .util import set_focus @provides(ITaskPane) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/tasks/task_window_backend.py python-pyface-6.1.2/pyface/ui/qt4/tasks/task_window_backend.py --- python-pyface-4.5.2/pyface/ui/qt4/tasks/task_window_backend.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/tasks/task_window_backend.py 2019-05-03 08:18:50.000000000 +0000 @@ -5,16 +5,18 @@ from traits.api import Instance, List # Local imports. -from dock_pane import AREA_MAP, INVERSE_AREA_MAP -from main_window_layout import MainWindowLayout from pyface.tasks.i_task_window_backend import MTaskWindowBackend from pyface.tasks.task_layout import PaneItem, TaskLayout +from .dock_pane import AREA_MAP, INVERSE_AREA_MAP +from .main_window_layout import MainWindowLayout # Constants. -CORNER_MAP = { 'top_left' : QtCore.Qt.TopLeftCorner, - 'top_right' : QtCore.Qt.TopRightCorner, - 'bottom_left' : QtCore.Qt.BottomLeftCorner, - 'bottom_right' : QtCore.Qt.BottomRightCorner } +CORNER_MAP = { + 'top_left': QtCore.Qt.TopLeftCorner, + 'top_right': QtCore.Qt.TopRightCorner, + 'bottom_left': QtCore.Qt.BottomLeftCorner, + 'bottom_right': QtCore.Qt.BottomRightCorner +} class TaskWindowBackend(MTaskWindowBackend): @@ -34,15 +36,15 @@ def create_contents(self, parent): """ Create and return the TaskWindow's contents. """ - QtGui.QApplication.instance().focusChanged.connect( - self._focus_changed_signal) + app = QtGui.QApplication.instance() + app.focusChanged.connect(self._focus_changed_signal) return QtGui.QStackedWidget(parent) def destroy(self): """ Destroy the backend. """ - QtGui.QApplication.instance().focusChanged.disconnect( - self._focus_changed_signal) + app = QtGui.QApplication.instance() + app.focusChanged.disconnect(self._focus_changed_signal) # signal to layout we don't need it any more self._main_window_layout.control = None @@ -70,12 +72,6 @@ # Show the dock panes. self._layout_state(state) - # OSX-specific: if there is only a single tool bar, it doesn't matter if - # the user can drag it around or not. Therefore, we can combine it with - # the title bar, which is idiomatic on the Mac. - self.control.setUnifiedTitleAndToolBarOnMac( - len(state.tool_bar_managers) <= 1) - #### Methods for saving and restoring the layout ########################## def get_layout(self): @@ -87,7 +83,7 @@ self._main_window_layout.get_layout(layout) # Extract the window's corner configuration. - for name, corner in CORNER_MAP.iteritems(): + for name, corner in CORNER_MAP.items(): area = INVERSE_AREA_MAP[int(self.control.corner(corner))] setattr(layout, name + '_corner', area) @@ -109,7 +105,7 @@ TaskLayout. """ # Assign the window's corners to the appropriate dock areas. - for name, corner in CORNER_MAP.iteritems(): + for name, corner in CORNER_MAP.items(): area = getattr(state.layout, name + '_corner') self.control.setCorner(corner, AREA_MAP[area]) @@ -120,8 +116,8 @@ # Add all panes not assigned an area by the TaskLayout. for dock_pane in state.dock_panes: if dock_pane.control not in self._main_window_layout.consumed: - self.control.addDockWidget(AREA_MAP[dock_pane.dock_area], - dock_pane.control) + dock_area = AREA_MAP[dock_pane.dock_area] + self.control.addDockWidget(dock_area, dock_pane.control) # By default, these panes are not visible. However, if a pane # has been explicitly set as visible, honor that setting. if dock_pane.visible: @@ -136,7 +132,7 @@ def _focus_changed_signal(self, old, new): if self.window.active_task: - panes = [ self.window.central_pane ] + self.window.dock_panes + panes = [self.window.central_pane] + self.window.dock_panes for pane in panes: if new and pane.control.isAncestorOf(new): pane.has_focus = True diff -Nru python-pyface-4.5.2/pyface/ui/qt4/tasks/tests/test_split_editor_area_pane.py python-pyface-6.1.2/pyface/ui/qt4/tasks/tests/test_split_editor_area_pane.py --- python-pyface-4.5.2/pyface/ui/qt4/tasks/tests/test_split_editor_area_pane.py 2015-03-16 14:33:12.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/tasks/tests/test_split_editor_area_pane.py 2019-07-20 11:46:59.000000000 +0000 @@ -5,8 +5,6 @@ import unittest from traits.api import HasTraits, Instance -from traitsui.api import Group, UItem, View -from traitsui.api import Tabbed as TabbedGroup from pyface.qt import QtGui, QtCore from pyface.tasks.split_editor_area_pane import EditorAreaWidget, \ @@ -17,34 +15,23 @@ from pyface.ui.qt4.util.testing import event_loop -class ViewWithTabs(HasTraits): - """ A view with tabs used to confuse the SplitEditorAreaPane. """ - traits_view = View( - TabbedGroup( - Group(UItem(label='tab 1')), - Group(UItem(label='tab 2')), - ) - ) - - class ViewWithTabsEditor(Editor): - """ Test editor, displaying a TraitsUI view with tabs. """ + """ Test editor, displaying a labels in tabs. """ name = 'Test Editor' def create(self, parent): """ Create and set the toolkit-specific contents of the editor. """ - view = ViewWithTabs() - self.ui = view.edit_traits(kind='subpanel', parent=parent) - self.control = self.ui.control + control = QtGui.QTabWidget() + control.addTab(QtGui.QLabel('tab 1'), 'group 1') + control.addTab(QtGui.QLabel('tab 2'), 'group 2') + self.control = control def destroy(self): """ Destroy the toolkit-specific control that represents the editor. """ self.control = None - self.ui.dispose() - self.ui = None class SplitEditorAreaPaneTestTask(Task): @@ -321,6 +308,80 @@ self.assertEquals(right_bottom.items[0].id, 1) self.assertEquals(right_bottom.items[1].id, 2) + def test_context_menu_merge_text_left_right_split(self): + # Regression test for enthought/pyface#422 + window = TaskWindow() + + task = SplitEditorAreaPaneTestTask() + editor_area = task.editor_area + window.add_task(task) + + with event_loop(): + window.open() + + editor_area_widget = editor_area.control + with event_loop(): + editor_area_widget.split(orientation=QtCore.Qt.Horizontal) + + # Get the tabs. + left_tab, right_tab = editor_area_widget.tabwidgets() + + # Check left context menu merge text. + left_tab_center = left_tab.mapToGlobal(left_tab.rect().center()) + left_context_menu = editor_area.get_context_menu(left_tab_center) + self.assertEqual( + left_context_menu.find_item("merge").action.name, + "Merge with right pane", + ) + + # And the right context menu merge text. + right_tab_center = right_tab.mapToGlobal(right_tab.rect().center()) + right_context_menu = editor_area.get_context_menu(right_tab_center) + self.assertEqual( + right_context_menu.find_item("merge").action.name, + "Merge with left pane", + ) + + with event_loop(): + window.close() + + def test_context_menu_merge_text_top_bottom_split(self): + # Regression test for enthought/pyface#422 + window = TaskWindow() + + task = SplitEditorAreaPaneTestTask() + editor_area = task.editor_area + window.add_task(task) + + with event_loop(): + window.open() + + editor_area_widget = editor_area.control + with event_loop(): + editor_area_widget.split(orientation=QtCore.Qt.Vertical) + + # Get the tabs. + top_tab, bottom_tab = editor_area_widget.tabwidgets() + + # Check top context menu merge text. + top_tab_center = top_tab.mapToGlobal(top_tab.rect().center()) + top_context_menu = editor_area.get_context_menu(top_tab_center) + self.assertEqual( + top_context_menu.find_item("merge").action.name, + "Merge with bottom pane", + ) + + # And the bottom context menu merge text. + bottom_tab_center = bottom_tab.mapToGlobal(bottom_tab.rect().center()) + bottom_context_menu = editor_area.get_context_menu(bottom_tab_center) + self.assertEqual( + bottom_context_menu.find_item("merge").action.name, + "Merge with top pane", + ) + + with event_loop(): + window.close() + def test_active_tabwidget_after_editor_containing_tabs_gets_focus(self): # Regression test: if an editor contains tabs, a change in focus # sets the editor area pane `active_tabwidget` to one of those tabs, @@ -354,6 +415,44 @@ with event_loop(): window.close() + + def test_active_editor_after_focus_change(self): + window = TaskWindow(size=(800, 600)) + + task = SplitEditorAreaPaneTestTask() + editor_area = task.editor_area + window.add_task(task) + + # Show the window. + with event_loop(): + window.open() + + with event_loop(): + app = get_app_qt4() + app.setActiveWindow(window.control) + + # Add and activate an editor which contains tabs. + left_editor = ViewWithTabsEditor() + right_editor = ViewWithTabsEditor() + + with event_loop(): + editor_area.add_editor(left_editor) + with event_loop(): + editor_area.control.split(orientation=QtCore.Qt.Horizontal) + with event_loop(): + editor_area.add_editor(right_editor) + + editor_area.activate_editor(right_editor) + self.assertEqual(editor_area.active_editor, right_editor) + + with event_loop(): + left_editor.control.setFocus() + + self.assertIsNotNone(editor_area.active_editor) + self.assertEqual(editor_area.active_editor, left_editor) + + with event_loop(): + window.close() if __name__ == '__main__': unittest.main() diff -Nru python-pyface-4.5.2/pyface/ui/qt4/tests/test_gui.py python-pyface-6.1.2/pyface/ui/qt4/tests/test_gui.py --- python-pyface-4.5.2/pyface/ui/qt4/tests/test_gui.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/tests/test_gui.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,76 @@ +""" +Qt-specific tests for the Qt GUI implementation. +""" +from __future__ import absolute_import + +import unittest + +from traits.api import Event, HasStrictTraits, Instance + +from pyface.api import GUI +from pyface.i_gui import IGUI +from pyface.qt import QtCore +from pyface.util.guisupport import get_app_qt4, is_event_loop_running_qt4 + + +class SimpleApplication(HasStrictTraits): + """ + Simple application that attempts to set a trait at start time, + and immediately exits in response to that trait. + """ + # The GUI instance underlying this app. + gui = Instance(IGUI) + + # Event fired after the event loop starts. + application_running = Event + + def __init__(self): + super(HasStrictTraits, self).__init__() + self.gui = GUI() + + def start(self): + """ + Start the application. + """ + # This shouldn't be executed until after the event loop is running. + self.gui.set_trait_later(self, 'application_running', True) + self.gui.start_event_loop() + + def stop(self): + self.gui.stop_event_loop() + + +class TestGui(unittest.TestCase): + def test_set_trait_later_runs_later(self): + # Regression test for enthought/pyface#272. + application = SimpleApplication() + + application_running = [] + + def exit_app(): + # Record whether the event loop is running or not, then exit. + application_running.append( + is_event_loop_running_qt4() + ) + application.stop() + + application.on_trait_change(exit_app, 'application_running') + + # Make sure that the application stops after 10 seconds, no matter + # what. + qt_app = get_app_qt4() + timeout_timer = QtCore.QTimer() + timeout_timer.setSingleShot(True) + timeout_timer.setInterval(10000) # 10 second timeout + timeout_timer.timeout.connect(qt_app.quit) + timeout_timer.start() + try: + application.start() + finally: + timeout_timer.stop() + # Attempt to leave the QApplication in a reasonably clean + # state in case of failure. + qt_app.sendPostedEvents() + qt_app.flush() + + self.assertTrue(application_running[0]) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/tests/test_mimedata.py python-pyface-6.1.2/pyface/ui/qt4/tests/test_mimedata.py --- python-pyface-4.5.2/pyface/ui/qt4/tests/test_mimedata.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/tests/test_mimedata.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,157 @@ +# +# (C) Copyright 2013 Enthought, Inc., Austin, TX +# All rights reserved. +# +# This file is open source software distributed according to the terms in +# LICENSE.txt +# + +import unittest +from six.moves.cPickle import dumps + +from pyface.qt import QtCore +from ..mimedata import PyMimeData, str2bytes + + +class PMDSubclass(PyMimeData): + pass + + +class PyMimeDataTestCase(unittest.TestCase): + + # Basic functionality tests + + def test_pickle(self): + md = PyMimeData(data=0) + self.assertEqual(md._local_instance, 0) + self.assertTrue(md.hasFormat(PyMimeData.MIME_TYPE)) + self.assertFalse(md.hasFormat(PyMimeData.NOPICKLE_MIME_TYPE)) + self.assertEqual(md.data(PyMimeData.MIME_TYPE).data(), + dumps(int)+dumps(0)) + + def test_nopickle(self): + md = PyMimeData(data=0, pickle=False) + self.assertEqual(md._local_instance, 0) + self.assertTrue(md.hasFormat(PyMimeData.NOPICKLE_MIME_TYPE)) + self.assertFalse(md.hasFormat(PyMimeData.MIME_TYPE)) + self.assertEqual( + md.data(PyMimeData.NOPICKLE_MIME_TYPE).data(), + str2bytes(str(id(0))) + ) + + def test_cant_pickle(self): + unpicklable = lambda: None + md = PyMimeData(data=unpicklable) + self.assertEqual(md._local_instance, unpicklable) + self.assertTrue(md.hasFormat(PyMimeData.NOPICKLE_MIME_TYPE)) + self.assertFalse(md.hasFormat(PyMimeData.MIME_TYPE)) + self.assertEqual( + md.data(PyMimeData.NOPICKLE_MIME_TYPE).data(), + str2bytes(str(id(unpicklable))) + ) + + def test_coerce_pymimedata(self): + md = PyMimeData(data=0) + md2 = PyMimeData.coerce(md) + self.assertEqual(md, md2) + + def test_coerce_subclass(self): + md = PMDSubclass(data=0) + md2 = PyMimeData.coerce(md) + self.assertEqual(md, md2) + + def test_coerce_QMimeData(self): + md = QtCore.QMimeData() + md.setText("test") + md2 = PyMimeData.coerce(md) + self.assertTrue(md2.hasText()) + self.assertEqual(md2.text(), "test") + + def test_coerce_object(self): + md = PyMimeData.coerce(0) + self.assertEqual(md._local_instance, 0) + self.assertTrue(md.hasFormat(PyMimeData.MIME_TYPE)) + self.assertFalse(md.hasFormat(PyMimeData.NOPICKLE_MIME_TYPE)) + self.assertEqual(md.data(PyMimeData.MIME_TYPE).data(), dumps(int)+dumps(0)) + + def test_coerce_unpicklable(self): + unpicklable = lambda: None + md = PyMimeData.coerce(unpicklable) + self.assertEqual(md._local_instance, unpicklable) + self.assertFalse(md.hasFormat(PyMimeData.MIME_TYPE)) + self.assertTrue(md.hasFormat(PyMimeData.NOPICKLE_MIME_TYPE)) + + def test_coerce_list(self): + md = PyMimeData.coerce([0]) + self.assertEqual(md._local_instance, [0]) + self.assertTrue(md.hasFormat(PyMimeData.MIME_TYPE)) + self.assertFalse(md.hasFormat(PyMimeData.NOPICKLE_MIME_TYPE)) + self.assertEqual(md.data(PyMimeData.MIME_TYPE).data(), dumps(list)+dumps([0])) + + def test_coerce_list_pymimedata(self): + md = PyMimeData(data=0) + md2 = PyMimeData.coerce([md]) + self.assertEqual(md2._local_instance, [0]) + self.assertTrue(md2.hasFormat(PyMimeData.MIME_TYPE)) + self.assertFalse(md2.hasFormat(PyMimeData.NOPICKLE_MIME_TYPE)) + self.assertEqual(md2.data(PyMimeData.MIME_TYPE).data(), + dumps(list)+dumps([0])) + + def test_coerce_list_pymimedata_nopickle(self): + md = PyMimeData(data=0, pickle=False) + md2 = PyMimeData.coerce([md]) + self.assertEqual(md2._local_instance, [0]) + self.assertFalse(md2.hasFormat(PyMimeData.MIME_TYPE)) + self.assertTrue(md2.hasFormat(PyMimeData.NOPICKLE_MIME_TYPE)) + + def test_coerce_list_pymimedata_mixed(self): + md1 = PyMimeData(data=0, pickle=False) + md2 = PyMimeData(data=0) + md = PyMimeData.coerce([md1, md2]) + self.assertEqual(md._local_instance, [0, 0]) + self.assertFalse(md.hasFormat(PyMimeData.MIME_TYPE)) + self.assertTrue(md.hasFormat(PyMimeData.NOPICKLE_MIME_TYPE)) + + def test_subclass_coerce_pymimedata(self): + md = PyMimeData(data=0) + md2 = PMDSubclass.coerce(md) + self.assertTrue(isinstance(md2, PMDSubclass)) + self.assertTrue(md2.hasFormat(PyMimeData.MIME_TYPE)) + self.assertFalse(md2.hasFormat(PyMimeData.NOPICKLE_MIME_TYPE)) + self.assertEqual(md2.data(PyMimeData.MIME_TYPE).data(), dumps(int)+dumps(0)) + + def test_instance(self): + md = PyMimeData(data=0) + self.assertEqual(md.instance(), 0) + + def test_instance_unpickled(self): + md = PyMimeData(data=0) + # remove local instance to simulate cross-process + md._local_instance = None + self.assertEqual(md.instance(), 0) + + def test_instance_nopickle(self): + md = PyMimeData(data=0, pickle=False) + # remove local instance to simulate cross-process + md._local_instance = None + self.assertEqual(md.instance(), None) + + def test_instance_type(self): + md = PyMimeData(data=0) + self.assertEqual(md.instanceType(), int) + + def test_instance_type_unpickled(self): + md = PyMimeData(data=0) + # remove local instance to simulate cross-process + md._local_instance = None + self.assertEqual(md.instanceType(), int) + + def test_instance_type_nopickle(self): + md = PyMimeData(data=0, pickle=False) + # remove local instance to simulate cross-process + md._local_instance = None + self.assertEqual(md.instanceType(), None) + + +if __name__ == '__main__': + unittest.main() diff -Nru python-pyface-4.5.2/pyface/ui/qt4/tests/test_progress_dialog.py python-pyface-6.1.2/pyface/ui/qt4/tests/test_progress_dialog.py --- python-pyface-4.5.2/pyface/ui/qt4/tests/test_progress_dialog.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/tests/test_progress_dialog.py 2019-06-14 12:22:56.000000000 +0000 @@ -0,0 +1,118 @@ +from __future__ import absolute_import + +import unittest + +from ..progress_dialog import ProgressDialog +from ..util.gui_test_assistant import GuiTestAssistant + + +class TestProgressDialog(unittest.TestCase, GuiTestAssistant): + + def setUp(self): + GuiTestAssistant.setUp(self) + self.dialog = ProgressDialog() + + def tearDown(self): + if self.dialog.control is not None: + with self.delete_widget(self.dialog.control): + self.dialog.destroy() + GuiTestAssistant.tearDown(self) + + def test_create(self): + # test that creation and destruction works as expected + self.dialog._create() + self.gui.process_events() + self.assertIsNotNone(self.dialog.control) + self.assertIsNotNone(self.dialog.progress_bar) + self.assertIsNotNone(self.dialog._message_control) + self.assertIsNone(self.dialog._elapsed_control) + self.assertIsNone(self.dialog._estimated_control) + self.assertIsNone(self.dialog._remaining_control) + self.dialog.destroy() + self.gui.process_events() + + def test_show_time(self): + # test that creation works with show_time + self.dialog.show_time = True + self.dialog._create() + self.gui.process_events() + self.assertIsNotNone(self.dialog._elapsed_control) + self.assertIsNotNone(self.dialog._estimated_control) + self.assertIsNotNone(self.dialog._remaining_control) + self.dialog.destroy() + self.gui.process_events() + + def test_show_percent(self): + # test that creation works with show_percent + self.dialog.show_percent = True + self.dialog._create() + self.gui.process_events() + self.assertEqual(self.dialog.progress_bar.format(), "%p%") + self.dialog.destroy() + self.gui.process_events() + + def test_update(self): + self.dialog.min = 0 + self.dialog.max = 10 + self.dialog.open() + for i in range(11): + result = self.dialog.update(i) + self.gui.process_events() + self.assertEqual(result, (True, False)) + if i < 10: + self.assertEqual(self.dialog.progress_bar.value(), i) + self.assertIsNone(self.dialog.control) + self.gui.process_events() + + def test_update_no_control(self): + # note: inconsistent implementation with Wx + self.dialog.min = 0 + self.dialog.max = 10 + result = self.dialog.update(1) + self.assertEqual(result, (None, None)) + self.gui.process_events() + + def test_change_message(self): + self.dialog.min = 0 + self.dialog.max = 10 + self.dialog.open() + for i in range(11): + self.dialog.change_message('Updating {}'.format(i)) + result = self.dialog.update(i) + self.gui.process_events() + self.assertEqual(result, (True, False)) + self.assertEqual(self.dialog.message, 'Updating {}'.format(i)) + self.assertEqual(self.dialog._message_control.text(), + 'Updating {}'.format(i)) + self.assertIsNone(self.dialog.control) + self.gui.process_events() + + def test_change_message_trait(self): + self.dialog.min = 0 + self.dialog.max = 10 + self.dialog.open() + for i in range(11): + self.dialog.message = 'Updating {}'.format(i) + result = self.dialog.update(i) + self.gui.process_events() + self.assertEqual(result, (True, False)) + self.assertEqual(self.dialog.message, 'Updating {}'.format(i)) + self.assertEqual(self.dialog._message_control.text(), + 'Updating {}'.format(i)) + self.assertIsNone(self.dialog.control) + self.gui.process_events() + + def test_update_show_time(self): + self.dialog.min = 0 + self.dialog.max = 10 + self.dialog.show_time = True + self.dialog.open() + for i in range(11): + result = self.dialog.update(i) + self.gui.process_events() + self.assertEqual(result, (True, False)) + self.assertNotEqual(self.dialog._elapsed_control.text(), "") + self.assertNotEqual(self.dialog._estimated_control.text(), "") + self.assertNotEqual(self.dialog._remaining_control.text(), "") + self.assertIsNone(self.dialog.control) + self.gui.process_events() diff -Nru python-pyface-4.5.2/pyface/ui/qt4/tests/test_qt_imports.py python-pyface-6.1.2/pyface/ui/qt4/tests/test_qt_imports.py --- python-pyface-4.5.2/pyface/ui/qt4/tests/test_qt_imports.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/tests/test_qt_imports.py 2019-06-18 10:52:41.000000000 +0000 @@ -0,0 +1,15 @@ +import unittest + + +class TestPyfaceQtImports(unittest.TestCase): + + def test_imports(self): + # check that all Qt API imports work + import pyface.qt.QtCore + import pyface.qt.QtGui + import pyface.qt.QtNetwork + import pyface.qt.QtOpenGL + import pyface.qt.QtScript + import pyface.qt.QtSvg + import pyface.qt.QtTest + import pyface.qt.QtWebKit \ No newline at end of file diff -Nru python-pyface-4.5.2/pyface/ui/qt4/timer/do_later.py python-pyface-6.1.2/pyface/ui/qt4/timer/do_later.py --- python-pyface-4.5.2/pyface/ui/qt4/timer/do_later.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/timer/do_later.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,56 +1,16 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2007, Riverbank Computing Limited -# All rights reserved. +# Copyright (c) 2018, Enthought, Inc. +# All rights reserved. # -# This software is provided without warranty under the terms of the BSD license. -# However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply - +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt # -# Author: Riverbank Computing Limited -# Description: -#------------------------------------------------------------------------------ - - -# Major package imports. -from pyface.qt import QtCore - - -class DoLaterTimer(QtCore.QTimer): - - # List of currently active timers: - active_timers = [] - - #--------------------------------------------------------------------------- - # Initializes the object: - #--------------------------------------------------------------------------- - - def __init__(self, interval, callable, args, kw_args): - QtCore.QTimer.__init__(self) - - global active_timers - for timer in self.active_timers: - if ((timer.callable == callable) and - (timer.args == args) and - (timer.kw_args == kw_args)): - timer.start(interval) - return - - self.active_timers.append(self) - self.callable = callable - self.args = args - self.kw_args = kw_args - - self.connect(self, QtCore.SIGNAL('timeout()'), self.Notify) - - self.setSingleShot(True) - self.start(interval) - - #--------------------------------------------------------------------------- - # Handles the timer pop event: - #--------------------------------------------------------------------------- +# Thanks for using Enthought open source! +""" +DoLaterTimer class - def Notify(self): - global active_timers +Provided for backward compatibility. +""" - self.active_timers.remove(self) - self.callable(*self.args, **self.kw_args) +from pyface.timer.do_later import DoLaterTimer \ No newline at end of file diff -Nru python-pyface-4.5.2/pyface/ui/qt4/timer/timer.py python-pyface-6.1.2/pyface/ui/qt4/timer/timer.py --- python-pyface-4.5.2/pyface/ui/qt4/timer/timer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/timer/timer.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,77 +1,30 @@ -#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited +# Copyright (c) 2018, Enthought Inc # All rights reserved. # -# This software is provided without warranty under the terms of the BSD license. -# However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply +# This software is provided without warranty under the terms of the BSD +# license. However, when used with the GPL version of PyQt the additional +# terms described in the PyQt GPL exception also apply -# -# Author: Riverbank Computing Limited -# Description: -#------------------------------------------------------------------------------ - - -# Major package imports. -from pyface.qt import QtCore - - -class Timer(QtCore.QTimer): - """Simple subclass of QTimer that allows the user to have a function called - periodically. Some code assumes that this is a sub-class of wx.Timer, so - we add a few wrapper methods to pretend it is. - - Any exceptions raised in the callable are caught. If - `StopIteration` is raised the timer stops. If other exceptions are - encountered the timer is stopped and the exception re-raised. - """ - - def __init__(self, millisecs, callable, *args, **kw_args): - """ Initialize instance to invoke the given `callable` with given - arguments and keyword args after every `millisecs` (milliseconds). - """ - QtCore.QTimer.__init__(self) - - self.callable = callable - self.args = args - self.kw_args = kw_args - - self.connect(self, QtCore.SIGNAL('timeout()'), self.Notify) - - self._is_active = True - self.start(millisecs) - - def Notify(self): - """ Call the given callable. Exceptions raised in the callable are - caught. If `StopIteration` is raised the timer stops. If other - exceptions are encountered the timer is stopped and the exception - re-raised. Note that the name of this method is part of the API - because some code expects this to be a wx.Timer sub-class. - """ - try: - self.callable(*self.args, **self.kw_args) - except StopIteration: - self.stop() - except: - self.stop() - raise - - def Start(self, millisecs=None): - """ Emulate wx.Timer. - """ - self._is_active = True - - if millisecs is None: - self.start() - else: - self.start(millisecs) - - def Stop(self): - """ Emulate wx.Timer. - """ - self._is_active = False - self.stop() - - def IsRunning(self): - """ Emulate wx.Timer. - """ - return self._is_active +from traits.api import Instance + +from pyface.qt.QtCore import QTimer +from pyface.timer.i_timer import BaseTimer + + +class PyfaceTimer(BaseTimer): + """ Abstract base class for Qt toolkit timers. """ + + #: The QTimer for the PyfaceTimer. + _timer = Instance(QTimer, (), allow_none=False) + + def __init__(self, **traits): + traits.setdefault('_timer', QTimer()) + super(PyfaceTimer, self).__init__(**traits) + self._timer.timeout.connect(self.perform) + + def _start(self): + self._timer.start(int(self.interval * 1000)) + + def _stop(self): + self._timer.stop() diff -Nru python-pyface-4.5.2/pyface/ui/qt4/util/gui_test_assistant.py python-pyface-6.1.2/pyface/ui/qt4/util/gui_test_assistant.py --- python-pyface-4.5.2/pyface/ui/qt4/util/gui_test_assistant.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/util/gui_test_assistant.py 2019-07-20 10:50:48.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2013-2015 by Enthought, Inc., Austin, TX +# Copyright (c) 2013-2017 by Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -8,9 +8,14 @@ # Thanks for using Enthought open source! import contextlib +import gc import threading -import mock +import six +if six.PY2: + import mock +else: + import unittest.mock as mock from pyface.qt.QtGui import QApplication from pyface.ui.qt4.gui import GUI @@ -36,9 +41,14 @@ qt_app=self.qt_app, gui=self.gui ) - self.traitsui_raise_patch = mock.patch( - 'traitsui.qt4.ui_base._StickyDialog.raise_') - self.traitsui_raise_patch.start() + try: + import traitsui.api + except ImportError: + self.traitsui_raise_patch = None + else: + self.traitsui_raise_patch = mock.patch( + 'traitsui.qt4.ui_base._StickyDialog.raise_') + self.traitsui_raise_patch.start() def new_activate(self): self.control.activateWindow() @@ -49,10 +59,29 @@ self.pyface_raise_patch.start() def tearDown(self): + # Process any tasks that a misbehaving test might have left on the + # queue. with self.event_loop_with_timeout(repeat=5): - self.gui.invoke_later(self.qt_app.closeAllWindows) - self.traitsui_raise_patch.stop() + pass + + # Some top-level widgets may only be present due to cyclic garbage not + # having been collected; force a garbage collection before we decide to + # close windows. This may need several rounds. + for _ in range(10): + if not gc.collect(): + break + + if len(self.qt_app.topLevelWidgets()) > 0: + with self.event_loop_with_timeout(repeat=5): + self.gui.invoke_later(self.qt_app.closeAllWindows) + + self.qt_app.flush() self.pyface_raise_patch.stop() + if self.traitsui_raise_patch is not None: + self.traitsui_raise_patch.stop() + + del self.pyface_raise_patch + del self.traitsui_raise_patch del self.event_loop_helper del self.gui del self.qt_app @@ -130,7 +159,7 @@ obj : HasTraits The HasTraits instance whose trait will change. trait : str - The extended trait name of trait changes to listen too. + The extended trait name of trait changes to listen to. condition : callable A callable to determine if the stop criteria have been met. This should accept no arguments. @@ -182,23 +211,30 @@ traits = set(traits) recorded_changes = set() + # Correctly handle the corner case where there are no traits. + if not traits: + condition.set() + def set_event(trait): recorded_changes.add(trait) if recorded_changes == traits: condition.set() - handlers = {} - for trait in traits: - handlers[trait] = lambda: set_event(trait) + def make_handler(trait): + def handler(): + set_event(trait) + return handler + + handlers = {trait: make_handler(trait) for trait in traits} - for trait, handler in handlers.iteritems(): + for trait, handler in handlers.items(): traits_object.on_trait_change(handler, trait) try: with self.event_loop_until_condition( condition=condition.is_set, timeout=timeout): yield finally: - for trait, handler in handlers.iteritems(): + for trait, handler in handlers.items(): traits_object.on_trait_change(handler, trait, remove=True) @contextlib.contextmanager diff -Nru python-pyface-4.5.2/pyface/ui/qt4/util/modal_dialog_tester.py python-pyface-6.1.2/pyface/ui/qt4/util/modal_dialog_tester.py --- python-pyface-4.5.2/pyface/ui/qt4/util/modal_dialog_tester.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/util/modal_dialog_tester.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,25 +1,32 @@ -# (C) Copyright 2014 Enthought, Inc., Austin, TX +# (C) Copyright 2014-2017 Enthought, Inc., Austin, TX # All right reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! """ A class to facilitate testing components that use TraitsUI or Qt Dialogs. """ import contextlib +import platform import sys import traceback from pyface.api import GUI, OK, CANCEL, YES, NO -from pyface.qt import QtCore, QtGui +from pyface.qt import QtCore, QtGui, qt_api from traits.api import Undefined from .event_loop_helper import EventLoopHelper -from .gui_test_assistant import find_qt_widget +from .testing import find_qt_widget BUTTON_TEXT = { - OK: 'OK', - CANCEL: 'Cancel', - YES: '&Yes', - NO: '&No', + OK: u'OK', + CANCEL: u'Cancel', + YES: u'Yes', + NO: u'No', } @@ -36,6 +43,10 @@ tester.open_and_run(when_opened=lambda x: x.close(accept=True)) self.assertEqual(tester.result, ) + # Even if the dialog was not opened upon calling `function`, + # `result` is assigned and the test may not fail. + # To test if the dialog was once opened: + self.assertTrue(tester.dialog_was_opened) .. note:: @@ -57,6 +68,7 @@ self._event_loop_error = [] self._helper = EventLoopHelper(qt_app=self._qt_app, gui=self._gui) self._dialog_widget = None + self.dialog_was_opened = False @property def result(self): @@ -105,10 +117,11 @@ """ Run the when_opened as soon as the dialog has opened. """ if self.dialog_opened(): self._gui.invoke_later(when_opened, self) + self.dialog_was_opened = True else: condition_timer.start() - # Setup and start the timer to singla the handler every 100 msec. + # Setup and start the timer to fire the handler every 100 msec. condition_timer.setInterval(100) condition_timer.setSingleShot(True) condition_timer.timeout.connect(handler) @@ -123,6 +136,8 @@ condition=self.value_assigned, timeout=15) finally: condition_timer.stop() + condition_timer.timeout.disconnect(handler) + self._helper.event_loop() self.assert_no_errors_collected() def open_and_wait(self, when_opened, *args, **kwargs): @@ -158,6 +173,7 @@ if self.dialog_opened(): self._dialog_widget = self.get_dialog_widget() self._gui.invoke_later(when_opened, self) + self.dialog_was_opened = True else: condition_timer.start() @@ -165,7 +181,12 @@ if self._dialog_widget is None: return False else: - return self.get_dialog_widget() != self._dialog_widget + value = (self.get_dialog_widget() != self._dialog_widget) + if value: + # process any pending events so that we have a clean + # event loop before we exit. + self._helper.event_loop() + return value # Setup and start the timer to signal the handler every 100 msec. condition_timer.setInterval(100) @@ -182,6 +203,9 @@ condition=condition, timeout=15) finally: condition_timer.stop() + condition_timer.timeout.disconnect(handler) + self._dialog_widget = None + self._helper.event_loop() self.assert_no_errors_collected() def open(self, *args, **kwargs): @@ -227,7 +251,6 @@ self._event_loop_error.append( (sys.exc_info()[0], traceback.format_exc()) ) - raise def assert_no_errors_collected(self): """ Assert that the tester has not collected any errors. @@ -246,13 +269,25 @@ def click_widget(self, text, type_=QtGui.QPushButton): """ Execute click on the widget of `type_` with `text`. + This strips '&' chars from the string, since usage varies from platform + to platform. """ control = self.get_dialog_widget() + + def test(widget): + # XXX asking for widget.text() causes occasional segfaults on Linux + # and pyqt (both 4 and 5). Not sure why this is happening. + # See issue #282 + return widget.text().replace('&', '') == text + widget = find_qt_widget( control, type_, - test=lambda widget: widget.text() == text + test=test ) + if widget is None: + # this will only occur if there is some problem with the test + raise RuntimeError("Could not find matching child widget.") widget.click() def click_button(self, button_id): @@ -263,7 +298,12 @@ """ A value was assigned to the result attribute. """ - return self._assigned + result = self._assigned + if result: + # process any pending events so that we have a clean + # even loop before we exit. + self._helper.event_loop() + return result def dialog_opened(self): """ Check that the dialog has opened. diff -Nru python-pyface-4.5.2/pyface/ui/qt4/util/testing.py python-pyface-6.1.2/pyface/ui/qt4/util/testing.py --- python-pyface-4.5.2/pyface/ui/qt4/util/testing.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/util/testing.py 2019-05-03 08:18:50.000000000 +0000 @@ -9,6 +9,7 @@ """ Tools for testing. """ +from __future__ import print_function from contextlib import contextmanager import os import sys @@ -55,27 +56,38 @@ @contextmanager -def silence_output(out=None, err=None): - """ Re-direct the stderr and stdout streams while in the block. """ +def _convert_none_to_null_handle(stream): + """ If 'stream' is None, provide a temporary handle to /dev/null. """ - if out is None: + if stream is None: out = open(os.devnull, 'w') - if err is None: - err = open(os.devnull, 'w') + try: + yield out + finally: + out.close() + else: + yield stream - _old_stderr = sys.stderr - _old_stderr.flush() - _old_stdout = sys.stdout - _old_stdout.flush() +@contextmanager +def silence_output(out=None, err=None): + """ Re-direct the stderr and stdout streams while in the block. """ - try: - sys.stdout = out - sys.stderr = err - yield - finally: - sys.stdout = _old_stdout - sys.stderr = _old_stderr + with _convert_none_to_null_handle(out) as out: + with _convert_none_to_null_handle(err) as err: + _old_stderr = sys.stderr + _old_stderr.flush() + + _old_stdout = sys.stdout + _old_stdout.flush() + + try: + sys.stdout = out + sys.stderr = err + yield + finally: + sys.stdout = _old_stdout + sys.stderr = _old_stderr def print_qt_widget_tree(widget, level=0): @@ -92,12 +104,12 @@ """ level = level + 4 if level == 0: - print - print ' '*level, widget + print() + print(' '*level, widget) for child in widget.children(): print_qt_widget_tree(child, level=level) if level == 0: - print + print() def find_qt_widget(start, type_, test=None): diff -Nru python-pyface-4.5.2/pyface/ui/qt4/util/tests/test_gui_test_assistant.py python-pyface-6.1.2/pyface/ui/qt4/util/tests/test_gui_test_assistant.py --- python-pyface-4.5.2/pyface/ui/qt4/util/tests/test_gui_test_assistant.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/util/tests/test_gui_test_assistant.py 2019-07-20 10:50:48.000000000 +0000 @@ -0,0 +1,60 @@ +import unittest + +from pyface.ui.qt4.util.gui_test_assistant import \ + GuiTestAssistant +from traits.api import Event, HasStrictTraits + + +class ExampleObject(HasStrictTraits): + """ Test class; target for test_event_loop_until_traits_change. """ + spam = Event + eggs = Event + + +class TestGuiTestAssistant(GuiTestAssistant, unittest.TestCase): + def test_event_loop_until_traits_change_with_single_trait_success(self): + # event_loop_until_traits_change calls self.fail on timeout. + obj = ExampleObject() + + # Successful case. + with self.event_loop_until_traits_change(obj, 'spam'): + obj.spam = True + + def test_event_loop_until_traits_change_with_single_trait_failure(self): + # event_loop_until_traits_change calls self.fail on timeout. + obj = ExampleObject() + + # Failing case. + with self.assertRaises(AssertionError): + with self.event_loop_until_traits_change(obj, 'spam', + timeout=0.1): + obj.eggs = True + + def test_event_loop_until_traits_change_with_multiple_traits_success(self): + # event_loop_until_traits_change calls self.fail on timeout. + obj = ExampleObject() + with self.event_loop_until_traits_change(obj, 'spam', 'eggs'): + obj.spam = True + obj.eggs = True + + def test_event_loop_until_traits_change_with_multiple_traits_failure(self): + # event_loop_until_traits_change calls self.fail on timeout. + obj = ExampleObject() + with self.assertRaises(AssertionError): + with self.event_loop_until_traits_change(obj, 'spam', 'eggs', + timeout=0.1): + obj.eggs = True + + # event_loop_until_traits_change calls self.fail on timeout. + with self.assertRaises(AssertionError): + with self.event_loop_until_traits_change(obj, 'spam', 'eggs', + timeout=0.1): + obj.spam = True + + def test_event_loop_until_traits_change_with_no_traits_success(self): + # event_loop_until_traits_change calls self.fail on timeout. + obj = ExampleObject() + + # Successful case. + with self.event_loop_until_traits_change(obj): + pass diff -Nru python-pyface-4.5.2/pyface/ui/qt4/util/tests/test_modal_dialog_tester.py python-pyface-6.1.2/pyface/ui/qt4/util/tests/test_modal_dialog_tester.py --- python-pyface-4.5.2/pyface/ui/qt4/util/tests/test_modal_dialog_tester.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/util/tests/test_modal_dialog_tester.py 2019-05-03 08:18:50.000000000 +0000 @@ -8,23 +8,34 @@ # Thanks for using Enthought open source! """ Tests for the tabular editor tester. """ +from __future__ import absolute_import import unittest -import cStringIO +from six.moves import cStringIO as StringIO +import platform from pyface.qt import QtGui -from pyface.api import MessageDialog, OK, CANCEL +from pyface.api import Dialog, MessageDialog, OK, CANCEL +from pyface.toolkit import toolkit_object from traits.api import HasStrictTraits -from traitsui.api import CancelButton, OKButton, View from pyface.ui.qt4.util.testing import silence_output from pyface.ui.qt4.util.gui_test_assistant import GuiTestAssistant from pyface.ui.qt4.util.modal_dialog_tester import ModalDialogTester +from pyface.util.testing import skip_if_no_traitsui + + +is_qt = toolkit_object.toolkit == 'qt4' +if is_qt: + from pyface.qt import qt_api +is_pyqt5 = (is_qt and qt_api == 'pyqt5') class MyClass(HasStrictTraits): def default_traits_view(self): + from traitsui.api import CancelButton, OKButton, View + view = View( buttons=[OKButton, CancelButton], resizable=False, @@ -38,7 +49,11 @@ else: return 'rejected' + def do_not_show_dialog(self): + return True + +@unittest.skipIf(is_pyqt5, "ModalDialogTester not working on pyqt5. Issue #302") class TestModalDialogTester(unittest.TestCase, GuiTestAssistant): """ Tests for the modal dialog tester. """ @@ -52,12 +67,15 @@ tester.open_and_run(when_opened=lambda x: x.close(accept=True)) self.assertTrue(tester.value_assigned()) self.assertEqual(tester.result, OK) + self.assertTrue(tester.dialog_was_opened) # reject tester.open_and_run(when_opened=lambda x: x.close()) self.assertTrue(tester.value_assigned()) self.assertEqual(tester.result, CANCEL) + self.assertTrue(tester.dialog_was_opened) + @skip_if_no_traitsui def test_on_traitsui_dialog(self): my_class = MyClass() tester = ModalDialogTester(my_class.run) @@ -66,11 +84,26 @@ tester.open_and_run(when_opened=lambda x: x.close(accept=True)) self.assertTrue(tester.value_assigned()) self.assertEqual(tester.result, 'accepted') + self.assertTrue(tester.dialog_was_opened) # reject tester.open_and_run(when_opened=lambda x: x.close()) self.assertTrue(tester.value_assigned()) self.assertEqual(tester.result, 'rejected') + self.assertTrue(tester.dialog_was_opened) + + @skip_if_no_traitsui + def test_dialog_was_not_opened_on_traitsui_dialog(self): + my_class = MyClass() + tester = ModalDialogTester(my_class.do_not_show_dialog) + + # it runs okay + tester.open_and_run(when_opened=lambda x: x.close(accept=True)) + self.assertTrue(tester.value_assigned()) + self.assertEqual(tester.result, True) + + # but no dialog is opened + self.assertFalse(tester.dialog_was_opened) def test_capture_errors_on_failure(self): dialog = MessageDialog() @@ -83,9 +116,10 @@ self.fail() finally: tester.close() + self.gui.process_events() with self.assertRaises(AssertionError): - alt_stderr = cStringIO.StringIO + alt_stderr = StringIO with silence_output(err=alt_stderr): tester.open_and_run(when_opened=failure) self.assertIn('raise self.failureException(msg)', alt_stderr) @@ -101,22 +135,24 @@ 1 / 0 finally: tester.close() + self.gui.process_events() with self.assertRaises(ZeroDivisionError): - alt_stderr = cStringIO.StringIO + alt_stderr = StringIO with silence_output(err=alt_stderr): tester.open_and_run(when_opened=raise_error) self.assertIn('ZeroDivisionError', alt_stderr) + @unittest.skip("has_widget code not working as designed. Issue #282.") def test_has_widget(self): - my_class = MyClass() - tester = ModalDialogTester(my_class.run) + dialog = Dialog() + tester = ModalDialogTester(dialog.open) def check_and_close(tester): try: with tester.capture_error(): self.assertTrue( - tester.has_widget('OK', QtGui.QPushButton) + tester.has_widget('OK', QtGui.QAbstractButton) ) self.assertFalse( tester.has_widget(text='I am a virtual button') @@ -126,15 +162,16 @@ tester.open_and_run(when_opened=check_and_close) + @unittest.skip("has_widget code not working as designed. Issue #282.") def test_find_widget(self): - my_class = MyClass() - tester = ModalDialogTester(my_class.run) + dialog = Dialog() + tester = ModalDialogTester(dialog.open) def check_and_close(tester): try: with tester.capture_error(): widget = tester.find_qt_widget( - type_=QtGui.QPushButton, + type_=QtGui.QAbstractButton, test=lambda x: x.text() == 'OK' ) self.assertIsInstance(widget, QtGui.QPushButton) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/widget.py python-pyface-6.1.2/pyface/ui/qt4/widget.py --- python-pyface-4.5.2/pyface/ui/qt4/widget.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/widget.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,18 +1,20 @@ -#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. +# Copyright (c) 2017, Enthought, Inc +# All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply - # # Author: Riverbank Computing Limited # Description: -#------------------------------------------------------------------------------ +# Major package imports. +from pyface.qt import QtCore, QtGui + # Enthought library imports. -from traits.api import Any, HasTraits, provides +from traits.api import Any, Bool, HasTraits, Instance, provides # Local imports. from pyface.i_widget import IWidget, MWidget @@ -24,21 +26,103 @@ interface for the API documentation. """ + # 'IWidget' interface ---------------------------------------------------- - #### 'IWidget' interface ################################################## - + #: The toolkit specific control that represents the widget. control = Any + #: The control's optional parent control. parent = Any - ########################################################################### + #: Whether or not the control is visible + visible = Bool(True) + + #: Whether or not the control is enabled + enabled = Bool(True) + + # Private interface ---------------------------------------------------- + + #: The event filter for the widget. + _event_filter = Instance(QtCore.QObject) + + # ------------------------------------------------------------------------ # 'IWidget' interface. - ########################################################################### + # ------------------------------------------------------------------------ + + def show(self, visible): + """ Show or hide the widget. + + Parameter + --------- + visible : bool + Visible should be ``True`` if the widget should be shown. + """ + self.visible = visible + if self.control is not None: + self.control.setVisible(visible) + + def enable(self, enabled): + """ Enable or disable the widget. + + Parameter + --------- + enabled : bool + The enabled state to set the widget to. + """ + self.enabled = enabled + if self.control is not None: + self.control.setEnabled(enabled) def destroy(self): + self._remove_event_listeners() if self.control is not None: self.control.hide() self.control.deleteLater() self.control = None -#### EOF ###################################################################### + def _add_event_listeners(self): + self.control.installEventFilter(self._event_filter) + + def _remove_event_listeners(self): + if self._event_filter is not None: + if self.control is not None: + self.control.removeEventFilter(self._event_filter) + self._event_filter = None + + # Trait change handlers -------------------------------------------------- + + def _visible_changed(self, new): + if self.control is not None: + self.show(new) + + def _enabled_changed(self, new): + if self.control is not None: + self.enable(new) + + def __event_filter_default(self): + return WidgetEventFilter(self) + + +class WidgetEventFilter(QtCore.QObject): + """ An internal class that watches for certain events on behalf of the + Widget instance. + """ + + def __init__(self, widget): + """ Initialise the event filter. """ + QtCore.QObject.__init__(self) + self._widget = widget + + def eventFilter(self, obj, event): + """ Adds any event listeners required by the window. """ + widget = self._widget + # Sanity check. + if obj is not widget.control: + return False + + event_type = event.type() + + if event_type in {QtCore.QEvent.Show, QtCore.QEvent.Hide}: + widget.visible = widget.control.isVisible() + + return False diff -Nru python-pyface-4.5.2/pyface/ui/qt4/window.py python-pyface-6.1.2/pyface/ui/qt4/window.py --- python-pyface-4.5.2/pyface/ui/qt4/window.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/window.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,28 +1,28 @@ -#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited +# Copyright (c) 2017-18, Enthought, Inc. # All rights reserved. # -# This software is provided without warranty under the terms of the BSD license. -# However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply - +# This software is provided without warranty under the terms of the BSD +# license. However, when used with the GPL version of PyQt the additional +# terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited +# Author: Enhtought, Inc. # Description: -#------------------------------------------------------------------------------ - # Major package imports. from pyface.qt import QtCore, QtGui # Enthought library imports. -from traits.api import Enum, Event, Property, provides, Unicode -from traits.api import Tuple +from traits.api import ( + Enum, Event, Property, Tuple, Unicode, VetoableEvent, provides +) # Local imports. from pyface.i_window import IWindow, MWindow from pyface.key_pressed_event import KeyPressedEvent -from gui import GUI -from widget import Widget +from .gui import GUI +from .widget import Widget @provides(IWindow) @@ -31,8 +31,7 @@ interface for the API documentation. """ - - #### 'IWindow' interface ################################################## + # 'IWindow' interface ----------------------------------------------------- position = Property(Tuple) @@ -42,44 +41,47 @@ title = Unicode - #### Events ##### + # Window Events ---------------------------------------------------------- - activated = Event - - closed = Event + #: The window has been opened. + opened = Event - closing = Event + #: The window is about to open. + opening = VetoableEvent - deactivated = Event + #: The window has been activated. + activated = Event - key_pressed = Event(KeyPressedEvent) + #: The window has been closed. + closed = Event - opened = Event + #: The window is about to be closed. + closing = VetoableEvent - opening = Event + #: The window has been deactivated. + deactivated = Event - #### Private interface #################################################### + # Private interface ------------------------------------------------------ - # Shadow trait for position. + #: Shadow trait for position. _position = Tuple((-1, -1)) - # Shadow trait for size. + #: Shadow trait for size. _size = Tuple((-1, -1)) - ########################################################################### + # ------------------------------------------------------------------------- # 'IWindow' interface. - ########################################################################### + # ------------------------------------------------------------------------- def activate(self): self.control.activateWindow() self.control.raise_() + # explicitly fire activated trait as signal doesn't create Qt event + self.activated = self - def show(self, visible): - self.control.setVisible(visible) - - ########################################################################### + # ------------------------------------------------------------------------- # Protected 'IWindow' interface. - ########################################################################### + # ------------------------------------------------------------------------- def _create_control(self, parent): """ Create a default QMainWindow. """ @@ -87,26 +89,24 @@ if self.size != (-1, -1): control.resize(*self.size) - if self.position != (-1, -1): control.move(*self.position) - if self.size_state != 'normal': self._size_state_changed(self.size_state) - control.setWindowTitle(self.title) + control.setEnabled(self.enabled) - return control + # XXX starting with visible true is not recommended + control.setVisible(self.visible) - def _add_event_listeners(self): - self._event_filter = _EventFilter(self) + return control - ########################################################################### + # ------------------------------------------------------------------------- # 'IWidget' interface. - ########################################################################### + # ------------------------------------------------------------------------- def destroy(self): - self._event_filter = None + self._remove_event_listeners() if self.control is not None: # Avoid problems with recursive calls. @@ -123,9 +123,9 @@ super(Window, self).destroy() control.close() - ########################################################################### + # ------------------------------------------------------------------------- # Private interface. - ########################################################################### + # ------------------------------------------------------------------------- def _get_position(self): """ Property getter for position. """ @@ -162,12 +162,16 @@ def _size_state_changed(self, state): control = self.control if control is None: - return # Nothing to do here + return # Nothing to do here if state == 'maximized': - control.setWindowState(control.windowState() | QtCore.Qt.WindowMaximized) + control.setWindowState( + control.windowState() | QtCore.Qt.WindowMaximized + ) elif state == 'normal': - control.setWindowState(control.windowState() & ~QtCore.Qt.WindowMaximized) + control.setWindowState( + control.windowState() & ~QtCore.Qt.WindowMaximized + ) def _title_changed(self, title): """ Static trait change handler. """ @@ -175,18 +179,18 @@ if self.control is not None: self.control.setWindowTitle(title) + def __event_filter_default(self): + return WindowEventFilter(self) -class _EventFilter(QtCore.QObject): + +class WindowEventFilter(QtCore.QObject): """ An internal class that watches for certain events on behalf of the Window instance. """ def __init__(self, window): """ Initialise the event filter. """ - QtCore.QObject.__init__(self) - - window.control.installEventFilter(self) self._window = window def eventFilter(self, obj, e): @@ -215,6 +219,9 @@ elif typ == QtCore.QEvent.WindowDeactivate: window.deactivated = window + elif typ in {QtCore.QEvent.Show, QtCore.QEvent.Hide}: + window.visible = window.control.isVisible() + elif typ == QtCore.QEvent.Resize: # Get the new size and set the shadow trait without performing # notification. @@ -239,14 +246,15 @@ mods = e.modifiers() window.key_pressed = KeyPressedEvent( - alt_down = ((mods & QtCore.Qt.AltModifier) == - QtCore.Qt.AltModifier), - control_down = ((mods & QtCore.Qt.ControlModifier) == - QtCore.Qt.ControlModifier), - shift_down = ((mods & QtCore.Qt.ShiftModifier) == - QtCore.Qt.ShiftModifier), - key_code = kcode, - event = e) + alt_down=((mods & + QtCore.Qt.AltModifier) == QtCore.Qt.AltModifier), + control_down=((mods & QtCore.Qt.ControlModifier + ) == QtCore.Qt.ControlModifier), + shift_down=((mods & QtCore.Qt.ShiftModifier + ) == QtCore.Qt.ShiftModifier), + key_code=kcode, + event=e + ) elif typ == QtCore.QEvent.WindowStateChange: # set the size_state of the window. @@ -257,5 +265,3 @@ window.size_state = 'normal' return False - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/qt4/wizard/wizard_page.py python-pyface-6.1.2/pyface/ui/qt4/wizard/wizard_page.py --- python-pyface-4.5.2/pyface/ui/qt4/wizard/wizard_page.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/wizard/wizard_page.py 2019-05-03 08:18:50.000000000 +0000 @@ -137,6 +137,6 @@ def _on_complete_changed(self): """ The trait handler for when the page's completion state changes. """ - self.emit(QtCore.SIGNAL('completeChanged()')) + self.completeChanged.emit() #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/qt4/wizard/wizard.py python-pyface-6.1.2/pyface/ui/qt4/wizard/wizard.py --- python-pyface-4.5.2/pyface/ui/qt4/wizard/wizard.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/wizard/wizard.py 2019-05-03 08:18:50.000000000 +0000 @@ -13,6 +13,7 @@ # Major package imports. +from __future__ import print_function from pyface.qt import QtCore, QtGui # Enthought library imports. @@ -78,8 +79,7 @@ # Necessary for 'nonmodal'. See Dialog for more info. if self.style == 'nonmodal': - QtCore.QObject.connect(control, QtCore.SIGNAL('finished(int)'), - self._finished_fired) + control.finished.connect(self._finished_fired) if self.size != (-1, -1): size = QtCore.QSize(*self.size) @@ -91,8 +91,7 @@ if self.help_id: control.setOption(QtGui.QWizard.HaveHelpButton) - QtCore.QObject.connect(control, QtCore.SIGNAL('helpRequested()'), - self._help_requested) + control.helpRequested.connect(self._help_requested) # Add the initial pages. for page in self.pages: @@ -112,7 +111,7 @@ """ Called when the 'Help' button is pressed. """ # FIXME: Hook into a help system. - print "Show help for", self.help_id + print("Show help for", self.help_id) #### Trait handlers ####################################################### @@ -168,8 +167,7 @@ self._controller = pyface_wizard.controller self._ids = {} - QtCore.QObject.connect(self, QtCore.SIGNAL('currentIdChanged(int)'), - self._update_controller) + self.currentIdChanged.connect(self._update_controller) def addWizardPage(self, page): """ Add a page that provides IWizardPage. """ diff -Nru python-pyface-4.5.2/pyface/ui/qt4/workbench/split_tab_widget.py python-pyface-6.1.2/pyface/ui/qt4/workbench/split_tab_widget.py --- python-pyface-4.5.2/pyface/ui/qt4/workbench/split_tab_widget.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/workbench/split_tab_widget.py 2019-05-03 08:18:50.000000000 +0000 @@ -9,6 +9,7 @@ # Standard library imports. import sys +import six # Major library imports. from pyface.qt import QtCore, QtGui, qt_api @@ -26,11 +27,13 @@ new_window_request = QtCore.Signal(QtCore.QPoint, QtGui.QWidget) tab_close_request = QtCore.Signal(QtGui.QWidget) tab_window_changed = QtCore.Signal(QtGui.QWidget) + editor_has_focus = QtCore.Signal(QtGui.QWidget) + focus_changed = QtCore.Signal(QtGui.QWidget, QtGui.QWidget) # The different hotspots of a QTabWidget. An non-negative value is a tab # index and the hotspot is to the left of it. - tabTextChanged = QtCore.Signal(QtGui.QWidget, unicode) + tabTextChanged = QtCore.Signal(QtGui.QWidget, six.text_type) _HS_NONE = -1 _HS_AFTER_LAST_TAB = -2 _HS_NORTH = -3 @@ -46,9 +49,7 @@ self.clear() - QtCore.QObject.connect(QtGui.QApplication.instance(), - QtCore.SIGNAL('focusChanged(QWidget *,QWidget *)'), - self._focus_changed) + QtGui.QApplication.instance().focusChanged.connect(self._focus_changed) def clear(self): """ Restore the widget to its pristine state. """ @@ -92,8 +93,8 @@ for t in range(ch.count()): # A tab state is a tuple of the widget's object name and # the title. - name = unicode(ch.widget(t).objectName()) - title = unicode(ch.tabText(t)) + name = six.text_type(ch.widget(t).objectName()) + title = six.text_type(ch.tabText(t)) tab_states.append((name, title)) @@ -104,7 +105,7 @@ sp_ch_states.append(ch_state) - return (str(QtGui.QSplitter.saveState(qsplitter)), sp_ch_states) + return (QtGui.QSplitter.saveState(qsplitter).data(), sp_ch_states) def restoreState(self, state, factory): """ Restore the contents from the given state (returned by a previous @@ -298,8 +299,7 @@ return if self._repeat_focus_changes: - self.emit(QtCore.SIGNAL('focusChanged(QWidget *,QWidget *)'), - old, new) + self.focus_changed.emit(old, new) if new is None: return @@ -321,7 +321,7 @@ else: nw = ntw.widget(ntidx) - self.emit(QtCore.SIGNAL('hasFocus'), nw) + self.editor_has_focus.emit(nw) def _tab_widget_of(self, target): """ Return the tab widget and index of the widget that contains the @@ -871,8 +871,8 @@ # LineEdit to change tab bar title te = _IndependentLineEdit("", self) te.hide() - te.connect(te, QtCore.SIGNAL('editingFinished()'), te, QtCore.SLOT('hide()')) - self.connect(te, QtCore.SIGNAL('returnPressed()'), self._setCurrentTabText) + te.editingFinished.connect(te.hide) + te.returnPressed.connect(self._setCurrentTabText) self._title_edit = te def resizeEvent(self, e): @@ -976,7 +976,7 @@ idx = self.currentIndex() text = self._title_edit.text() self.setTabText(idx, u'\u25b6'+text) - self._root.emit(QtCore.SIGNAL('tabTextChanged(QWidget *, QString)'), self.parent().widget(idx), text) + self._root.tabTextChanged.emit(self.parent().widget(idx), text) def _resize_title_edit_to_current_tab(self): idx = self.currentIndex() diff -Nru python-pyface-4.5.2/pyface/ui/qt4/workbench/tests/test_workbench_window_layout.py python-pyface-6.1.2/pyface/ui/qt4/workbench/tests/test_workbench_window_layout.py --- python-pyface-4.5.2/pyface/ui/qt4/workbench/tests/test_workbench_window_layout.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/workbench/tests/test_workbench_window_layout.py 2019-06-14 12:22:56.000000000 +0000 @@ -0,0 +1,25 @@ +from __future__ import absolute_import +import mock +import unittest + +from pyface.ui.qt4.workbench.split_tab_widget import SplitTabWidget +from pyface.ui.qt4.workbench.workbench_window_layout import \ + WorkbenchWindowLayout + + +class TestWorkbenchWindowLayout(unittest.TestCase): + def test_change_of_active_qt_editor(self): + # Test error condition for enthought/mayavi#321 + + mock_split_tab_widget = mock.Mock(spec=SplitTabWidget) + + layout = WorkbenchWindowLayout(_qt4_editor_area=mock_split_tab_widget) + + # This should not throw + layout._qt4_active_editor_changed(None, None) + self.assertEqual(mock_split_tab_widget.setTabTextColor.called, False) + + mock_active_editor = mock.Mock() + layout._qt4_active_editor_changed(None, mock_active_editor) + + self.assertEqual(mock_split_tab_widget.setTabTextColor.called, True) diff -Nru python-pyface-4.5.2/pyface/ui/qt4/workbench/workbench_window_layout.py python-pyface-6.1.2/pyface/ui/qt4/workbench/workbench_window_layout.py --- python-pyface-4.5.2/pyface/ui/qt4/workbench/workbench_window_layout.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/qt4/workbench/workbench_window_layout.py 2019-05-03 08:18:50.000000000 +0000 @@ -21,10 +21,11 @@ from traits.api import Instance, on_trait_change # Local imports. -from split_tab_widget import SplitTabWidget from pyface.message_dialog import error from pyface.workbench.i_workbench_window_layout import \ MWorkbenchWindowLayout +from .split_tab_widget import SplitTabWidget +import six # Logging. @@ -130,8 +131,7 @@ def close(self): # Don't fire signals for editors that have destroyed their controls. - QtCore.QObject.disconnect(self._qt4_editor_area, - QtCore.SIGNAL('hasFocus'), self._qt4_editor_focus) + self._qt4_editor_area.editor_has_focus.disconnect(self._qt4_editor_focus) self._qt4_editor_area.clear() @@ -143,20 +143,14 @@ def create_initial_layout(self, parent): self._qt4_editor_area = editor_area = SplitTabWidget(parent) - QtCore.QObject.connect(editor_area, QtCore.SIGNAL('hasFocus'), - self._qt4_editor_focus) + editor_area.editor_has_focus.connect(self._qt4_editor_focus) # We are interested in focus changes but we get them from the editor # area rather than qApp to allow the editor area to restrict them when # needed. - QtCore.QObject.connect( - editor_area, QtCore.SIGNAL('focusChanged(QWidget *,QWidget *)'), - self._qt4_view_focus_changed) - - QtCore.QObject.connect(self._qt4_editor_area, - QtCore.SIGNAL('tabTextChanged(QWidget *, QString)'), - self._qt4_editor_title_changed) + editor_area.focus_changed.connect(self._qt4_view_focus_changed) + editor_area.tabTextChanged.connect(self._qt4_editor_title_changed) editor_area.new_window_request.connect(self._qt4_new_window_request) editor_area.tab_close_request.connect(self._qt4_tab_close_request) editor_area.tab_window_changed.connect(self._qt4_tab_window_changed) @@ -202,7 +196,7 @@ view_ids = [v.id for v in self.window.views if self.contains_view(v)] # Everything else is provided by QMainWindow. - state = str(self.window.control.saveState()) + state = self.window.control.saveState() return (0, (view_ids, state)) @@ -292,7 +286,7 @@ self._qt4_editor_area.restoreState(editor_layout, resolve_id) def get_toolkit_memento(self): - return (0, dict(geometry=str(self.window.control.saveGeometry()))) + return (0, {'geometry' : self.window.control.saveGeometry()}) def set_toolkit_memento(self, memento): if hasattr(memento, 'toolkit_data'): @@ -304,6 +298,8 @@ if geometry is not None: self.window.control.restoreGeometry(geometry) + def is_editor_area_visible(self): + return self._qt4_editor_area.isVisible() ########################################################################### # Private interface. @@ -320,7 +316,7 @@ def _qt4_editor_title_changed(self, control, title): """ Handle the title being changed """ for editor in self.window.editors: - if editor.control == control: editor.name = unicode(title) + if editor.control == control: editor.name = six.text_type(title) def _qt4_editor_tab_spinner(self, editor, name, new): # Do we need to do this verification? @@ -336,7 +332,8 @@ def _qt4_active_editor_changed(self, old, new): """ Handle change of active editor """ # Reset tab title to foreground color - self._qt4_editor_area.setTabTextColor(new.control) + if new is not None: + self._qt4_editor_area.setTabTextColor(new.control) def _qt4_view_focus_changed(self, old, new): """ Handle the change of focus for a view. """ @@ -466,7 +463,7 @@ try: dwa = _EDIT_AREA_MAP[position] except KeyError: - raise ValueError, "unknown view position: %s" % position + raise ValueError("unknown view position: %s" % position) mw.addDockWidget(dwa, dw) elif position == 'with': @@ -478,7 +475,7 @@ try: orient, swap = _VIEW_AREA_MAP[position] except KeyError: - raise ValueError, "unknown view position: %s" % position + raise ValueError("unknown view position: %s" % position) mw.splitDockWidget(rel_dw, dw, orient) @@ -501,10 +498,9 @@ dw = QtGui.QDockWidget(view.name, self.window.control) dw.setWidget(_ViewContainer(size, self.window.control)) dw.setObjectName(view.id) - dw.connect(dw.toggleViewAction(), QtCore.SIGNAL('toggled(bool)'), - self._qt4_handle_dock_visibility) - dw.connect(dw, QtCore.SIGNAL('visibilityChanged(bool)'), - self._qt4_handle_dock_visibility) + dw.toggleViewAction().toggled.connect( + self._qt4_handle_dock_visibility) + dw.visibilityChanged.connect(self._qt4_handle_dock_visibility) # Save the dock window. view._qt4_dock = dw @@ -520,7 +516,7 @@ view.window = self.window try: - view.control = view.create_control(self.window.control) + view.control = view.create_control(dw.widget()) except: # Tidy up if the view couldn't be created. delattr(view, '_qt4_dock') diff -Nru python-pyface-4.5.2/pyface/ui/wx/about_dialog.py python-pyface-6.1.2/pyface/ui/wx/about_dialog.py --- python-pyface-4.5.2/pyface/ui/wx/about_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/about_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -31,7 +31,7 @@ # Local imports. from pyface.i_about_dialog import IAboutDialog, MAboutDialog from pyface.image_resource import ImageResource -from dialog import Dialog +from .dialog import Dialog _DIALOG_TEXT = ''' diff -Nru python-pyface-4.5.2/pyface/ui/wx/action/action_item.py python-pyface-6.1.2/pyface/ui/wx/action/action_item.py --- python-pyface-4.5.2/pyface/ui/wx/action/action_item.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/action/action_item.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,6 +1,4 @@ -#------------------------------------------------------------------------------ -# -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2005-19, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -11,14 +9,17 @@ # Thanks for using Enthought open source! # # Author: Enthought, Inc. -# -#------------------------------------------------------------------------------ """ The wx specific implementations the action manager internal classes. """ # Standard libary imports. -from inspect import getargspec +import six +if six.PY2: + from inspect import getargspec +else: + # avoid deprecation warning + from inspect import getfullargspec as getargspec # Major package imports. import wx @@ -33,7 +34,8 @@ _STYLE_TO_KIND_MAP = { 'push' : wx.ITEM_NORMAL, 'radio' : wx.ITEM_RADIO, - 'toggle' : wx.ITEM_CHECK + 'toggle' : wx.ITEM_CHECK, + 'widget' : None, } @@ -74,7 +76,11 @@ action = item.action label = action.name kind = _STYLE_TO_KIND_MAP[action.style] - longtip = action.description + longtip = action.description or action.tooltip + + if action.style == "widget": + raise NotImplementedError( + "WxPython does not support widgets in menus") if len(action.accelerator) > 0: label = label + '\t' + action.accelerator @@ -85,12 +91,26 @@ if len(label) == 0: label = item.action.__class__.__name__ - self.control_id = wx.NewId() + + if getattr(action, 'menu_role', False): + if action.menu_role == "About": + self.control_id = wx.ID_ABOUT + elif action.menu_role == "Preferences": + self.control_id = wx.ID_PREFERENCES + elif action.menu_role == "Quit": + self.control_id = wx.ID_EXIT + else: + self.control_id = wx.NewId() self.control = wx.MenuItem(menu, self.control_id, label, longtip, kind) # If the action has an image then display it. if action.image is not None: - self.control.SetBitmap(action.image.create_bitmap()) + try: + self.control.SetBitmap(action.image.create_bitmap()) + except: + # Some platforms don't allow radio buttons to have + # bitmaps, so just ignore the exception if it happens + pass menu.AppendItem(self.control) menu.menu_items.append(self) @@ -217,7 +237,10 @@ def _on_action_name_changed(self, action, trait_name, old, new): """ Called when the name trait is changed on an action. """ - self.control.SetText(action.name) + label = action.name + if len(action.accelerator) > 0: + label = label + '\t' + action.accelerator + self.control.SetText(label) return @@ -249,11 +272,11 @@ # contains information about the time the event occurred etc), so # we only pass it if the perform method requires it. This is also # useful as Traits UI controllers *never* require the event. - args, varargs, varkw, dflts = getargspec(self.controller.perform) + argspec = getargspec(self.controller.perform) # If the only arguments are 'self' and 'action' then don't pass # the event! - if len(args) == 2: + if len(argspec.args) == 2: self.controller.perform(action) else: @@ -266,10 +289,10 @@ # Most of the time, action's do no care about the event (it # contains information about the time the event occurred etc), so # we only pass it if the perform method requires it. - args, varargs, varkw, dflts = getargspec(action.perform) + argspec = getargspec(action.perform) # If the only argument is 'self' then don't pass the event! - if len(args) == 1: + if len(argspec.args) == 1: action.perform() else: @@ -345,19 +368,32 @@ else: self.tool_bar.SetSize((-1, 50)) - self.control_id = wx.NewId() - self.control = tool_bar.AddLabelTool( - self.control_id, label, bmp, wx.NullBitmap, kind, tooltip, longtip - ) + if action.style == 'widget': + widget = action.create_control(self.tool_bar) + self.control = tool_bar.AddControl(widget, label) + self.control_id = self.control.GetId() + else: + self.control_id = wx.NewId() + self.control = tool_bar.AddLabelTool( + self.control_id, label, bmp, wx.NullBitmap, kind, tooltip, longtip, None + ) - # Set the initial checked state. - tool_bar.ToggleTool(self.control_id, action.checked) + # Set the initial checked state. + tool_bar.ToggleTool(self.control_id, action.checked) - # Set the initial enabled/disabled state of the action. - tool_bar.EnableTool(self.control_id, action.enabled and action.visible) + if hasattr(tool_bar, 'ShowTool'): + # Set the initial enabled/disabled state of the action. + tool_bar.EnableTool(self.control_id, action.enabled) + + # Set the initial visibility + tool_bar.ShowTool(self.control_id, action.visible) + else: + # Set the initial enabled/disabled state of the action. + tool_bar.EnableTool( + self.control_id, action.enabled and action.visible) - # Wire it up. - wx.EVT_TOOL(parent, self.control_id, self._on_tool) + # Wire it up. + wx.EVT_TOOL(parent, self.control_id, self._on_tool) # Listen for trait changes on the action (so that we can update its # enabled/disabled/checked state etc). @@ -369,8 +405,6 @@ self.controller = controller controller.add_to_toolbar(self) - return - ########################################################################### # Private interface. ########################################################################### @@ -380,16 +414,20 @@ def _enabled_changed(self): """ Called when our 'enabled' trait is changed. """ - self.tool_bar.EnableTool(self.control_id, self.enabled and self.visible) - - return + if hasattr(self.tool_bar, 'ShowTool'): + self.tool_bar.EnableTool(self.control_id, self.enabled) + else: + self.tool_bar.EnableTool( + self.control_id, self.enabled and self.visible) def _visible_changed(self): """ Called when our 'visible' trait is changed. """ - self.tool_bar.EnableTool(self.control_id, self.visible and self.enabled) - - return + if hasattr(self.tool_bar, 'ShowTool'): + self.tool_bar.ShowTool(self.control_id, self.visible) + else: + self.tool_bar.EnableTool( + self.control_id, self.enabled and self.visible) def _checked_changed(self): """ Called when our 'checked' trait is changed. """ @@ -414,16 +452,20 @@ def _on_action_enabled_changed(self, action, trait_name, old, new): """ Called when the enabled trait is changed on an action. """ - self.tool_bar.EnableTool(self.control_id, action.enabled and action.visible) - - return + if hasattr(self.tool_bar, 'ShowTool'): + self.tool_bar.EnableTool(self.control_id, action.enabled) + else: + self.tool_bar.EnableTool( + self.control_id, action.enabled and action.visible) def _on_action_visible_changed(self, action, trait_name, old, new): """ Called when the visible trait is changed on an action. """ - self.tool_bar.EnableTool(self.control_id, action.visible and action.enabled) - - return + if hasattr(self.tool_bar, 'ShowTool'): + self.tool_bar.ShowTool(self.control_id, action.visible) + else: + self.tool_bar.EnableTool( + self.control_id, self.enabled and action.visible) def _on_action_checked_changed(self, action, trait_name, old, new): """ Called when the checked trait is changed on an action. """ @@ -465,11 +507,11 @@ # contains information about the time the event occurred etc), so # we only pass it if the perform method requires it. This is also # useful as Traits UI controllers *never* require the event. - args, varargs, varkw, dflts = getargspec(self.controller.perform) + argspec = getargspec(self.controller.perform) # If the only arguments are 'self' and 'action' then don't pass # the event! - if len(args) == 2: + if len(argspec.args) == 2: self.controller.perform(action) else: @@ -481,10 +523,10 @@ # Most of the time, action's do no care about the event (it # contains information about the time the event occurred etc), so # we only pass it if the perform method requires it. - args, varargs, varkw, dflts = getargspec(action.perform) + argspec = getargspec(action.perform) # If the only argument is 'self' then don't pass the event! - if len(args) == 1: + if len(argspec.args) == 1: action.perform() else: @@ -515,6 +557,10 @@ action = self.item.action label = action.name + if action.style == "widget": + raise NotImplementedError( + "WxPython does not support widgets in palettes") + # Tool palette tools never have '...' at the end. if label.endswith('...'): label = label[:-3] diff -Nru python-pyface-4.5.2/pyface/ui/wx/action/menu_manager.py python-pyface-6.1.2/pyface/ui/wx/action/menu_manager.py --- python-pyface-4.5.2/pyface/ui/wx/action/menu_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/action/menu_manager.py 2019-05-03 08:18:50.000000000 +0000 @@ -21,7 +21,7 @@ import wx # Enthought library imports. -from traits.api import Unicode +from traits.api import Unicode, Bool # Local imports. from pyface.action.action_manager import ActionManager @@ -41,6 +41,9 @@ # label will be). name = Unicode + # Does the menu require a separator before the menu item name? + separator = Bool(True) + ########################################################################### # 'MenuManager' interface. ########################################################################### @@ -205,6 +208,10 @@ previous_non_empty_group = item else: + if isinstance(item, MenuManager): + if item.separator: + self.AppendSeparator() + previous_non_empty_group = item item.add_to_menu(parent, self, self._controller) previous_non_empty_group = group diff -Nru python-pyface-4.5.2/pyface/ui/wx/action/status_bar_manager.py python-pyface-6.1.2/pyface/ui/wx/action/status_bar_manager.py --- python-pyface-4.5.2/pyface/ui/wx/action/status_bar_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/action/status_bar_manager.py 2019-05-03 08:18:50.000000000 +0000 @@ -55,6 +55,14 @@ return self.status_bar + def remove_status_bar(self, parent): + """ Removes a status bar. """ + + if self.status_bar is not None: + self.status_bar.Destroy() + self.status_bar._pyface_control = None + self.status_bar = None + ########################################################################### # Property handlers. ########################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/action/tool_bar_manager.py python-pyface-6.1.2/pyface/ui/wx/action/tool_bar_manager.py --- python-pyface-4.5.2/pyface/ui/wx/action/tool_bar_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/action/tool_bar_manager.py 2019-05-03 08:18:50.000000000 +0000 @@ -24,6 +24,7 @@ from traits.api import Bool, Enum, Instance, Str, Tuple # Local imports. +from pyface.wx.aui import aui from pyface.image_cache import ImageCache from pyface.action.action_manager import ActionManager @@ -82,7 +83,7 @@ #### Trait change handlers ################################################ #### Methods ############################################################## - def create_tool_bar(self, parent, controller=None): + def create_tool_bar(self, parent, controller=None, aui=False): """ Creates a tool bar. """ # If a controller is required it can either be set as a trait on the @@ -109,7 +110,10 @@ style |= wx.TB_NODIVIDER # Create the control. - tool_bar = _ToolBar(self, parent, -1, style=style) + if aui: + tool_bar = _AuiToolBar(self, parent, -1, style=style) + else: + tool_bar = _ToolBar(self, parent, -1, style=style) # fixme: Setting the tool bitmap size seems to be the only way to # change the height of the toolbar in wx. @@ -170,8 +174,12 @@ # If the group is a radio group, set the initial checked state # of every tool in it. if item.action.style == 'radio': - tool_bar.ToggleTool(item.control_id, item.action.checked) - checked = checked or item.action.checked + if item.control_id is not None: + # Only set checked state if control has been created. + # Using extra_actions of tasks, it appears that this + # may be called multiple times. + tool_bar.ToggleTool(item.control_id, item.action.checked) + checked = checked or item.action.checked # Every item in a radio group MUST be 'radio' style, so we # can just skip to the next group. @@ -232,4 +240,169 @@ return + +class _AuiToolBar(aui.AuiToolBar): + """ The toolkit-specific tool bar implementation for AUI windows. """ + + ########################################################################### + # 'object' interface. + ########################################################################### + + def __init__(self, tool_bar_manager, parent, id, style): + """ Constructor. """ + + aui.AuiToolBar.__init__(self, parent, -1, style=style) + + # Listen for changes to the tool bar manager's enablement and + # visibility. + self.tool_bar_manager = tool_bar_manager + + self.tool_bar_manager.on_trait_change( + self._on_tool_bar_manager_enabled_changed, 'enabled' + ) + + self.tool_bar_manager.on_trait_change( + self._on_tool_bar_manager_visible_changed, 'visible' + ) + + # we need to defer hiding tools until first time Realize is called so + # we can get the correct order of the toolbar for reinsertion at the + # correct position + self.initially_hidden_tool_ids = [] + + # map of tool ids to a tuple: position in full toolbar and the + # ToolBarTool itself. Can't keep a weak reference here because once + # removed from the toolbar the item would be garbage collected. + self.tool_map = {} + + return + + def Realize(self): + if len(self.tool_map) == 0: + for pos in range(self.GetToolsCount()): + tool = self.GetToolByPos(pos) + self.tool_map[tool.GetId()] = (pos, tool) + aui.AuiToolBar.Realize(self) + if len(self.initially_hidden_tool_ids) > 0: + for tool_id in self.initially_hidden_tool_ids: + self.RemoveTool(tool_id) + self.initially_hidden_tool_ids = [] + self.ShowTool = self.ShowToolPostRealize + + def ShowTool(self, tool_id, state): + """Used before realization to flag which need to be initially hidden + """ + if not state: + self.initially_hidden_tool_ids.append(tool_id) + + def ShowToolPostRealize(self, tool_id, state): + """Normal ShowTool method, activated after first call to Realize + """ + tool = self.FindById(tool_id) + if state and tool is None: + self.InsertToolInOrder(tool_id) + self.EnableTool(tool_id, True) + self.Realize() + # Update the toolbar in the AUI manager to force toolbar resize + wx.CallAfter(self.tool_bar_manager.controller.task.window._aui_manager.Update) + elif not state and tool is not None: + self.RemoveTool(tool_id) + # Update the toolbar in the AUI manager to force toolbar resize + wx.CallAfter(self.tool_bar_manager.controller.task.window._aui_manager.Update) + + def InsertToolInOrder(self, tool_id): + orig_pos, tool = self.tool_map[tool_id] + for pos in range(self.GetToolsCount()): + existing_tool = self.GetToolByPos(pos) + existing_id = existing_tool.GetId() + existing_orig_pos, _ = self.tool_map[tool_id] + if existing_orig_pos > orig_pos: + break + self.InsertToolItem(pos+1, tool) + + + ##### Additional convenience functions for the normal AGW AUI toolbar + + def AddLabelTool(self, id, label, bitmap, bmpDisabled, kind, shortHelp, + longHelp, clientData): + "The full AddTool() function." + return self.AddTool(id, label, bitmap, bmpDisabled, kind, shortHelp, + longHelp, clientData, None) + + def InsertToolItem(self, pos, tool): + self._items[pos:pos] = [tool] + return tool + + def DeleteTool(self, tool_id): + """ + Removes the specified tool from the toolbar and deletes it. + + :param integer `tool_id`: the :class:`AuiToolBarItem` identifier. + :returns: ``True`` if the tool was deleted, ``False`` otherwise. + :note: Note that it is unnecessary to call :meth:`Realize` for the + change to take place, it will happen immediately. + """ + + tool = self.RemoveTool(tool_id) + if tool is not None: + tool.Destroy() + return True + + return False + + + def RemoveTool(self, tool_id): + """ + Removes the specified tool from the toolbar but doesn't delete it. + + :param integer `tool_id`: the :class:`AuiToolBarItem` identifier. + :returns: ``True`` if the tool was deleted, ``False`` otherwise. + :note: Note that it is unnecessary to call :meth:`Realize` for the + change to take place, it will happen immediately. + """ + + idx = self.GetToolIndex(tool_id) + + if idx >= 0 and idx < len(self._items): + self._items.pop(idx) + self.Realize() + return True + + return False + + FindById = aui.AuiToolBar.FindTool + + GetToolState = aui.AuiToolBar.GetToolToggled + + GetToolsCount = aui.AuiToolBar.GetToolCount + + def GetToolByPos(self, pos): + return self._items[pos] + + def OnSize(self, event): + # Quickly short-circuit if the toolbar isn't realized + if not hasattr(self, '_absolute_min_size'): + return + + aui.AuiToolBar.OnSize(self, event) + + + ########################################################################### + # Trait change handlers. + ########################################################################### + + def _on_tool_bar_manager_enabled_changed(self, obj, trait_name, old, new): + """ Dynamic trait change handler. """ + + obj.controller.task.window._wx_enable_tool_bar(self, new) + + return + + def _on_tool_bar_manager_visible_changed(self, obj, trait_name, old, new): + """ Dynamic trait change handler. """ + + obj.controller.task.window._wx_show_tool_bar(self, new) + + return + #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/action/tool_palette_manager.py python-pyface-6.1.2/pyface/ui/wx/action/tool_palette_manager.py --- python-pyface-4.5.2/pyface/ui/wx/action/tool_palette_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/action/tool_palette_manager.py 2019-05-03 08:18:50.000000000 +0000 @@ -26,7 +26,7 @@ # Local imports. from pyface.image_cache import ImageCache from pyface.action.action_manager import ActionManager -from tool_palette import ToolPalette +from .tool_palette import ToolPalette class ToolPaletteManager(ActionManager): diff -Nru python-pyface-4.5.2/pyface/ui/wx/application_window.py python-pyface-6.1.2/pyface/ui/wx/application_window.py --- python-pyface-4.5.2/pyface/ui/wx/application_window.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/application_window.py 2019-06-14 11:44:07.000000000 +0000 @@ -22,25 +22,18 @@ # Major package imports. import wx - -try: - import wx.aui - AUI = True - -except ImportError: - AUI = False +from pyface.wx.aui import aui, PyfaceAuiManager # Enthought library imports. from pyface.action.api import MenuBarManager, StatusBarManager from pyface.action.api import ToolBarManager -from traits.api import Instance, List, provides, Unicode +from traits.api import Instance, List, on_trait_change, provides, Unicode from pyface.i_application_window import IApplicationWindow from pyface.i_application_window import MApplicationWindow from pyface.image_resource import ImageResource # Local imports. -from window import Window -from system_metrics import SystemMetrics +from .window import Window @provides(IApplicationWindow) @@ -81,7 +74,7 @@ ########################################################################### def _create_contents(self, parent): - panel = wx.Panel(parent, -1) + panel = wx.Panel(parent, -1, name="ApplicationWindow") panel.SetSize((500, 400)) panel.SetBackgroundColour('blue') @@ -102,15 +95,12 @@ def _create_tool_bar(self, parent): tool_bar_managers = self._get_tool_bar_managers() if len(tool_bar_managers) > 0: - if AUI: - for tool_bar_manager in reversed(tool_bar_managers): - tool_bar = tool_bar_manager.create_tool_bar(parent) - self._add_toolbar_to_aui_manager( - tool_bar, tool_bar_manager.name - ) - else: - tool_bar = tool_bar_managers[0].create_tool_bar(parent) - self.control.SetToolBar(tool_bar) + for tool_bar_manager in reversed(tool_bar_managers): + tool_bar = tool_bar_manager.create_tool_bar(parent, aui=True) + self._add_toolbar_to_aui_manager( + tool_bar + ) + self._aui_manager.Update() def _set_window_icon(self): if self.icon is None: @@ -138,29 +128,22 @@ def _create(self): - if AUI: - # fixme: We have to capture the AUI manager as an attribute, - # otherwise it gets garbage collected and we get a core dump... - # Ahh, the sweet smell of open-source ;^() - self._aui_manager = wx.aui.AuiManager() - super(ApplicationWindow, self)._create() - if AUI: - body = self._create_body(self.control) - contents = self._create_contents(body) - body.GetSizer().Add(contents, 1, wx.EXPAND) - body.Fit() + self._aui_manager = PyfaceAuiManager() + self._aui_manager.SetManagedWindow(self.control) - else: - contents = self._create_contents(self.control) + # Keep a reference to the AUI Manager in the control because Panes + # will need to access it in order to lay themselves out + self.control._aui_manager = self._aui_manager + + contents = self._create_contents(self.control) self._create_trim_widgets(self.control) - if AUI: - # Updating the AUI manager actually commits all of the pane's added - # to it (this allows batch updates). - self._aui_manager.Update() + # Updating the AUI manager actually commits all of the pane's added + # to it (this allows batch updates). + self._aui_manager.Update() return @@ -175,16 +158,14 @@ pos=self.position ) - control.SetBackgroundColour(SystemMetrics().dialog_background_color) - - if AUI: - # Let the AUI manager look after the frame. - self._aui_manager.SetManagedWindow(control) + # Mac/Win needs this, otherwise background color is black + attr = control.GetDefaultAttributes() + control.SetBackgroundColour(attr.colBg) return control def destroy(self): - if self.control and AUI: + if self.control: self._aui_manager.UnInit() super(ApplicationWindow, self).destroy() @@ -192,38 +173,24 @@ # Private interface. ########################################################################### - def _add_toolbar_to_aui_manager(self, tool_bar, name='Tool Bar'): + def _add_toolbar_to_aui_manager(self, tool_bar): """ Add a toolbar to the AUI manager. """ - info = wx.aui.AuiPaneInfo() - info.Caption(name) - info.LeftDockable(False) - info.Name(name) - info.RightDockable(False) - info.ToolbarPane() - info.Top() - + info = self._get_tool_bar_pane_info(tool_bar) self._aui_manager.AddPane(tool_bar, info) return - def _create_body(self, parent): - """ Create the body of the frame. """ - - panel = wx.Panel(parent, -1) - sizer = wx.BoxSizer(wx.VERTICAL) - panel.SetSizer(sizer) - - info = wx.aui.AuiPaneInfo() - info.Caption('Body') - info.Dockable(False) - info.Floatable(False) - info.Name('Body') - info.CentrePane() - - self._aui_manager.AddPane(panel, info) + def _get_tool_bar_pane_info(self, tool_bar): + info = aui.AuiPaneInfo() + info.Caption(tool_bar.tool_bar_manager.name) + info.LeftDockable(False) + info.Name(tool_bar.tool_bar_manager.id) + info.RightDockable(False) + info.ToolbarPane() + info.Top() - return panel + return info def _get_tool_bar_managers(self): """ Return all tool bar managers specified for the window. """ @@ -240,35 +207,49 @@ def _wx_enable_tool_bar(self, tool_bar, enabled): """ Enable/Disablea tool bar. """ - if AUI: - # AUI toolbars cannot be enabled/disabled. - pass - - else: - tool_bar.Enable(enabled) + # AUI toolbars cannot be enabled/disabled. return def _wx_show_tool_bar(self, tool_bar, visible): """ Hide/Show a tool bar. """ - if AUI: - pane = self._aui_manager.GetPane(tool_bar.tool_bar_manager.name) - - if visible: - pane.Show() + pane = self._aui_manager.GetPane(tool_bar.tool_bar_manager.id) - else: - pane.Hide() - - self._aui_manager.Update() + if visible: + pane.Show() else: - tool_bar.Show(visible) + # Without this workaround, toolbars know the sizes of other + # hidden toolbars and leave gaps in the toolbar dock + pane.window.Show(False) + self._aui_manager.DetachPane(pane.window) + info = self._get_tool_bar_pane_info(pane.window) + info.Hide() + self._aui_manager.AddPane(pane.window, info) + + self._aui_manager.Update() return #### Trait change handlers ################################################ + + def _menu_bar_manager_changed(self): + if self.control is not None: + self._create_menu_bar(self.control) + + def _status_bar_manager_changed(self, old, new): + if self.control is not None: + if old is not None: + self.control.SetStatusBar(None) + old.remove_status_bar(self.control) + self._create_status_bar(self.control) + + @on_trait_change('tool_bar_manager, tool_bar_managers') + def _update_tool_bar_managers(self): + if self.control is not None: + self._create_tool_bar(self.control) + def _icon_changed(self): self._set_window_icon() diff -Nru python-pyface-4.5.2/pyface/ui/wx/clipboard.py python-pyface-6.1.2/pyface/ui/wx/clipboard.py --- python-pyface-4.5.2/pyface/ui/wx/clipboard.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/clipboard.py 2019-05-03 08:18:50.000000000 +0000 @@ -10,8 +10,8 @@ #------------------------------------------------------------------------------ # Standard library imports -from cStringIO import StringIO -from cPickle import dumps, load, loads +from six.moves import cStringIO as StringIO +from six.moves.cPickle import dumps, load, loads # System library imports import wx @@ -19,6 +19,7 @@ # ETS imports from traits.api import provides from pyface.i_clipboard import IClipboard, BaseClipboard +import six # Data formats PythonObjectFormat = wx.CustomDataFormat('PythonObject') @@ -136,7 +137,7 @@ def _set_file_data(self, data): if cb.Open(): tfo = wx.FileDataObject() - if isinstance(data, basestring): + if isinstance(data, six.string_types): tfo.AddFile(data) else: for filename in data: diff -Nru python-pyface-4.5.2/pyface/ui/wx/confirmation_dialog.py python-pyface-6.1.2/pyface/ui/wx/confirmation_dialog.py --- python-pyface-4.5.2/pyface/ui/wx/confirmation_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/confirmation_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -27,7 +27,7 @@ from pyface.i_confirmation_dialog import IConfirmationDialog, MConfirmationDialog from pyface.constant import CANCEL, YES, NO from pyface.image_resource import ImageResource -from dialog import Dialog +from .dialog import Dialog @provides(IConfirmationDialog) @@ -60,7 +60,7 @@ ########################################################################### def _create_buttons(self, parent): - sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer = wx.StdDialogButtonSizer() # 'YES' button. if self.yes_label: @@ -72,7 +72,7 @@ if self.default == YES: yes.SetDefault() wx.EVT_BUTTON(parent, wx.ID_YES, self._on_yes) - sizer.Add(yes) + sizer.AddButton(yes) # 'NO' button. if self.no_label: @@ -84,7 +84,7 @@ if self.default == NO: no.SetDefault() wx.EVT_BUTTON(parent, wx.ID_NO, self._on_no) - sizer.Add(no, 0, wx.LEFT, 10) + sizer.AddButton(no) if self.cancel: # 'Cancel' button. @@ -98,8 +98,9 @@ cancel.SetDefault() wx.EVT_BUTTON(parent, wx.ID_CANCEL, self._wx_on_cancel) - sizer.Add(cancel, 0, wx.LEFT, 10) + sizer.AddButton(cancel) + sizer.Realize() return sizer def _create_dialog_area(self, parent): diff -Nru python-pyface-4.5.2/pyface/ui/wx/dialog.py python-pyface-6.1.2/pyface/ui/wx/dialog.py --- python-pyface-4.5.2/pyface/ui/wx/dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -27,7 +27,7 @@ # Local imports. from pyface.i_dialog import IDialog, MDialog from pyface.constant import OK, CANCEL, YES, NO -from window import Window +from .window import Window # Map wx dialog related constants to the pyface equivalents. @@ -76,7 +76,7 @@ ########################################################################### def _create_buttons(self, parent): - sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer = wx.StdDialogButtonSizer() # The 'OK' button. if self.ok_label: @@ -87,7 +87,7 @@ self._wx_ok = ok = wx.Button(parent, wx.ID_OK, label) ok.SetDefault() wx.EVT_BUTTON(parent, wx.ID_OK, self._wx_on_ok) - sizer.Add(ok) + sizer.AddButton(ok) # The 'Cancel' button. if self.cancel_label: @@ -97,7 +97,7 @@ self._wx_cancel = cancel = wx.Button(parent, wx.ID_CANCEL, label) wx.EVT_BUTTON(parent, wx.ID_CANCEL, self._wx_on_cancel) - sizer.Add(cancel, 0, wx.LEFT, 10) + sizer.AddButton(cancel) # The 'Help' button. if len(self.help_id) > 0: @@ -108,8 +108,9 @@ help = wx.Button(parent, wx.ID_HELP, label) wx.EVT_BUTTON(parent, wx.ID_HELP, self._wx_on_help) - sizer.Add(help, 0, wx.LEFT, 10) + sizer.AddButton(help) + sizer.Realize() return sizer def _create_contents(self, parent): @@ -157,7 +158,8 @@ if self.resizeable: style |= wx.RESIZE_BORDER - return wx.Dialog(parent, -1, self.title, style=style) + return wx.Dialog(parent, -1, self.title, self.position, self.size, + style) #### wx event handlers #################################################### @@ -179,7 +181,4 @@ def _wx_on_help(self, event): """ Called when the 'Help' button is pressed. """ - - print 'Heeeeelllllllllllllpppppppppppppppppppp' - -#### EOF ###################################################################### + pass diff -Nru python-pyface-4.5.2/pyface/ui/wx/directory_dialog.py python-pyface-6.1.2/pyface/ui/wx/directory_dialog.py --- python-pyface-4.5.2/pyface/ui/wx/directory_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/directory_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -25,7 +25,8 @@ # Local imports. from pyface.i_directory_dialog import IDirectoryDialog, MDirectoryDialog -from dialog import Dialog +from .dialog import Dialog +import six @provides(IDirectoryDialog) @@ -59,7 +60,7 @@ def close(self): # Get the path of the chosen directory. - self.path = unicode(self.control.GetPath()) + self.path = six.text_type(self.control.GetPath()) # Let the window close as normal. super(DirectoryDialog, self).close() diff -Nru python-pyface-4.5.2/pyface/ui/wx/expandable_header.py python-pyface-6.1.2/pyface/ui/wx/expandable_header.py --- python-pyface-4.5.2/pyface/ui/wx/expandable_header.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/expandable_header.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,244 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" A header for an entry in a collection of expandables. The header +provides a visual indicator of the current state, a text label, and a +'remove' button. """ +from __future__ import absolute_import + +# Major package imports. +import wx + +# Enthought library imports. +from traits.api import Instance, Event, Str, Bool + +# local imports +from pyface.wx.util.font_helper import new_font_like +from .image_resource import ImageResource +from .widget import Widget + + +class ExpandableHeader(Widget): + """ A header for an entry in a collection of expandables. The header + provides a visual indicator of the current state, a text label, and a + 'remove' button. """ + + # The title of the panel. + title = Str('Panel') + + # The carat image to show when the panel is collapsed. + collapsed_carat_image = Instance(ImageResource, ImageResource('carat_closed')) + # The carat image to show when the panel is expanded. + expanded_carat_image = Instance(ImageResource, ImageResource('carat_open')) + # The backing header image when the mouse is elsewhere + header_bar_image = Instance(ImageResource, + ImageResource('panel_gradient')) + # The backing header image when the mouse is over + header_mouseover_image = Instance(ImageResource, + ImageResource('panel_gradient_over')) + + # The carat image to show when the panel is expanded. + remove_image = Instance(ImageResource, ImageResource('close')) + + # Represents the current state of the button. True means pressed. + state = Bool(False) + + #### Events #### + + # The panel has been expanded or collapsed + panel_expanded = Event + + + _CARAT_X = 4 + _CARAT_Y = 2 + _TEXT_Y = 0 + _TEXT_X_OFFSET = 10 + + ########################################################################### + # 'object' interface. + ########################################################################### + + def __init__(self, parent, container, **traits): + """ Creates the panel. """ + + # Base class constructor. + super(ExpandableHeader, self).__init__(**traits) + + # Create the toolkit-specific control that represents the widget. + self.control = self._create_control(parent) + + self._container = container + return + + ########################################################################### + # Private interface. + ########################################################################### + + def _create_control(self, parent): + """ Create the toolkit-specific control that represents the widget. """ + + collapsed_carat = self.collapsed_carat_image.create_image() + self._collapsed_bmp = collapsed_carat.ConvertToBitmap() + self._carat_w = self._collapsed_bmp.GetWidth() + + expanded_carat = self.expanded_carat_image.create_image() + self._expanded_bmp = expanded_carat.ConvertToBitmap() + + header_bar = self.header_bar_image.create_image() + self._header_bmp = header_bar.ConvertToBitmap() + + header_bar_over = self.header_mouseover_image.create_image() + self._header_mouseover_bmp = header_bar_over.ConvertToBitmap() + + self._background_bmp = self._header_bmp + + close_image = self.remove_image.create_image() + self._remove_bmp = close_image.ConvertToBitmap() + + # create our panel and initialize it appropriately + sizer = wx.BoxSizer(wx.VERTICAL) + panel = wx.Panel(parent, -1, style=wx.CLIP_CHILDREN) + panel.SetSizer(sizer) + panel.SetAutoLayout(True) + + # needed on GTK systems for EVT_ERASE_BACKGROUND to work + panel.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) + + # create the remove button + remove = wx.BitmapButton(panel, -1, self._remove_bmp, style=0, + pos=(-1, 3)) + sizer.Add(remove, 0, wx.ALIGN_RIGHT, 5) + + # Create a suitable font. + self._font = new_font_like(wx.NORMAL_FONT, + point_size=wx.NORMAL_FONT.GetPointSize()- 1) + + height = self._get_preferred_height(parent, self.title, self._font) + panel.SetSize((-1, height)) + + wx.EVT_ERASE_BACKGROUND(panel, self._on_erase_background) + wx.EVT_ENTER_WINDOW(panel, self._on_enter_leave) + wx.EVT_LEAVE_WINDOW(panel, self._on_enter_leave) + wx.EVT_LEFT_DOWN(panel, self._on_down) + wx.EVT_RIGHT_DOWN(panel, self._on_down) + + wx.EVT_BUTTON(panel, remove.GetId(), self._on_remove) + + return panel + + def _get_preferred_height(self, parent, text, font): + """ Calculates the preferred height of the widget. """ + + dc = wx.MemoryDC() + + dc.SetFont(font) + text_w, text_h = dc.GetTextExtent(text) + text_h = text_h + self._TEXT_Y + + # add in width of buttons + carat_h = self._collapsed_bmp.GetHeight() + self._CARAT_Y + + return max(text_h, carat_h) + + def _draw_carat_button(self, dc): + """ Draws the button at the correct coordinates. """ + + if self.state: + bmp = self._expanded_bmp + else: + bmp = self._collapsed_bmp + + dc.DrawBitmap(bmp, self._CARAT_X, self._CARAT_Y, True) + + return + + def _tile_background_image(self, dc, width, height): + """ Tiles the background image. """ + + w = self._background_bmp.GetWidth() + h = self._background_bmp.GetHeight() + + x = 0 + while x < width: + y = 0 + while y < height: + dc.DrawBitmap(self._background_bmp, x, y) + + y = y + h + + x = x + w + + return + + def _draw_title(self, dc): + """ Draws the text label for the header. """ + dc.SetFont(self._font) + + # Render the text. + dc.DrawText(self.title, self._carat_w + self._TEXT_X_OFFSET, + self._TEXT_Y) + + def _draw(self, dc): + """ Draws the control. """ + + size = self.control.GetClientSize() + + # Tile the background image. + self._tile_background_image(dc, size.width, size.height) + + self._draw_title(dc) + + # Draw the carat button + self._draw_carat_button(dc) + + return + + ########################################################################### + # wx event handlers. + ########################################################################### + + def _on_erase_background(self, event): + """ Called when the background of the panel is erased. """ + + #print 'ImageButton._on_erase_background' + dc = event.GetDC() + self._draw(dc) + return + + def _on_enter_leave(self, event): + """ Called when button is pressed. """ + + #print 'ExpandableHeader._on_enter_leave' + if event.Entering(): + self._background_bmp = self._header_mouseover_bmp + else: + self._background_bmp = self._header_bmp + + self.control.Refresh() + event.Skip() + + def _on_down(self, event): + """ Called when button is pressed. """ + + #print 'ImageButton._on_down' + self.state = not self.state + self.control.Refresh() + + # fire an event so any listeners can pick up the change + self.panel_expanded = self + event.Skip() + + def _on_remove(self, event): + """ Called when remove button is pressed. """ + + self._container.remove_panel(self.title) diff -Nru python-pyface-4.5.2/pyface/ui/wx/expandable_panel.py python-pyface-6.1.2/pyface/ui/wx/expandable_panel.py --- python-pyface-4.5.2/pyface/ui/wx/expandable_panel.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/expandable_panel.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,160 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" A Layered panel. """ +from __future__ import absolute_import + +# Major package imports. +import wx + +from traits.api import Instance + +# Local imports. +from .expandable_header import ExpandableHeader +from .image_resource import ImageResource +from .widget import Widget + + +class ExpandablePanel(Widget): + """ An expandable panel. """ + + # The default style. + STYLE = wx.CLIP_CHILDREN + + collapsed_image = Instance(ImageResource, ImageResource('mycarat1')) + expanded_image = Instance(ImageResource, ImageResource('mycarat2')) + + ########################################################################### + # 'object' interface. + ########################################################################### + + def __init__(self, parent, **traits): + """ Creates a new LayeredPanel. """ + + # Base class constructor. + super(ExpandablePanel, self).__init__(**traits) + + # Create the toolkit-specific control that represents the widget. + self.control = self._create_control(parent) + + # The layers in the panel. + # + # { str name : wx.Window layer } + self._layers = {} + self._headers = {} + + return + + ########################################################################### + # 'Expandale' interface. + ########################################################################### + + def add_panel(self, name, layer): + """ Adds a layer with the specified name. + + All layers are hidden when they are added. Use 'show_layer' to make a + layer visible. + + """ + + parent = self.control + sizer = self.control.GetSizer() + + # Add the heading text. + header = self._create_header(parent, text=name) + sizer.Add(header, 0, wx.EXPAND) + + # Add the layer to our sizer. + sizer.Add(layer, 1, wx.EXPAND) + + # All layers are hidden when they are added. Use 'show_layer' to make + # a layer visible. + sizer.Show(layer, False) + + # fixme: Should we warn if a layer is being overridden? + self._layers[name] = layer + + return layer + + def remove_panel(self, name): + """ Removes a layer and its header from the container.""" + + if name not in self._layers: + return + + sizer = self.control.GetSizer() + panel = self._layers[name] + header = self._headers[name] + sizer.Remove(panel) + panel.Destroy() + sizer.Remove(header) + header.Destroy() + + sizer.Layout() + + return + + ########################################################################### + # Private interface. + ########################################################################### + + def _create_control(self, parent): + """ Create the toolkit-specific control that represents the widget. """ + + panel = wx.Panel(parent, -1, style=self.STYLE) + sizer = wx.BoxSizer(wx.VERTICAL) + panel.SetSizer(sizer) + panel.SetAutoLayout(True) + + return panel + + def _create_header(self, parent, text): + """ Creates a panel header. """ + + sizer = wx.BoxSizer(wx.HORIZONTAL) + panel = wx.Panel(parent, -1, style=wx.CLIP_CHILDREN) + panel.SetSizer(sizer) + panel.SetAutoLayout(True) + + # Add the panel header. + heading = ExpandableHeader(panel, self, + title = text) + sizer.Add(heading.control, 1, wx.EXPAND) + + heading.on_trait_change(self._on_button, 'panel_expanded') + + # Resize the panel to match the sizer's minimum size. + sizer.Fit(panel) + + # hang onto it for when we destroy + self._headers[text] = panel + + return panel + + #### wx event handlers #################################################### + + def _on_button(self, event): + """ called when one of the expand/contract buttons is pressed. """ + + header = event + name = header.title + visible = header.state + + sizer = self.control.GetSizer() + sizer.Show(self._layers[name], visible) + sizer.Layout() + + # fixme: Errrr, maybe we can NOT do this! + w, h = self.control.GetSize() + self.control.SetSize((w+1, h+1)) + self.control.SetSize((w, h)) diff -Nru python-pyface-4.5.2/pyface/ui/wx/fields/combo_field.py python-pyface-6.1.2/pyface/ui/wx/fields/combo_field.py --- python-pyface-4.5.2/pyface/ui/wx/fields/combo_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/fields/combo_field.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,109 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2017-19, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" The Wx-specific implementation of the combo field class """ + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +import wx + +from traits.api import provides + +from pyface.fields.i_combo_field import IComboField, MComboField +from .field import Field + + +@provides(IComboField) +class ComboField(MComboField, Field): + """ The Wx-specific implementation of the combo field class """ + + # ------------------------------------------------------------------------ + # IWidget interface + # ------------------------------------------------------------------------ + + def _create_control(self, parent): + """ Create the toolkit-specific control that represents the widget. """ + control = wx.Choice(parent, -1) + return control + + # ------------------------------------------------------------------------ + # Private interface + # ------------------------------------------------------------------------ + + def _update_value(self, event): + """ Handle a change to the value from user interaction + """ + # do normal focus event stuff + if isinstance(event, wx.FocusEvent): + event.Skip() + if self.control is not None: + self.value = self.values[event.GetInt()] + + # Toolkit control interface --------------------------------------------- + + def _get_control_value(self): + """ Toolkit specific method to get the control's value. """ + index = self.control.GetSelection() + if index != -1: + return self.values[index] + else: + raise IndexError("no value selected") + + def _get_control_text(self): + """ Toolkit specific method to get the control's text content. """ + index = self.control.GetSelection() + if index != -1: + return self.control.GetString(index) + else: + raise IndexError("no value selected") + + def _set_control_value(self, value): + """ Toolkit specific method to set the control's value. """ + index = self.values.index(value) + self.control.SetSelection(index) + event = wx.CommandEvent(wx.EVT_CHOICE.typeId, self.control.GetId()) + event.SetInt(index) + wx.PostEvent(self.control.GetEventHandler(), event) + + def _observe_control_value(self, remove=False): + """ Toolkit specific method to change the control value observer. """ + if remove: + self.control.Unbind(wx.EVT_CHOICE, handler=self._update_value) + else: + self.control.Bind(wx.EVT_CHOICE, self._update_value) + + def _get_control_text_values(self): + """ Toolkit specific method to get the control's text values. """ + values = [] + for i in range(self.control.GetCount()): + values.append(self.control.GetString(i)) + return values + + def _set_control_values(self, values): + """ Toolkit specific method to set the control's values. """ + current_value = self.value + self.control.Clear() + for i, value in enumerate(values): + item = self.formatter(value) + if isinstance(item, tuple): + image, text = item + else: + text = item + self.control.Insert(text, i, value) + + if current_value in values: + self._set_control_value(current_value) + else: + self._set_control_value(self.value) diff -Nru python-pyface-4.5.2/pyface/ui/wx/fields/field.py python-pyface-6.1.2/pyface/ui/wx/fields/field.py --- python-pyface-4.5.2/pyface/ui/wx/fields/field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/fields/field.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,88 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2017-19, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" The Wx-specific implementation of the text field class """ + +from __future__ import absolute_import, print_function, unicode_literals + +from traits.api import Any, Instance, Unicode, provides + +import wx + +from pyface.fields.i_field import IField, MField +from pyface.ui.wx.widget import Widget + + +@provides(IField) +class Field(MField, Widget): + """ The Wxspecific implementation of the field class + + This is an abstract class which is not meant to be instantiated. + """ + + #: The value held by the field. + value = Any + + #: A tooltip for the field. + tooltip = Unicode + + #: An optional context menu for the field. + context_menu = Instance('pyface.action.menu_manager.MenuManager') + + # ------------------------------------------------------------------------ + # IField interface + # ------------------------------------------------------------------------ + + def _initialize_control(self): + """ Perform any toolkit-specific initialization for the control. """ + self.control.SetToolTipString(self.tooltip) + self.control.Enable(self.enabled) + self.control.Show(self.visible) + + # ------------------------------------------------------------------------ + # IWidget interface + # ------------------------------------------------------------------------ + + def _create(self): + super(Field, self)._create() + self._add_event_listeners() + + def destroy(self): + self._remove_event_listeners() + super(Field, self).destroy() + + # ------------------------------------------------------------------------ + # Private interface + # ------------------------------------------------------------------------ + + def _get_control_tooltip(self): + """ Toolkit specific method to get the control's tooltip. """ + return self.control.GetToolTipString() + + def _set_control_tooltip(self, tooltip): + """ Toolkit specific method to set the control's tooltip. """ + self.control.SetToolTipString(tooltip) + + def _observe_control_context_menu(self, remove=False): + """ Toolkit specific method to change the control menu observer. """ + if remove: + self.control.Unbind(wx.EVT_CONTEXT_MENU, + handler=self._handle_context_menu) + else: + self.control.Bind(wx.EVT_CONTEXT_MENU, self._handle_context_menu) + + def _handle_control_context_menu(self, event): + """ Signal handler for displaying context menu. """ + if self.control is not None and self.context_menu is not None: + menu = self.context_menu.create_menu(self.control) + self.control.PopupMenu(menu) diff -Nru python-pyface-4.5.2/pyface/ui/wx/fields/spin_field.py python-pyface-6.1.2/pyface/ui/wx/fields/spin_field.py --- python-pyface-4.5.2/pyface/ui/wx/fields/spin_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/fields/spin_field.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,69 @@ +# Copyright (c) 2017-19, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: + +""" The Wx-specific implementation of the spin field class """ + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +import wx + +from traits.api import provides + +from pyface.fields.i_spin_field import ISpinField, MSpinField +from .field import Field + + +@provides(ISpinField) +class SpinField(MSpinField, Field): + """ The Wx-specific implementation of the spin field class """ + + # ------------------------------------------------------------------------ + # IWidget interface + # ------------------------------------------------------------------------ + + def _create_control(self, parent): + """ Create the toolkit-specific control that represents the widget. """ + + control = wx.SpinCtrl(parent, style=wx.TE_PROCESS_ENTER) + return control + + # ------------------------------------------------------------------------ + # Private interface + # ------------------------------------------------------------------------ + + def _get_control_value(self): + """ Toolkit specific method to get the control's value. """ + return self.control.GetValue() + + def _set_control_value(self, value): + """ Toolkit specific method to set the control's value. """ + self.control.SetValue(value) + event = wx.SpinEvent(wx.EVT_SPINCTRL.typeId, self.control.GetId()) + event.SetInt(value) + wx.PostEvent(self.control.GetEventHandler(), event) + + def _observe_control_value(self, remove=False): + """ Toolkit specific method to change the control value observer. """ + if remove: + self.control.Unbind(wx.EVT_SPINCTRL, handler=self._update_value) + else: + self.control.Bind(wx.EVT_SPINCTRL, self._update_value) + + def _get_control_bounds(self): + """ Toolkit specific method to get the control's bounds. """ + return (self.control.GetMin(), self.control.GetMax()) + + def _set_control_bounds(self, bounds): + """ Toolkit specific method to set the control's bounds. """ + self.control.SetRange(*bounds) diff -Nru python-pyface-4.5.2/pyface/ui/wx/fields/text_field.py python-pyface-6.1.2/pyface/ui/wx/fields/text_field.py --- python-pyface-4.5.2/pyface/ui/wx/fields/text_field.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/fields/text_field.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,100 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2017-19, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" The Wx-specific implementation of the text field class """ + +from __future__ import print_function, absolute_import + +import wx + +from traits.api import provides + +from pyface.fields.i_text_field import ITextField, MTextField +from .field import Field + + +@provides(ITextField) +class TextField(MTextField, Field): + """ The Wx-specific implementation of the text field class """ + + # ------------------------------------------------------------------------ + # IWidget interface + # ------------------------------------------------------------------------ + + def _create_control(self, parent): + """ Create the toolkit-specific control that represents the widget. """ + + style = wx.TE_PROCESS_ENTER + if self.echo == 'password': + style |= wx.TE_PASSWORD + + control = wx.TextCtrl(parent, -1, value=self.value, style=style) + return control + + # ------------------------------------------------------------------------ + # Private interface + # ------------------------------------------------------------------------ + + def _update_value(self, event): + # do normal focus event stuff + if isinstance(event, wx.FocusEvent): + event.Skip() + if self.control is not None: + self.value = self.control.GetValue() + + def _get_control_value(self): + """ Toolkit specific method to get the control's value. """ + return self.control.GetValue() + + def _set_control_value(self, value): + """ Toolkit specific method to set the control's value. """ + self.control.SetValue(value) + + def _observe_control_value(self, remove=False): + """ Toolkit specific method to change the control value observer. """ + if remove: + self.control.Unbind(wx.EVT_TEXT, handler=self._update_value) + else: + self.control.Bind(wx.EVT_TEXT, self._update_value) + + def _get_control_placeholder(self): + """ Toolkit specific method to set the control's placeholder. """ + return self.control.GetHint() + + def _set_control_placeholder(self, placeholder): + """ Toolkit specific method to set the control's placeholder. """ + self.control.SetHint(placeholder) + + def _get_control_echo(self): + """ Toolkit specific method to get the control's echo. """ + return self.echo + + def _set_control_echo(self, echo): + """ Toolkit specific method to set the control's echo. """ + # Can't change echo on Wx after control has been created." + pass + + def _get_control_read_only(self): + """ Toolkit specific method to get the control's read_only state. """ + return not self.control.IsEditable() + + def _set_control_read_only(self, read_only): + """ Toolkit specific method to set the control's read_only state. """ + self.control.SetEditable(not read_only) + + def _observe_control_editing_finished(self, remove=False): + """ Change observation of whether editing is finished. """ + if remove: + self.control.Unbind(wx.EVT_TEXT_ENTER, handler=self._update_value) + else: + self.control.Bind(wx.EVT_TEXT_ENTER, self._update_value) diff -Nru python-pyface-4.5.2/pyface/ui/wx/file_dialog.py python-pyface-6.1.2/pyface/ui/wx/file_dialog.py --- python-pyface-4.5.2/pyface/ui/wx/file_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/file_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -28,7 +28,8 @@ # Local imports. from pyface.i_file_dialog import IFileDialog, MFileDialog -from dialog import Dialog +from .dialog import Dialog +import six @provides(IFileDialog) @@ -74,7 +75,7 @@ def close(self): # Get the path of the chosen directory. - self.path = unicode(self.control.GetPath()) + self.path = six.text_type(self.control.GetPath()) # Work around wx bug throwing exception on cancel of file dialog if len(self.path)>0: self.paths = self.control.GetPaths() @@ -105,11 +106,11 @@ default_filename = self.default_filename if self.action == 'open': - style = wx.OPEN + style = wx.FD_OPEN elif self.action == 'open files': - style = wx.OPEN | wx.MULTIPLE + style = wx.FD_OPEN | wx.FD_MULTIPLE else: - style = wx.SAVE | wx.OVERWRITE_PROMPT + style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT # Create the actual dialog. dialog = wx.FileDialog(parent, self.title, defaultDir=default_directory, diff -Nru python-pyface-4.5.2/pyface/ui/wx/grid/api.py python-pyface-6.1.2/pyface/ui/wx/grid/api.py --- python-pyface-4.5.2/pyface/ui/wx/grid/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/grid/api.py 2019-05-03 08:18:50.000000000 +0000 @@ -11,14 +11,15 @@ # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ -from grid import Grid -from grid_model import GridModel, GridSortEvent -from composite_grid_model import CompositeGridModel -from inverted_grid_model import InvertedGridModel -from simple_grid_model import SimpleGridModel, GridRow, GridColumn -from trait_grid_model import TraitGridModel, TraitGridColumn, \ +from __future__ import absolute_import + +from .grid import Grid +from .grid_model import GridModel, GridSortEvent +from .composite_grid_model import CompositeGridModel +from .inverted_grid_model import InvertedGridModel +from .simple_grid_model import SimpleGridModel, GridRow, GridColumn +from .trait_grid_model import TraitGridModel, TraitGridColumn, \ TraitGridSelection -from grid_cell_renderer import GridCellRenderer +from .grid_cell_renderer import GridCellRenderer #### EOF ###################################################################### - diff -Nru python-pyface-4.5.2/pyface/ui/wx/grid/checkbox_image_renderer.py python-pyface-6.1.2/pyface/ui/wx/grid/checkbox_image_renderer.py --- python-pyface-4.5.2/pyface/ui/wx/grid/checkbox_image_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/grid/checkbox_image_renderer.py 2019-05-03 08:18:50.000000000 +0000 @@ -18,7 +18,7 @@ from pyface.image_resource import ImageResource # local imports -from mapped_grid_cell_image_renderer import MappedGridCellImageRenderer +from .mapped_grid_cell_image_renderer import MappedGridCellImageRenderer checked_image_map = { True: ImageResource('checked'), False: ImageResource('unchecked'), diff -Nru python-pyface-4.5.2/pyface/ui/wx/grid/checkbox_renderer.py python-pyface-6.1.2/pyface/ui/wx/grid/checkbox_renderer.py --- python-pyface-4.5.2/pyface/ui/wx/grid/checkbox_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/grid/checkbox_renderer.py 2019-05-03 08:18:50.000000000 +0000 @@ -13,8 +13,8 @@ #------------------------------------------------------------------------------ # local imports -from checkbox_image_renderer import CheckboxImageRenderer -from grid_cell_renderer import GridCellRenderer +from .checkbox_image_renderer import CheckboxImageRenderer +from .grid_cell_renderer import GridCellRenderer class CheckboxRenderer(GridCellRenderer): diff -Nru python-pyface-4.5.2/pyface/ui/wx/grid/composite_grid_model.py python-pyface-6.1.2/pyface/ui/wx/grid/composite_grid_model.py --- python-pyface-4.5.2/pyface/ui/wx/grid/composite_grid_model.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/grid/composite_grid_model.py 2019-05-03 08:18:50.000000000 +0000 @@ -16,7 +16,7 @@ from traits.api import Dict, List, Trait # local imports -from grid_model import GridModel, GridRow +from .grid_model import GridModel, GridRow class CompositeGridModel(GridModel): """ A CompositeGridModel is a model whose underlying data is diff -Nru python-pyface-4.5.2/pyface/ui/wx/grid/edit_image_renderer.py python-pyface-6.1.2/pyface/ui/wx/grid/edit_image_renderer.py --- python-pyface-4.5.2/pyface/ui/wx/grid/edit_image_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/grid/edit_image_renderer.py 2019-05-03 08:18:50.000000000 +0000 @@ -16,7 +16,7 @@ from pyface.image_resource import ImageResource # Local import -from grid_cell_image_renderer import GridCellImageRenderer +from .grid_cell_image_renderer import GridCellImageRenderer class EditImageRenderer(GridCellImageRenderer): image = ImageResource('table_edit') diff -Nru python-pyface-4.5.2/pyface/ui/wx/grid/edit_renderer.py python-pyface-6.1.2/pyface/ui/wx/grid/edit_renderer.py --- python-pyface-4.5.2/pyface/ui/wx/grid/edit_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/grid/edit_renderer.py 2019-05-03 08:18:50.000000000 +0000 @@ -12,8 +12,8 @@ # Description: #------------------------------------------------------------------------------ -from edit_image_renderer import EditImageRenderer -from grid_cell_renderer import GridCellRenderer +from .edit_image_renderer import EditImageRenderer +from .grid_cell_renderer import GridCellRenderer class EditRenderer(GridCellRenderer): diff -Nru python-pyface-4.5.2/pyface/ui/wx/grid/grid.py python-pyface-6.1.2/pyface/ui/wx/grid/grid.py --- python-pyface-4.5.2/pyface/ui/wx/grid/grid.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/grid/grid.py 2019-05-03 08:18:50.000000000 +0000 @@ -28,18 +28,18 @@ from wx import TheClipboard # Enthought library imports -from pyface.api import Sorter, Widget +from pyface.api import Widget from pyface.timer.api import do_later from traits.api import Bool, Color, Enum, Event, Font, Instance, Int, \ - List, Trait, Undefined + Trait, Undefined from pyface.wx.drag_and_drop import PythonDropSource, \ PythonDropTarget, PythonObject -from pyface.wx.drag_and_drop import clipboard as enClipboard -from traitsui.wx.dnd_editor import FileDropSource +from pyface.wx.drag_and_drop import clipboard as enClipboard, FileDropSource # local imports -from grid_model import GridModel -from combobox_focus_handler import ComboboxFocusHandler +from .grid_model import GridModel +from .combobox_focus_handler import ComboboxFocusHandler +import six # Is this code running on MS Windows? is_win32 = (sys.platform == 'win32') @@ -513,8 +513,8 @@ font = self.default_label_font if font is None: - font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) - font.SetWeight(wx.BOLD) + font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) + font.SetWeight(wx.FONTWEIGHT_BOLD) self._grid.SetLabelFont(font) @@ -737,7 +737,7 @@ evt.Skip() if evt.Dragging() and not evt.ControlDown(): data = self.__get_drag_value() - if isinstance(data, basestring): + if isinstance(data, six.string_types): file = abspath(data) if exists(file): FileDropSource(self._grid, file) @@ -1396,11 +1396,11 @@ wdx = 0.0 widths = [] cached = getattr( self, '_cached_widths', None ) - current = [ grid.GetColSize( i ) for i in xrange( n ) ] + current = [ grid.GetColSize( i ) for i in range( n ) ] if (cached is None) or (len( cached ) != n): self._cached_widths = cached = [ None ] * n - for i in xrange( n ): + for i in range( n ): cw = cached[i] if ((cw is None) or (-cw == current[i]) or # hack: For some reason wx always seems to adjust column 0 by @@ -1572,12 +1572,12 @@ if row == self._grid._current_sorted_row: if self._grid._row_sort_reversed: if is_win32: - ulabel = unicode(label, 'ascii') + u' \u00ab' + ulabel = six.text_type(label, 'ascii') + u' \u00ab' label = ulabel.encode('latin-1') else: label += ' <<' elif is_win32: - ulabel = unicode(label, 'ascii') + u' \u00bb' + ulabel = six.text_type(label, 'ascii') + u' \u00bb' label = ulabel.encode('latin-1') else: label += ' >>' @@ -1592,12 +1592,12 @@ if col == self._grid._current_sorted_col: if self._grid._col_sort_reversed: if is_win32: - ulabel = unicode(label, 'ascii') + u' \u00ab' + ulabel = six.text_type(label, 'ascii') + u' \u00ab' label = ulabel.encode('latin-1') else: label += ' <<' elif is_win32: - ulabel = unicode(label, 'ascii') + u' \u00bb' + ulabel = six.text_type(label, 'ascii') + u' \u00bb' label = ulabel.encode('latin-1') else: label += ' >>' @@ -1771,7 +1771,7 @@ # Dispose of the editors in the cache after a brief delay, so as # to allow completion of the current event: - do_later( self._editor_dispose, self._editor_cache.values() ) + do_later( self._editor_dispose, list(self._editor_cache.values()) ) self._editor_cache = {} self._renderer_cache = {} diff -Nru python-pyface-4.5.2/pyface/ui/wx/grid/inverted_grid_model.py python-pyface-6.1.2/pyface/ui/wx/grid/inverted_grid_model.py --- python-pyface-4.5.2/pyface/ui/wx/grid/inverted_grid_model.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/grid/inverted_grid_model.py 2019-05-03 08:18:50.000000000 +0000 @@ -7,7 +7,7 @@ from traits.api import Instance # local imports -from grid_model import GridModel +from .grid_model import GridModel class InvertedGridModel(GridModel): """ An adapter model that inverts all of its row/column targets. Use diff -Nru python-pyface-4.5.2/pyface/ui/wx/grid/mapped_grid_cell_image_renderer.py python-pyface-6.1.2/pyface/ui/wx/grid/mapped_grid_cell_image_renderer.py --- python-pyface-4.5.2/pyface/ui/wx/grid/mapped_grid_cell_image_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/grid/mapped_grid_cell_image_renderer.py 2019-05-03 08:18:50.000000000 +0000 @@ -15,7 +15,7 @@ text displayed in the same way the standard string renderer normally would, all data retrieved from specified value maps. """ -from grid_cell_image_renderer import GridCellImageRenderer +from .grid_cell_image_renderer import GridCellImageRenderer class MappedGridCellImageRenderer(GridCellImageRenderer): """ Maps data values to image and text. """ @@ -37,7 +37,7 @@ value = self._get_value(grid, row, col) - if self.image_map.has_key(value): + if value in self.image_map: result = self.image_map[value] else: result = None @@ -51,7 +51,7 @@ value = self._get_value(grid, row, col) - if self.text_map.has_key(value): + if value in self.text_map: result = self.text_map[value] else: result = None diff -Nru python-pyface-4.5.2/pyface/ui/wx/grid/simple_grid_model.py python-pyface-6.1.2/pyface/ui/wx/grid/simple_grid_model.py --- python-pyface-4.5.2/pyface/ui/wx/grid/simple_grid_model.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/grid/simple_grid_model.py 2019-05-03 08:18:50.000000000 +0000 @@ -22,7 +22,7 @@ from pyface.wx.drag_and_drop import clipboard as enClipboard # local imports -from grid_model import GridColumn, GridModel, GridRow +from .grid_model import GridColumn, GridModel, GridRow class SimpleGridModel(GridModel): """ A SimpleGridModel simply builds a table from a 2-dimensional @@ -301,4 +301,3 @@ #### EOF #################################################################### - diff -Nru python-pyface-4.5.2/pyface/ui/wx/grid/tests/composite_grid_model_test_case.py python-pyface-6.1.2/pyface/ui/wx/grid/tests/composite_grid_model_test_case.py --- python-pyface-4.5.2/pyface/ui/wx/grid/tests/composite_grid_model_test_case.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/grid/tests/composite_grid_model_test_case.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,9 +1,15 @@ import unittest -from pyface.ui.wx.grid.api \ - import CompositeGridModel, GridRow, GridColumn, SimpleGridModel +try: + from pyface.ui.wx.grid.api \ + import CompositeGridModel, GridRow, GridColumn, SimpleGridModel +except ImportError: + wx_available = False +else: + wx_available = True +@unittest.skipUnless(wx_available, "Wx is not available") class CompositeGridModelTestCase( unittest.TestCase ): def setUp(self): diff -Nru python-pyface-4.5.2/pyface/ui/wx/grid/tests/simple_grid_model_test_case.py python-pyface-6.1.2/pyface/ui/wx/grid/tests/simple_grid_model_test_case.py --- python-pyface-4.5.2/pyface/ui/wx/grid/tests/simple_grid_model_test_case.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/grid/tests/simple_grid_model_test_case.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,9 +1,15 @@ import unittest -from pyface.ui.wx.grid.api \ - import GridRow, GridColumn, SimpleGridModel +try: + from pyface.ui.wx.grid.api \ + import GridRow, GridColumn, SimpleGridModel +except ImportError: + wx_available = False +else: + wx_available = True +@unittest.skipUnless(wx_available, "Wx is not available") class CompositeGridModelTestCase( unittest.TestCase ): def setUp(self): diff -Nru python-pyface-4.5.2/pyface/ui/wx/grid/trait_grid_cell_adapter.py python-pyface-6.1.2/pyface/ui/wx/grid/trait_grid_cell_adapter.py --- python-pyface-4.5.2/pyface/ui/wx/grid/trait_grid_cell_adapter.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/grid/trait_grid_cell_adapter.py 2019-05-03 08:18:50.000000000 +0000 @@ -18,9 +18,6 @@ from wx.grid import PyGridCellEditor from wx import SIZE_ALLOW_MINUS_ONE -# Enthought library imports -from traitsui.api import UI, default_handler - # Local imports: from combobox_focus_handler import ComboboxFocusHandler @@ -64,6 +61,8 @@ def Create(self, parent, id, evtHandler): """ Called to create the control, which must derive from wxControl. """ + from traitsui.api import UI, default_handler + # If the editor has already been created, ignore the request: if hasattr( self, '_control' ): return @@ -206,7 +205,11 @@ if isinstance(control, wx.TextCtrl): control.SetSelection(-1, -1) - def EndEdit(self, row, col, grid): + def EndEdit(self, *args): + """ Validate the input data. """ + return True # Pass on all data to ApplyEdit + + def ApplyEdit(self, row, col, grid): """ Do anything necessary to complete the editing. """ self._control.Show(False) @@ -269,4 +272,3 @@ self._editor.dispose() #### EOF ###################################################################### - diff -Nru python-pyface-4.5.2/pyface/ui/wx/grid/trait_grid_model.py python-pyface-6.1.2/pyface/ui/wx/grid/trait_grid_model.py --- python-pyface-4.5.2/pyface/ui/wx/grid/trait_grid_model.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/grid/trait_grid_model.py 2019-05-31 13:42:40.000000000 +0000 @@ -19,12 +19,13 @@ from that object gets a column.""" # Enthought library imports +from __future__ import print_function from traits.api import Any, Bool, Callable, Dict, Function, HasTraits, \ Int, List, Str, Trait, TraitError, Type # local imports -from grid_model import GridColumn, GridModel, GridSortEvent -from trait_grid_cell_adapter import TraitGridCellAdapter +from .grid_model import GridColumn, GridModel, GridSortEvent +from .trait_grid_cell_adapter import TraitGridCellAdapter # The classes below are part of the table specification. class TraitGridColumn(GridColumn): @@ -234,7 +235,7 @@ self.data.reverse() # now fire an event to tell the grid we're sorted - print 'firing sort event' + print('firing sort event') self.column_sorted = GridSortEvent(index = col, reversed = reverse) return @@ -386,7 +387,7 @@ formats = self.__get_column_formats(col) if value is not None and formats is not None and \ - formats.has_key(type(value)) and \ + type(value) in formats and \ formats[type(value)] is not None: try: format = formats[type(value)] @@ -702,4 +703,3 @@ return #### EOF #################################################################### - diff -Nru python-pyface-4.5.2/pyface/ui/wx/gui.py python-pyface-6.1.2/pyface/ui/wx/gui.py --- python-pyface-4.5.2/pyface/ui/wx/gui.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/gui.py 2019-07-20 11:46:59.000000000 +0000 @@ -63,42 +63,36 @@ # 'GUI' class interface. ########################################################################### + @classmethod def invoke_after(cls, millisecs, callable, *args, **kw): - wx.FutureCall(millisecs, callable, *args, **kw) - - invoke_after = classmethod(invoke_after) + wx.CallLater(millisecs, callable, *args, **kw) + @classmethod def invoke_later(cls, callable, *args, **kw): wx.CallAfter(callable, *args, **kw) - invoke_later = classmethod(invoke_later) - + @classmethod def set_trait_after(cls, millisecs, obj, trait_name, new): - wx.FutureCall(millisecs, setattr, obj, trait_name, new) - - set_trait_after = classmethod(set_trait_after) + wx.CallLater(millisecs, setattr, obj, trait_name, new) + @classmethod def set_trait_later(cls, obj, trait_name, new): wx.CallAfter(setattr, obj, trait_name, new) - set_trait_later = classmethod(set_trait_later) - + @staticmethod def process_events(allow_user_events=True): if allow_user_events: wx.GetApp().Yield(True) else: wx.SafeYield() - process_events = staticmethod(process_events) - + @staticmethod def set_busy(busy=True): if busy: GUI._cursor = wx.BusyCursor() else: GUI._cursor = None - set_busy = staticmethod(set_busy) - ########################################################################### # 'GUI' interface. ########################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/heading_text.py python-pyface-6.1.2/pyface/ui/wx/heading_text.py --- python-pyface-4.5.2/pyface/ui/wx/heading_text.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/heading_text.py 2019-05-03 08:18:50.000000000 +0000 @@ -26,8 +26,8 @@ # Local imports. from pyface.i_heading_text import IHeadingText, MHeadingText from pyface.image_resource import ImageResource -from pyface.util.font_helper import new_font_like -from widget import Widget +from pyface.wx.util.font_helper import new_font_like +from .widget import Widget @provides(IHeadingText) diff -Nru python-pyface-4.5.2/pyface/ui/wx/image_button.py python-pyface-6.1.2/pyface/ui/wx/image_button.py --- python-pyface-4.5.2/pyface/ui/wx/image_button.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/image_button.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,266 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: David C. Morrill +# +# Description: Image and text-based pyface button/toolbar/radio button control. +# +#------------------------------------------------------------------------------ +""" An image and text-based control that can be used as a normal, radio or + toolbar button. +""" +from __future__ import absolute_import + +import wx +from numpy import array, fromstring, reshape, ravel, dtype + +from traits.api import Str, Range, Enum, Instance, Event, false + +from .widget import Widget +from .image_resource import ImageResource + +#------------------------------------------------------------------------------- +# Constants: +#------------------------------------------------------------------------------- + +# Text color used when a button is disabled: +DisabledTextColor = wx.Colour( 128, 128, 128 ) + +#------------------------------------------------------------------------------- +# 'ImageButton' class: +#------------------------------------------------------------------------------- + +class ImageButton ( Widget ): + """ An image and text-based control that can be used as a normal, radio or + toolbar button. + """ + + # Pens used to draw the 'selection' marker: + _selectedPenDark = wx.Pen( + wx.SystemSettings.GetColour( wx.SYS_COLOUR_3DSHADOW ), 1, + wx.PENSTYLE_SOLID + ) + + _selectedPenLight = wx.Pen( + wx.SystemSettings.GetColour( wx.SYS_COLOUR_3DHIGHLIGHT ), 1, + wx.PENSTYLE_SOLID + ) + + #--------------------------------------------------------------------------- + # Trait definitions: + #--------------------------------------------------------------------------- + + # The image: + image = Instance( ImageResource, allow_none = True ) + + # The (optional) label: + label = Str + + # Extra padding to add to both the left and right sides: + width_padding = Range( 0, 31, 7 ) + + # Extra padding to add to both the top and bottom sides: + height_padding = Range( 0, 31, 5 ) + + # Presentation style: + style = Enum( 'button', 'radio', 'toolbar', 'checkbox' ) + + # Orientation of the text relative to the image: + orientation = Enum( 'vertical', 'horizontal' ) + + # Is the control selected ('radio' or 'checkbox' style)? + selected = false + + # Fired when a 'button' or 'toolbar' style control is clicked: + clicked = Event + + #--------------------------------------------------------------------------- + # Initializes the object: + #--------------------------------------------------------------------------- + + def __init__ ( self, parent, **traits ): + """ Creates a new image control. + """ + self._image = None + + super( ImageButton, self ).__init__( **traits ) + + # Calculate the size of the button: + idx = idy = tdx = tdy = 0 + if self._image is not None: + idx = self._image.GetWidth() + idy = self._image.GetHeight() + + if self.label != '': + dc = wx.ScreenDC() + dc.SetFont( wx.NORMAL_FONT ) + tdx, tdy = dc.GetTextExtent( self.label ) + + wp2 = self.width_padding + 2 + hp2 = self.height_padding + 2 + if self.orientation == 'horizontal': + self._ix = wp2 + spacing = (idx > 0) * (tdx > 0) * 4 + self._tx = self._ix + idx + spacing + dx = idx + tdx + spacing + dy = max( idy, tdy ) + self._iy = hp2 + ((dy - idy) / 2) + self._ty = hp2 + ((dy - tdy) / 2) + else: + self._iy = hp2 + spacing = (idy > 0) * (tdy > 0) * 2 + self._ty = self._iy + idy + spacing + dx = max( idx, tdx ) + dy = idy + tdy + spacing + self._ix = wp2 + ((dx - idx) / 2) + self._tx = wp2 + ((dx - tdx) / 2) + + # Create the toolkit-specific control: + self._dx = dx + wp2 + wp2 + self._dy = dy + hp2 + hp2 + self.control = wx.Window( parent, -1, + size = wx.Size( self._dx, self._dy ) ) + self.control._owner = self + self._mouse_over = self._button_down = False + + # Set up mouse event handlers: + wx.EVT_ENTER_WINDOW( self.control, self._on_enter_window ) + wx.EVT_LEAVE_WINDOW( self.control, self._on_leave_window ) + wx.EVT_LEFT_DOWN( self.control, self._on_left_down ) + wx.EVT_LEFT_UP( self.control, self._on_left_up ) + wx.EVT_PAINT( self.control, self._on_paint ) + + #--------------------------------------------------------------------------- + # Handles the 'image' trait being changed: + #--------------------------------------------------------------------------- + + def _image_changed ( self, image ): + self._image = self._mono_image = None + if image is not None: + self._img = image.create_image() + self._image = self._img.ConvertToBitmap() + + if self.control is not None: + self.control.Refresh() + + #--------------------------------------------------------------------------- + # Handles the 'selected' trait being changed: + #--------------------------------------------------------------------------- + + def _selected_changed ( self, selected ): + """ Handles the 'selected' trait being changed. + """ + if selected and (self.style == 'radio'): + for control in self.control.GetParent().GetChildren(): + owner = getattr( control, '_owner', None ) + if (isinstance( owner, ImageButton ) and owner.selected and + (owner is not self)): + owner.selected = False + break + + self.control.Refresh() + +#-- wx event handlers ---------------------------------------------------------- + + def _on_enter_window ( self, event ): + """ Called when the mouse enters the widget. """ + + if self.style != 'button': + self._mouse_over = True + self.control.Refresh() + + def _on_leave_window ( self, event ): + """ Called when the mouse leaves the widget. """ + + if self._mouse_over: + self._mouse_over = False + self.control.Refresh() + + def _on_left_down ( self, event ): + """ Called when the left mouse button goes down on the widget. """ + self._button_down = True + self.control.CaptureMouse() + self.control.Refresh() + + def _on_left_up ( self, event ): + """ Called when the left mouse button goes up on the widget. """ + control = self.control + control.ReleaseMouse() + self._button_down = False + wdx, wdy = control.GetClientSizeTuple() + x, y = event.GetX(), event.GetY() + control.Refresh() + if (0 <= x < wdx) and (0 <= y < wdy): + if self.style == 'radio': + self.selected = True + elif self.style == 'checkbox': + self.selected = not self.selected + else: + self.clicked = True + + def _on_paint ( self, event ): + """ Called when the widget needs repainting. + """ + wdc = wx.PaintDC( self.control ) + wdx, wdy = self.control.GetClientSizeTuple() + ox = (wdx - self._dx) / 2 + oy = (wdy - self._dy) / 2 + + disabled = (not self.control.IsEnabled()) + if self._image is not None: + image = self._image + if disabled: + if self._mono_image is None: + img = self._img + data = reshape(fromstring(img.GetData(), dtype('uint8')), + (-1, 3)) * array([[ 0.297, 0.589, 0.114 ]]) + g = data[ :, 0 ] + data[ :, 1 ] + data[ :, 2 ] + data[ :, 0 ] = data[ :, 1 ] = data[ :, 2 ] = g + img.SetData(ravel(data.astype(dtype('uint8'))).tostring()) + img.SetMaskColour(0, 0, 0) + self._mono_image = img.ConvertToBitmap() + self._img = None + image = self._mono_image + wdc.DrawBitmap( image, ox + self._ix, oy + self._iy, True ) + + if self.label != '': + if disabled: + wdc.SetTextForeground( DisabledTextColor ) + wdc.SetFont( wx.NORMAL_FONT ) + wdc.DrawText( self.label, ox + self._tx, oy + self._ty ) + + pens = [ self._selectedPenLight, self._selectedPenDark ] + bd = self._button_down + style = self.style + is_rc = (style in ( 'radio', 'checkbox' )) + if bd or (style == 'button') or (is_rc and self.selected): + if is_rc: + bd = 1 - bd + wdc.SetBrush( wx.TRANSPARENT_BRUSH ) + wdc.SetPen( pens[ bd ] ) + wdc.DrawLine( 1, 1, wdx - 1, 1 ) + wdc.DrawLine( 1, 1, 1, wdy - 1 ) + wdc.DrawLine( 2, 2, wdx - 2, 2 ) + wdc.DrawLine( 2, 2, 2, wdy - 2 ) + wdc.SetPen( pens[ 1 - bd ] ) + wdc.DrawLine( wdx - 2, 2, wdx - 2, wdy - 1 ) + wdc.DrawLine( 2, wdy - 2, wdx - 2, wdy - 2 ) + wdc.DrawLine( wdx - 3, 3, wdx - 3, wdy - 2 ) + wdc.DrawLine( 3, wdy - 3, wdx - 3, wdy - 3 ) + + elif self._mouse_over and (not self.selected): + wdc.SetBrush( wx.TRANSPARENT_BRUSH ) + wdc.SetPen( pens[ bd ] ) + wdc.DrawLine( 0, 0, wdx, 0 ) + wdc.DrawLine( 0, 1, 0, wdy ) + wdc.SetPen( pens[ 1 - bd ] ) + wdc.DrawLine( wdx - 1, 1, wdx - 1, wdy ) + wdc.DrawLine( 1, wdy - 1, wdx - 1, wdy - 1 ) diff -Nru python-pyface-4.5.2/pyface/ui/wx/image_list.py python-pyface-6.1.2/pyface/ui/wx/image_list.py --- python-pyface-4.5.2/pyface/ui/wx/image_list.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/image_list.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,105 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" A cached image list. """ +from __future__ import absolute_import + +# Major package imports. +import wx + +# Local imports +from .image_resource import ImageResource +import six + + +# fixme: rename to 'CachedImageList'?!? +class ImageList(wx.ImageList): + """ A cached image list. """ + + def __init__(self, width, height): + """ Creates a new cached image list. """ + + # Base-class constructor. + wx.ImageList.__init__(self, width, height) + + self._width = width + self._height = height + + # Cache of the indexes of the images in the list! + self._cache = {} # {filename : index} + + return + + ########################################################################### + # 'ImageList' interface. + ########################################################################### + + def GetIndex(self, filename): + """ Returns the index of the specified image. + + The image will be loaded and added to the image list if it is not + already there. + + """ + + # Try the cache first. + index = self._cache.get(filename) + if index is None: + # Were we passed an image resource? + if isinstance(filename, ImageResource): + # Create an image. + image = filename.create_image(size=(self._width, self._height)) + + # If the filename is a string then it is the filename of some kind + # of image (e.g 'foo.gif', 'image/foo.png' etc). + elif isinstance(filename, six.string_types): + # Load the image from the file. + image = wx.Image(filename, wx.BITMAP_TYPE_ANY) + + # Otherwise the filename is *actually* an icon (in our case, + # probably related to a MIME type). + else: + # Create a bitmap from the icon. + bmp = wx.EmptyBitmap(self._width, self._height) + bmp.CopyFromIcon(filename) + + # Turn it into an image so that we can scale it. + image = wx.ImageFromBitmap(bmp) + + # We force all images in the cache to be the same size. + self._scale(image) + + # We also force them to be bitmaps! + bmp = image.ConvertToBitmap() + + # Add the bitmap to the actual list... + index = self.Add(bmp) + + # ... and update the cache. + self._cache[filename] = index + + return index + + ########################################################################### + # Private interface. + ########################################################################### + + def _scale(self, image): + """ Scales the specified image (if necessary). """ + + if image.GetWidth() != self._width or image.GetHeight()!= self._height: + image.Rescale(self._width, self._height) + + return image + +#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/image_resource.py python-pyface-6.1.2/pyface/ui/wx/image_resource.py --- python-pyface-4.5.2/pyface/ui/wx/image_resource.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/image_resource.py 2019-05-03 08:18:50.000000000 +0000 @@ -74,6 +74,22 @@ return icon + def image_size(cls, image): + """ Get the size of a toolkit image + + Parameters + ---------- + image : toolkit image + A toolkit image to compute the size of. + + Returns + ------- + size : tuple + The (width, height) tuple giving the size of the image. + """ + size = image.GetSize() + return size.Get() + ########################################################################### # Private interface. ########################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/image_widget.py python-pyface-6.1.2/pyface/ui/wx/image_widget.py --- python-pyface-4.5.2/pyface/ui/wx/image_widget.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/image_widget.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,243 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" A clickable/draggable widget containing an image. """ +from __future__ import absolute_import + +# Major package imports. +import wx + +# Enthought library imports. +from traits.api import Any, Bool, Event + +# Local imports. +from .widget import Widget + + +class ImageWidget(Widget): + """ A clickable/draggable widget containing an image. """ + + #### 'ImageWidget' interface ############################################## + + # The bitmap. + bitmap = Any + + # Is the widget selected? + selected = Bool(False) + + #### Events #### + + # A key was pressed while the tree is in focus. + key_pressed = Event + + # A node has been activated (ie. double-clicked). + node_activated = Event + + # A drag operation was started on a node. + node_begin_drag = Event + + # A (non-leaf) node has been collapsed. + node_collapsed = Event + + # A (non-leaf) node has been expanded. + node_expanded = Event + + # A left-click occurred on a node. + node_left_clicked = Event + + # A right-click occurred on a node. + node_right_clicked = Event + + #### Private interface #################################################### + + _selected = Any + + ########################################################################### + # 'object' interface. + ########################################################################### + + def __init__ (self, parent, **traits): + """ Creates a new widget. """ + + # Base class constructors. + super(ImageWidget, self).__init__(**traits) + + # Add some padding around the image. + size = (self.bitmap.GetWidth() + 10, self.bitmap.GetHeight() + 10) + + # Create the toolkit-specific control. + self.control = wx.Window(parent, -1, size=size) + self.control.__tag__ = 'hack' + + self._mouse_over = False + self._button_down = False + + # Set up mouse event handlers: + self.control.Bind(wx.EVT_ENTER_WINDOW, self._on_enter_window) + self.control.Bind(wx.EVT_LEAVE_WINDOW, self._on_leave_window) + self.control.Bind(wx.EVT_LEFT_DCLICK, self._on_left_dclick) + self.control.Bind(wx.EVT_LEFT_DOWN, self._on_left_down) + self.control.Bind(wx.EVT_LEFT_UP, self._on_left_up) + self.control.Bind(wx.EVT_PAINT, self._on_paint) + + # Pens used to draw the 'selection' marker: + # ZZZ: Make these class instances when moved to the wx toolkit code. + self._selectedPenDark = wx.Pen( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DSHADOW), 1, + wx.PENSTYLE_SOLID + ) + + self._selectedPenLight = wx.Pen( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DHIGHLIGHT), 1, + wx.PENSTYLE_SOLID + ) + + return + + ########################################################################### + # Private interface. + ########################################################################### + + #### Trait event handlers ################################################# + + def _bitmap_changed(self, bitmap): + """ Called when the widget's bitmap is changed. """ + + if self.control is not None: + self.control.Refresh() + + return + + def _selected_changed(self, selected): + """ Called when the selected state of the widget is changed. """ + + if selected: + for control in self.GetParent().GetChildren(): + if hasattr(control, '__tag__'): + if control.Selected(): + control.Selected(False) + break + + self.Refresh() + + return + + #### wx event handlers #################################################### + + def _on_enter_window(self, event): + """ Called when the mouse enters the widget. """ + + if self._selected is not None: + self._mouse_over = True + self.Refresh() + + return + + def _on_leave_window(self, event): + """ Called when the mouse leaves the widget. """ + + if self._mouse_over: + self._mouse_over = False + self.Refresh() + + return + + def _on_left_dclick(self, event): + """ Called when the left mouse button is double-clicked. """ + + #print 'left dclick' + + event.Skip() + + return + + def _on_left_down ( self, event = None ): + """ Called when the left mouse button goes down on the widget. """ + + #print 'left down' + + if self._selected is not None: + self.CaptureMouse() + self._button_down = True + self.Refresh() + + event.Skip() + + return + + def _on_left_up ( self, event = None ): + """ Called when the left mouse button goes up on the widget. """ + + #print 'left up' + + need_refresh = self._button_down + if need_refresh: + self.ReleaseMouse() + self._button_down = False + + if self._selected is not None: + wdx, wdy = self.GetClientSizeTuple() + x = event.GetX() + y = event.GetY() + if (0 <= x < wdx) and (0 <= y < wdy): + if self._selected != -1: + self.Selected( True ) + elif need_refresh: + self.Refresh() + + return + + if need_refresh: + self.Refresh() + + event.Skip() + + return + + def _on_paint ( self, event = None ): + """ Called when the widget needs repainting. """ + + wdc = wx.PaintDC( self.control ) + wdx, wdy = self.control.GetClientSizeTuple() + bitmap = self.bitmap + bdx = bitmap.GetWidth() + bdy = bitmap.GetHeight() + wdc.DrawBitmap( bitmap, (wdx - bdx) / 2, (wdy - bdy) / 2, True ) + + pens = [ self._selectedPenLight, self._selectedPenDark ] + bd = self._button_down + if self._mouse_over: + wdc.SetBrush( wx.TRANSPARENT_BRUSH ) + wdc.SetPen( pens[ bd ] ) + wdc.DrawLine( 0, 0, wdx, 0 ) + wdc.DrawLine( 0, 1, 0, wdy ) + wdc.SetPen( pens[ 1 - bd ] ) + wdc.DrawLine( wdx - 1, 1, wdx - 1, wdy ) + wdc.DrawLine( 1, wdy - 1, wdx - 1, wdy - 1 ) + + if self._selected == True: + wdc.SetBrush( wx.TRANSPARENT_BRUSH ) + wdc.SetPen( pens[ bd ] ) + wdc.DrawLine( 1, 1, wdx - 1, 1 ) + wdc.DrawLine( 1, 1, 1, wdy - 1 ) + wdc.DrawLine( 2, 2, wdx - 2, 2 ) + wdc.DrawLine( 2, 2, 2, wdy - 2 ) + wdc.SetPen( pens[ 1 - bd ] ) + wdc.DrawLine( wdx - 2, 2, wdx - 2, wdy - 1 ) + wdc.DrawLine( 2, wdy - 2, wdx - 2, wdy - 2 ) + wdc.DrawLine( wdx - 3, 3, wdx - 3, wdy - 2 ) + wdc.DrawLine( 3, wdy - 3, wdx - 3, wdy - 3 ) + + return + +#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/init.py python-pyface-6.1.2/pyface/ui/wx/init.py --- python-pyface-4.5.2/pyface/ui/wx/init.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/init.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,31 +1,48 @@ #------------------------------------------------------------------------------ +# Copyright (c) 2007, Riverbank Computing Limited +# All rights reserved. # -# Copyright (c) 2007, Riverbank Computing Limited -# All rights reserved. -# -# This software is provided without warranty under the terms of the BSD -# license included in enthought/LICENSE.txt and may be redistributed only -# under the conditions described in the aforementioned license. The license -# is also available online at http://www.enthought.com/licenses/BSD.txt +# Copyright (c) 2017, Enthought, Inc. +# All rights reserved. # +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt #------------------------------------------------------------------------------ -# Major package imports. import wx +from traits.trait_notifiers import set_ui_handler, ui_handler + +from pyface.base_toolkit import Toolkit +from .gui import GUI + # Check the version number is late enough. -if wx.VERSION < (2, 6): - raise RuntimeError, "Need wx version 2.6 or higher, but got %s" % str(wx.VERSION) +if wx.VERSION < (2, 8): + raise RuntimeError( + "Need wx version 2.8 or higher, but got %s" % str(wx.VERSION) + ) + # It's possible that it has already been initialised. _app = wx.GetApp() - if _app is None: - _app = wx.PySimpleApp() + _app = wx.App() + + +# stop logging to a modal window by default +# (apps can override by setting a different active target) +_log = wx.LogStderr() +wx.Log.SetActiveTarget(_log) + + +# create the toolkit object +toolkit_object = Toolkit('pyface', 'wx', 'pyface.ui.wx') - # Before we can load any images we have to initialize wxPython's image - # handlers. - wx.InitAllImageHandlers() -#### EOF ###################################################################### +# ensure that Traits has a UI handler appropriate for the toolkit. +if ui_handler is None: + # Tell the traits notification handlers to use this UI handler + set_ui_handler(GUI.invoke_later) diff -Nru python-pyface-4.5.2/pyface/ui/wx/ipython_widget.py python-pyface-6.1.2/pyface/ui/wx/ipython_widget.py --- python-pyface-4.5.2/pyface/ui/wx/ipython_widget.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/ipython_widget.py 2019-05-03 08:18:50.000000000 +0000 @@ -18,7 +18,8 @@ """ # Standard library imports. -import __builtin__ +from __future__ import print_function +import six.moves.builtins import codeop import re import sys @@ -38,7 +39,8 @@ from pyface.wx.drag_and_drop import PythonDropTarget # Local imports. -from widget import Widget +from .widget import Widget +import six # Constants. IPYTHON_VERSION = tuple(map(int, IPython.Release.version_base.split('.'))) @@ -115,10 +117,10 @@ # Suppress all key input, to avoid waiting def my_rawinput(x=None): return '\n' - old_rawinput = __builtin__.raw_input - __builtin__.raw_input = my_rawinput + old_rawinput = six.moves.builtins.raw_input + six.moves.builtins.raw_input = my_rawinput IPythonController.__init__(self, *args, **kwargs) - __builtin__.raw_input = old_rawinput + six.moves.builtins.raw_input = old_rawinput # XXX: This is bugware for IPython bug: # https://bugs.launchpad.net/ipython/+bug/270998 @@ -184,7 +186,7 @@ is_complete = codeop.compile_command(clean_string, "", "exec") self.release_output() - except Exception, e: + except Exception as e: # XXX: Hack: return True so that the # code gets executed and the error captured. is_complete = True @@ -261,7 +263,7 @@ # I am patching this here instead of in the IPython module, but at some # point, this needs to be merged in. if self.debug: - print >>sys.__stdout__, "_popup_completion" , self.input_buffer + print("_popup_completion" , self.input_buffer, file=sys.__stdout__) line = self.input_buffer if (self.AutoCompActive() and line and not line[-1] == '.') \ @@ -271,7 +273,7 @@ offset = len(self._get_completion_text(line)) self.pop_completion(completions, offset=offset) if self.debug: - print >>sys.__stdout__, completions + print(completions, file=sys.__stdout__) def _get_completion_text(self, line): """ Returns the text to be completed by breaking the line at specified @@ -403,7 +405,7 @@ name = 'dragged' if hasattr(obj, 'name') \ - and isinstance(obj.name, basestring) and len(obj.name) > 0: + and isinstance(obj.name, six.string_types) and len(obj.name) > 0: py_name = python_name(obj.name) # Make sure that the name is actually a valid Python identifier. @@ -435,10 +437,10 @@ """ Called whenever a change is made to the text of the document. """ self.key_pressed = KeyPressedEvent( - alt_down = event.m_altDown == 1, - control_down = event.m_controlDown == 1, - shift_down = event.m_shiftDown == 1, - key_code = event.m_keyCode, + alt_down = event.AltDown() == 1, + control_down = event.ControlDown() == 1, + shift_down = event.ShiftDown() == 1, + key_code = event.GetKeyCode(), event = event ) diff -Nru python-pyface-4.5.2/pyface/ui/wx/layered_panel.py python-pyface-6.1.2/pyface/ui/wx/layered_panel.py --- python-pyface-4.5.2/pyface/ui/wx/layered_panel.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/layered_panel.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,179 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" A Layered panel. """ +from __future__ import absolute_import + +# Major package imports. +import wx +from wx.lib.scrolledpanel import ScrolledPanel + +# Enthought library imports. +from traits.api import Any, Str, Int + +# Local imports. +from .widget import Widget + + +class LayeredPanel(Widget): + """ A Layered panel. + + A layered panel contains one or more named layers, with only one layer + visible at any one time (think of a 'tab' control minus the tabs!). Each + layer is a toolkit-specific control. + + """ + + # The default style. + STYLE = wx.CLIP_CHILDREN + + #### "Layered Panel' interface ############################################ + + # The toolkit-specific control of the currently displayed layer. + current_layer = Any + + # The name of the currently displayed layer. + current_layer_name = Str + + # The minimum for the panel, which is the maximum of the minimum + # sizes of the layers + min_width = Int(0) + min_height = Int(0) + + ########################################################################### + # 'object' interface. + ########################################################################### + + def __init__(self, parent, **traits): + """ Creates a new LayeredPanel. """ + + # Base class constructor. + super(LayeredPanel, self).__init__(**traits) + + # Create the toolkit-specific control that represents the widget. + self.control = self._create_control(parent) + + # The layers in the panel. + # + # { str name : wx.Window layer } + self._layers = {} + + return + + ########################################################################### + # 'LayeredPanel' interface. + ########################################################################### + + def add_layer(self, name, layer): + """ Adds a layer with the specified name. + + All layers are hidden when they are added. Use 'show_layer' to make a + layer visible. + + """ + + # Add the layer to our sizer. + sizer = self.control.GetSizer() + sizer.Add(layer, 1, wx.EXPAND) + + # All layers are hidden when they are added. Use 'show_layer' to make + # a layer visible. + sizer.Show(layer, False) + + # fixme: Should we warn if a layer is being overridden? + self._layers[name] = layer + + # fixme: The minimum size stuff that was added for linux broke the + # sizing on Windows (at least for the preference dialog). The + # preference dialog now sets the minimum width and height to -1 so + # that this layout code doesn't get executed. + if self.min_width != -1 or self.min_height != -1: + if layer.GetSizer() is None: + return layer + + min_size = layer.GetSizer().CalcMin() + needs_layout = False + if min_size.GetWidth() > self.min_width: + self.min_width = min_size.GetWidth() + needs_layout = True + if min_size.GetHeight() > self.min_height: + self.min_height = min_size.GetHeight() + needs_layout = True + + if needs_layout: + # Reset our size hints and relayout + self.control.SetSizeHints(self.min_width, self.min_height) + self.control.GetSizer().Layout() + + # fixme: Force our parent to reset it's size hints to its + # minimum + parent = self.control.GetParent() + parent.GetSizer().SetSizeHints(parent) + parent.GetSizer().Layout() + + return layer + + def show_layer(self, name): + """ Shows the layer with the specified name. """ + + # Hide the current layer (if one is displayed). + if self.current_layer is not None: + self._hide_layer(self.current_layer) + + # Show the specified layer. + layer = self._show_layer(name, self._layers[name]) + + return layer + + def has_layer(self, name): + """ Does the panel contain a layer with the specified name? """ + + return name in self._layers + + ########################################################################### + # Private interface. + ########################################################################### + + def _create_control(self, parent): + """ Create the toolkit-specific control that represents the widget. """ + + panel = ScrolledPanel(parent, -1, style=self.STYLE) + sizer = wx.BoxSizer(wx.VERTICAL) + panel.SetSizer(sizer) + panel.SetAutoLayout(True) + panel.SetupScrolling() + + return panel + + def _hide_layer(self, layer): + """ Hides the specified layer. """ + + sizer = self.control.GetSizer() + sizer.Show(layer, False) + sizer.Layout() + + return + + def _show_layer(self, name, layer): + """ Shows the specified layer. """ + + sizer = self.control.GetSizer() + sizer.Show(layer, True) + sizer.Layout() + + self.current_layer = layer + self.current_layer_name = name + + return layer + +#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/list_box.py python-pyface-6.1.2/pyface/ui/wx/list_box.py --- python-pyface-4.5.2/pyface/ui/wx/list_box.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/list_box.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,145 @@ +""" A simple list box widget with a model-view architecture. """ +from __future__ import absolute_import + +# Major package imports. +import wx + +# Enthought library imports. +from traits.api import Event, Instance, Int + +# Local imports. +from pyface.list_box_model import ListBoxModel +from .widget import Widget + + +class ListBox(Widget): + """ A simple list box widget with a model-view architecture. """ + + # The model that provides the data for the list box. + model = Instance(ListBoxModel) + + # The objects currently selected in the list. + selection = Int(-1) + + # Events. + + # An item has been activated. + item_activated = Event + + # Default style. + STYLE = wx.LB_SINGLE | wx.LB_HSCROLL | wx.LB_NEEDED_SB + + + def __init__(self, parent, **traits): + """ Creates a new list box. """ + + # Base-class constructors. + super(ListBox, self).__init__(**traits) + + # Create the widget! + self._create_control(parent) + + # Listen for changes to the model. + self.model.on_trait_change(self._on_model_changed, "list_changed") + + return + + def dispose(self): + self.model.on_trait_change(self._on_model_changed, "list_changed", + remove = True) + self.model.dispose() + return + + ########################################################################### + # 'ListBox' interface. + ########################################################################### + + def refresh(self): + """ Refreshes the list box. """ + + # For now we just clear out the entire list. + self.control.Clear() + + # Populate the list. + self._populate() + + return + + ########################################################################### + # wx event handlers. + ########################################################################### + + def _on_item_selected(self, event): + """ Called when an item in the list is selected. """ + + listbox = event.GetEventObject() + + self.selection = listbox.GetSelection() + + return + + def _on_item_activated(self, event): + """ Called when an item in the list is activated. """ + + listbox = event.GetEventObject() + index = listbox.GetSelection() + + # Trait event notification. + self.item_activated = index + + return + + ########################################################################### + # Trait handlers. + ########################################################################### + + #### Static ############################################################### + + def _selection_changed(self, index): + """ Called when the selected item is changed. """ + + if index != -1: + self.control.SetSelection(index) + + return + + #### Dynamic ############################################################## + + def _on_model_changed(self, event): + """ Called when the model has changed. """ + + # For now we just clear out the entire list. + self.refresh() + + return + + ########################################################################### + # Private interface. + ########################################################################### + + def _create_control(self, parent): + """ Creates the widget. """ + + self.control = wx.ListBox(parent, -1, style = self.STYLE) + + # Wire it up! + wx.EVT_LISTBOX(self.control, self.control.GetId(), + self._on_item_selected) + wx.EVT_LISTBOX_DCLICK(self.control, self.control.GetId(), + self._on_item_activated) + + # Populate the list. + self._populate() + + return + + def _populate(self): + """ Populates the list box. """ + + for index in range(self.model.get_item_count()): + label, item = self.model.get_item_at(index) + self.control.Append(label, item) + + return + +#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/mdi_application_window.py python-pyface-6.1.2/pyface/ui/wx/mdi_application_window.py --- python-pyface-4.5.2/pyface/ui/wx/mdi_application_window.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/mdi_application_window.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,186 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" An MDI top-level application window. """ +from __future__ import absolute_import + +# Major package imports. +import wx + +# Enthought library imports. +from traits.api import Bool, Instance, Int, Tuple + +# Local imports. +from .application_window import ApplicationWindow +from .image_resource import ImageResource + +try: + import wx.aui + AUI = True +except: + AUI = False + + +class MDIApplicationWindow(ApplicationWindow): + """ An MDI top-level application window. + + The application window has support for a menu bar, tool bar and a status + bar (all of which are optional). + + Usage: Create a sub-class of this class and override the protected + '_create_contents' method. + + """ + + #### 'MDIApplicationWindow' interface ##################################### + + # The workarea background image. + background_image = Instance(ImageResource, ImageResource('background')) + + # Should we tile the workarea background image? The alternative is to + # scale it. Be warned that scaling the image allows for 'pretty' images, + # but is MUCH slower than tiling. + tile_background_image = Bool(True) + + # WX HACK FIXME + # UPDATE: wx 2.6.1 does NOT fix this issue. + _wx_offset = Tuple(Int, Int) + + ########################################################################### + # 'MDIApplicationWindow' interface. + ########################################################################### + + def create_child_window(self, title=None, is_mdi=True, float=True): + """ Create a child window. """ + if title is None: + title = self.title + + if is_mdi: + return wx.MDIChildFrame(self.control, -1, title) + else: + if float: + style = wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT + else: + style = wx.DEFAULT_FRAME_STYLE + return wx.Frame(self.control, -1, title, style=style) + + ########################################################################### + # Protected 'Window' interface. + ########################################################################### + + def _create_contents(self, parent): + """ Create the contents of the MDI window. """ + + # Create the 'trim' widgets (menu, tool and status bars etc). + self._create_trim_widgets(self.control) + + # The work-area background image (it can be tiled or scaled). + self._image = self.background_image.create_image() + self._bmp = self._image.ConvertToBitmap() + + # Frame events. + # + # We respond to size events to layout windows around the MDI frame. + wx.EVT_SIZE(self.control, self._on_size) + + # Client window events. + client_window = self.control.GetClientWindow() + wx.EVT_ERASE_BACKGROUND(client_window, self._on_erase_background) + + self._wx_offset = client_window.GetPositionTuple() + + if AUI: + # Let the AUI manager look after the frame. + self._aui_manager.SetManagedWindow(self.control) + + contents = super(MDIApplicationWindow, self)._create_contents(parent) + + return contents + + def _create_control(self, parent): + """ Create the toolkit-specific control that represents the window. """ + + control = wx.MDIParentFrame( + parent, -1, self.title, style=wx.DEFAULT_FRAME_STYLE, + size=self.size, pos=self.position + ) + + return control + + ########################################################################### + # Private interface. + ########################################################################### + + + def _tile_background_image(self, dc, width, height): + """ Tiles the background image. """ + + w = self._bmp.GetWidth() + h = self._bmp.GetHeight() + + x = 0 + while x < width: + y = 0 + while y < height: + dc.DrawBitmap(self._bmp, x, y) + y = y + h + + x = x + w + + return + + def _scale_background_image(self, dc, width, height): + """ Scales the background image. """ + + # Scale the image (if necessary). + image = self._image + if image.GetWidth() != width or image.GetHeight()!= height: + image = self._image.Copy() + image.Rescale(width, height) + + # Convert it to a bitmap and draw it. + dc.DrawBitmap(image.ConvertToBitmap(), 0, 0) + + return + + ##### wx event handlers ################################################### + + def _on_size(self, event): + """ Called when the frame is resized. """ + + wx.LayoutAlgorithm().LayoutMDIFrame(self.control) + + return + + def _on_erase_background(self, event): + """ Called when the background of the MDI client window is erased. """ + + # fixme: Close order... + if self.control is None: + return + + frame = self.control + + dc = event.GetDC() + if not dc: + dc = wx.ClientDC(frame.GetClientWindow()) + + size = frame.GetClientSize() + + # Currently you have two choices, tile the image or scale it. Be + # warned that scaling is MUCH slower than tiling. + if self.tile_background_image: + self._tile_background_image(dc, size.width, size.height) + + else: + self._scale_background_image(dc, size.width, size.height) diff -Nru python-pyface-4.5.2/pyface/ui/wx/message_dialog.py python-pyface-6.1.2/pyface/ui/wx/message_dialog.py --- python-pyface-4.5.2/pyface/ui/wx/message_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/message_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -25,7 +25,7 @@ # Local imports. from pyface.i_message_dialog import IMessageDialog, MMessageDialog -from dialog import Dialog +from .dialog import Dialog # Map the ETS severity to the corresponding wx standard icon. @@ -72,7 +72,13 @@ else: message = self.message - return wx.MessageDialog(parent, message, self.title, - _SEVERITY_TO_ICON_MAP[self.severity] | wx.OK | wx.STAY_ON_TOP) + style = _SEVERITY_TO_ICON_MAP[self.severity] | wx.OK | wx.STAY_ON_TOP + if self.resizeable: + style |= wx.RESIZE_BORDER + + dlg = wx.MessageDialog(parent, message, self.title, style, + self.position) + if self.size != (-1, -1): + dlg.SetSize(self.size) -#### EOF ###################################################################### + return dlg diff -Nru python-pyface-4.5.2/pyface/ui/wx/multi_toolbar_window.py python-pyface-6.1.2/pyface/ui/wx/multi_toolbar_window.py --- python-pyface-4.5.2/pyface/ui/wx/multi_toolbar_window.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/multi_toolbar_window.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,153 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" A top-level application window that supports multiple toolbars. """ +from __future__ import absolute_import + +# Major package imports. +import wx + +# Enthought library imports +from pyface.action.api import ToolBarManager +from traits.api import Trait, TraitDict, TraitEnum, TraitList + +# Local imports +from .application_window import ApplicationWindow + + +class MultiToolbarWindow(ApplicationWindow): + """ A top-level application window that supports multiple toolbars. + + The multi-toolbar window has support for a menu bar, status bar, and + multiple toolbars (all of which are optional). + + """ + + # The toolbars in the order they were added to the window. + _tool_bar_managers = Trait([], TraitList(Trait(ToolBarManager))) + + # Map of toolbar to screen location. + _tool_bar_locations = Trait({}, + TraitDict(Trait(ToolBarManager), + TraitEnum('top', 'bottom', + 'left', 'right'))) + + ########################################################################### + # Protected 'Window' interface. + ########################################################################### + def _create_contents(self, parent): + panel = super(MultiToolbarWindow, self)._create_contents(parent) + self._create_trim_widgets(parent) + + return panel + + def _create_trim_widgets(self, parent): + + # The frame's icon. + self._set_window_icon() + + # Add the (optional) menu bar. + self._create_menu_bar(parent) + + # Add the (optional) status bar. + self._create_status_bar(parent) + + # Add the (optional) tool bars. + self.sizer = self._create_tool_bars(parent) + + return + + def _create_tool_bars(self, parent): + """ Create the tool bars for this window. """ + + if len(self._tool_bar_managers) > 0: + # Create a top level sizer to handle to main layout and attach + # it to the parent frame. + self.main_sizer = sizer = wx.BoxSizer(wx.VERTICAL) + parent.SetSizer(sizer) + parent.SetAutoLayout(True) + + for tool_bar_manager in self._tool_bar_managers: + location = self._tool_bar_locations[tool_bar_manager] + sizer = self._create_tool_bar(parent, sizer, tool_bar_manager, + location) + + return sizer + + return None + + def _create_tool_bar(self, parent, sizer, tool_bar_manager, location): + """ Create and add the toolbar to the parent window at the specified + location. + + Returns the sizer where the remaining content should be added. For + 'top' and 'left' toolbars, we can return the same sizer that contains + the toolbar, because subsequent additions will be added below or to + the right of those toolbars. For 'right' and 'bottom' toolbars, we + create a spacer toolbar to hold the content. + """ + + tool_bar = tool_bar_manager.create_tool_bar(parent) + + if location == 'top': + child_sizer = wx.BoxSizer(wx.VERTICAL) + child_sizer.Add(tool_bar, 0, wx.ALL | wx.ALIGN_LEFT | wx.EXPAND) + sizer.Add(child_sizer, 1, wx.ALL | wx.EXPAND) + + if location == 'bottom': + toolbar_sizer = wx.BoxSizer(wx.VERTICAL) + + # Add the placeholder for the content before adding the toolbar. + child_sizer = self._create_content_spacer(toolbar_sizer) + + # Add the tool bar. + toolbar_sizer.Add(tool_bar, 0, wx.ALL | wx.ALIGN_TOP | wx.EXPAND) + sizer.Add(toolbar_sizer, 1, wx.ALL | wx.EXPAND) + + if location == 'left': + child_sizer = wx.BoxSizer(wx.HORIZONTAL) + child_sizer.Add(tool_bar, 0, wx.ALL | wx.ALIGN_TOP | wx.EXPAND) + sizer.Add(child_sizer, 1, wx.ALL | wx.EXPAND) + + if location == 'right': + toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL) + + # Add the placeholder for the content before adding the toolbar. + child_sizer = self._create_content_spacer(toolbar_sizer) + + # Add the tool bar. + toolbar_sizer.Add(tool_bar, 0, wx.ALL | wx.ALIGN_TOP | wx.EXPAND) + sizer.Add(toolbar_sizer, 1, wx.ALL | wx.EXPAND) + + return child_sizer + + def _create_content_spacer(self, sizer): + spacer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(spacer, 1, wx.ALL | wx.EXPAND) + + return spacer + + ########################################################################### + # Public MultiToolbarWindow interface + ########################################################################### + + def add_tool_bar(self, tool_bar_manager, location='top'): + """ Add a toolbar in the specified location. + + Valid locations are 'top', 'bottom', 'left', and 'right' + """ + + self._tool_bar_managers.append(tool_bar_manager) + self._tool_bar_locations[tool_bar_manager] = location + +#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/preference/preference_dialog.py python-pyface-6.1.2/pyface/ui/wx/preference/preference_dialog.py --- python-pyface-4.5.2/pyface/ui/wx/preference/preference_dialog.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/preference/preference_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,215 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005-2015, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" The preference dialog. """ + + +# Major package imports. +import wx + +# Enthought library imports. +from traits.api import Any, Dict, Float, Instance, Str + +# Local imports. +from pyface.preference.preference_node import PreferenceNode +from pyface.ui.wx.heading_text import HeadingText +from pyface.ui.wx.layered_panel import LayeredPanel +from pyface.ui.wx.split_dialog import SplitDialog +from pyface.ui.wx.viewer.tree_viewer import TreeViewer +from pyface.viewer.default_tree_content_provider import DefaultTreeContentProvider +from pyface.wx.util.font_helper import new_font_like + + +class PreferenceDialog(SplitDialog): + """ The preference dialog. """ + + #### 'Dialog' interface ################################################### + + # The dialog title. + title = Str('Preferences') + + #### 'SplitDialog' interface ############################################## + + # The ratio of the size of the left/top pane to the right/bottom pane. + ratio = Float(0.25) + + #### 'PreferenceDialog' interface ######################################### + + # The root of the preference hierarchy. + root = Instance(PreferenceNode) + + #### Private interface #################################################### + + # The preference pages in the dialog (they are created lazily). + _pages = Dict + + # The current visible preference page. + _current_page = Any + + ########################################################################### + # Protected 'Dialog' interface. + ########################################################################### + + def _create_buttons(self, parent): + """ Creates the buttons. """ + + sizer = wx.BoxSizer(wx.HORIZONTAL) + + # 'Done' button. + done = wx.Button(parent, wx.ID_OK, "Done") + done.SetDefault() + wx.EVT_BUTTON(parent, wx.ID_OK, self._wx_on_ok) + sizer.Add(done) + + return sizer + + ########################################################################### + # Protected 'SplitDialog' interface. + ########################################################################### + + def _create_lhs(self, parent): + """ Creates the panel containing the preference page tree. """ + + return self._create_tree(parent) + + def _create_rhs(self, parent): + """ Creates the panel containing the selected preference page. """ + + panel = wx.Panel(parent, -1, style=wx.CLIP_CHILDREN) + sizer = wx.BoxSizer(wx.VERTICAL) + panel.SetSizer(sizer) + panel.SetAutoLayout(True) + + # The 'pretty' title bar ;^) + self.__title = HeadingText(panel) + sizer.Add( + self.__title.control, 0, + wx.EXPAND | wx.BOTTOM | wx.LEFT | wx.RIGHT, 5 + ) + + # The preference page of the node currently selected in the tree. + self._layered_panel = LayeredPanel(panel, min_width=-1, min_height=-1) + sizer.Add( + self._layered_panel.control, 1, + wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, 5 + ) + + # The 'Restore Defaults' button etc. + buttons = self._create_page_buttons(panel) + sizer.Add(buttons, 0, wx.ALIGN_RIGHT | wx.TOP | wx.RIGHT, 5) + + # A separator. + line = wx.StaticLine(panel, -1) + sizer.Add(line, 0, wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, 5) + + # Resize the panel to fit the sizer's minimum size. + sizer.Fit(panel) + + return panel + + ########################################################################### + # Private interface. + ########################################################################### + + def _create_tree(self, parent): + """ Creates the preference page tree. """ + + tree_viewer = TreeViewer( + parent, + input = self.root, + show_images = False, + show_root = False, + content_provider = DefaultTreeContentProvider() + ) + + tree_viewer.on_trait_change(self._on_selection_changed, 'selection') + + return tree_viewer.control + + def _create_page_buttons(self, parent): + """ Creates the 'Restore Defaults' button, etc. + + At the moment the "etc." is an optional 'Help' button. + + """ + + self._button_sizer = sizer = wx.BoxSizer(wx.HORIZONTAL) + + # 'Help' button. Comes first so 'Restore Defaults' doesn't jump around. + self._help = help = wx.Button(parent, -1, "Help") + wx.EVT_BUTTON(parent, help.GetId(), self._on_help) + sizer.Add(help, 0, wx.RIGHT, 5) + + # 'Restore Defaults' button. + restore = wx.Button(parent, -1, "Restore Defaults") + wx.EVT_BUTTON(parent, restore.GetId(), self._on_restore_defaults) + sizer.Add(restore) + + return sizer + + ########################################################################### + # wx event handlers. + ########################################################################### + + def _on_restore_defaults(self, event): + """ Called when the 'Restore Defaults' button is pressed. """ + + page = self._pages[self._layered_panel.current_layer_name] + page.restore_defaults() + + return + + def _on_help(self, event): + """ Called when the 'Help' button is pressed. """ + + page = self._pages[self._layered_panel.current_layer_name] + page.show_help_topic() + + return + + ########################################################################### + # Trait event handlers. + ########################################################################### + + def _on_selection_changed(self, selection): + """ Called when a node in the tree is selected. """ + + if len(selection) > 0: + # The tree is in single selection mode. + node = selection[0] + + # We only show the help button if the selected node has a help + # topic Id. + if len(node.help_id) > 0: + self._button_sizer.Show(self._help, True) + + else: + self._button_sizer.Show(self._help, False) + + # Show the selected preference page. + layered_panel = self._layered_panel + parent = self._layered_panel.control + + # If we haven't yet displayed the node's preference page during the + # lifetime of this dialog, then we have to create it. + if not layered_panel.has_layer(node.name): + page = node.create_page() + layered_panel.add_layer(node.name, page.create_control(parent)) + self._pages[node.name] = page + + layered_panel.show_layer(node.name) + self.__title.text = node.name + + return + +#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/progress_dialog.py python-pyface-6.1.2/pyface/ui/wx/progress_dialog.py --- python-pyface-4.5.2/pyface/ui/wx/progress_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/progress_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -24,17 +24,25 @@ from traits.api import Bool, Enum, Instance, Int, Property, provides, Str # Local imports -from widget import Widget from pyface.i_progress_dialog import IProgressDialog, MProgressDialog -from window import Window +from .widget import Widget +from .window import Window class ProgressBar(Widget): """ A simple progress bar dialog intended to run in the UI thread """ + #: The progress bar's parent control. parent = Instance(wx.Window) + + #: The progress bar's control. control = Instance(wx.Gauge) + + #: The orientation of the progress bar. direction = Enum('horizontal', 'horizontal', 'vertical') + #: The maximum value for the progress bar. + _max = Int + def __init__(self, parent, minimum=0, maximum=100, direction='horizontal', size=(200, -1)): """ @@ -52,10 +60,7 @@ self.control = wx.Gauge(parent, -1, maximum, style=style, size=size) def update(self, value): - """ - Updates the progress bar to the desired value. - - """ + """ Update the progress bar to the desired value. """ if self._max == 0: self.control.Pulse() else: @@ -70,26 +75,61 @@ # Show the toolkit-specific control in the parent self.control.Show() + class ProgressDialog(MProgressDialog, Window): """ A simple progress dialog window which allows itself to be updated """ + #: The progress bar progress_bar = Instance(ProgressBar) + + #: The window title title = Str + + #: The text message to display in the dialog message = Property() + + #: The minimum value of the progress range min = Int + + #: The minimum value of the progress range max = Int + + #: The margin around the progress bar margin = Int(5) + + #: Whether or not the progress dialog can be cancelled can_cancel = Bool(False) + + #: Whether or not to show the time taken show_time = Bool(False) + + #: Whether or not to show the percent completed show_percent = Bool(False) + + #: Whether or not the dialog was cancelled by the user _user_cancelled = Bool(False) + + #: The text of the message label _message_text = Str() + #: The size of the dialog dialog_size = Instance(wx.Size) # Label for the 'cancel' button cancel_button_label = Str('Cancel') + #: The widget showing the message text + _message_control = Instance(wx.StaticText) + + #: The widget showing the time elapsed + _elapsed_control = Instance(wx.StaticText) + + #: The widget showing the estimated time to completion + _estimated_control = Instance(wx.StaticText) + + #: The widget showing the estimated time remaining + _remaining_control = Instance(wx.StaticText) + def __init__(self, *args, **kw): if 'message' in kw: self._message_text = kw.pop('message') @@ -100,12 +140,18 @@ super(ProgressDialog, self).__init__( *args, **kw) + #------------------------------------------------------------------------- + # IWindow Interface + #------------------------------------------------------------------------- + def open(self): + """ Opens the window. """ super(ProgressDialog, self).open() self._start_time = time.time() wx.GetApp().Yield(True) def close(self): + """ Closes the window. """ if self.progress_bar is not None: self.progress_bar.destroy() self.progress_bar = None @@ -115,7 +161,19 @@ super(ProgressDialog, self).close() + #------------------------------------------------------------------------- + # IProgressDialog Interface + #------------------------------------------------------------------------- + def change_message(self, value): + """ Change the displayed message in the progress dialog + + Parameters + ---------- + message : str or unicode + The new message to display. + + """ self._message_text = value if self._message_control is not None: @@ -124,16 +182,21 @@ msg_control_size = self._message_control.GetSize() self.dialog_size.x = max(self.dialog_size.x, msg_control_size.x + 2*self.margin) - self.control.SetClientSize(self.dialog_size) + if self.control is not None: + self.control.SetClientSize(self.dialog_size) - self.control.GetSizer().Layout() + self.control.GetSizer().Layout() def update(self, value): - """ - updates the progress bar to the desired value. If the value is >= - the maximum and the progress bar is not contained in another panel - the parent window will be closed + """ Update the progress bar to the desired value + If the value is >= the maximum and the progress bar is not contained + in another panel the parent window will be closed. + + Parameters + ---------- + value : + The progress value to set. """ if self.progress_bar is None: @@ -183,6 +246,10 @@ return (not self._user_cancelled, False) + #------------------------------------------------------------------------- + # Private Interface + #------------------------------------------------------------------------- + def _on_cancel(self, event): self._user_cancelled = True self.close() @@ -209,7 +276,6 @@ self._cancel = None if self.can_cancel == True: - # 'Cancel' button. self._cancel = cancel = wx.Button(dialog, wx.ID_CANCEL, self.cancel_button_label) @@ -221,7 +287,6 @@ self.dialog_size.y += button_size.y + 2*self.margin parent_sizer.Add(sizer, 0, wx.ALIGN_RIGHT | wx.ALL, self.margin) - return def _create_label(self, dialog, parent_sizer, text): local_sizer = wx.BoxSizer() @@ -244,8 +309,6 @@ self.dialog_size.x = max(self.dialog_size.x, progress_bar_size.x + 2*self.margin + horiz_spacer) self.dialog_size.y += progress_bar_size.y + 2*self.margin - return - def _create_message(self, dialog, parent_sizer): self._message_control = wx.StaticText(dialog, -1, self.message) parent_sizer.Add(self._message_control, 0, wx.LEFT | wx.TOP, self.margin) @@ -254,15 +317,12 @@ self.dialog_size.x = max(self.dialog_size.x, msg_control_size.x + 2*self.margin) self.dialog_size.y += msg_control_size.y + 2*self.margin - return - def _create_percent(self, dialog, parent_sizer): if not self.show_percent: return raise NotImplementedError - def _create_timer(self, dialog, parent_sizer): if not self.show_time: return @@ -282,8 +342,6 @@ self.dialog_size.x = max(self.dialog_size.x, timer_size.x + 2*self.margin) self.dialog_size.y += timer_size.y + 2*self.margin - return - def _create_control(self, parent): """ Creates the window contents. @@ -315,4 +373,3 @@ dialog.CentreOnParent() return dialog - diff -Nru python-pyface-4.5.2/pyface/ui/wx/python_editor.py python-pyface-6.1.2/pyface/ui/wx/python_editor.py --- python-pyface-4.5.2/pyface/ui/wx/python_editor.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/python_editor.py 2019-05-03 08:18:50.000000000 +0000 @@ -26,8 +26,8 @@ # Local imports. from pyface.i_python_editor import IPythonEditor, MPythonEditor from pyface.key_pressed_event import KeyPressedEvent -from pyface.util.python_stc import PythonSTC, faces -from widget import Widget +from pyface.wx.python_stc import PythonSTC, faces +from .widget import Widget @provides(IPythonEditor) @@ -96,7 +96,7 @@ if path is None: path = self.path - f = file(path, 'w') + f = open(path, 'w') f.write(self.control.GetText()) f.close() diff -Nru python-pyface-4.5.2/pyface/ui/wx/python_shell.py python-pyface-6.1.2/pyface/ui/wx/python_shell.py --- python-pyface-4.5.2/pyface/ui/wx/python_shell.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/python_shell.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,6 +1,4 @@ -#------------------------------------------------------------------------------ -# -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2005-18, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -11,14 +9,12 @@ # Thanks for using Enthought open source! # # Author: Enthought, Inc. -# -#------------------------------------------------------------------------------ """ Enthought pyface package component """ # Standard library imports. -import __builtin__ +import six.moves.builtins import os import sys import types @@ -37,7 +33,8 @@ # Local imports. from pyface.i_python_shell import IPythonShell, MPythonShell from pyface.key_pressed_event import KeyPressedEvent -from widget import Widget +from .widget import Widget +import six @provides(IPythonShell) @@ -46,7 +43,6 @@ IPythonShell interface for the API documentation. """ - #### 'IPythonShell' interface ############################################# command_executed = Event @@ -121,12 +117,7 @@ self.control.clearCommand() self.control.write('# Executing "%s"\n' % path) - if sys.platform == 'win32' and sys.version_info < (2,5,1): - # Work around a bug in Python for Windows. For details, see: - # http://projects.scipy.org/ipython/ipython/ticket/123 - exec file(path) in prog_ns, prog_ns - else: - execfile(path, prog_ns, prog_ns) + execfile(path, prog_ns, prog_ns) if not hidden: self.control.prompt() @@ -144,6 +135,33 @@ del prog_ns['__nonzero__'] self.interpreter().locals.update(prog_ns) + def get_history(self): + """ Return the current command history and index. + + Returns + ------- + history : list of str + The list of commands in the new history. + history_index : int from 0 to len(history) + The current item in the command history navigation. + """ + return self.control.history, self.control.historyIndex + + def set_history(self, history, history_index): + """ Replace the current command history and index with new ones. + + Parameters + ---------- + history : list of str + The list of commands in the new history. + history_index : int from 0 to len(history) + The current item in the command history navigation. + """ + if not 0 <= history_index <= len(history): + history_index = len(history) + self.control.history = list(history) + self.control.historyIndex = history_index + ########################################################################### # 'IWidget' interface. ########################################################################### @@ -171,7 +189,7 @@ name = 'dragged' if hasattr(obj, 'name') \ - and isinstance(obj.name, basestring) and len(obj.name) > 0: + and isinstance(obj.name, six.string_types) and len(obj.name) > 0: py_name = python_name(obj.name) # Make sure that the name is actually a valid Python identifier. @@ -203,21 +221,21 @@ # This was originally in the python_shell plugin, but is toolkit # specific. - if event.m_altDown and event.m_keyCode == 317: + if event.AltDown() and event.GetKeyCode() == 317: zoom = self.shell.control.GetZoom() if zoom != 20: self.control.SetZoom(zoom+1) - elif event.m_altDown and event.m_keyCode == 319: + elif event.AltDown() and event.GetKeyCode() == 319: zoom = self.shell.control.GetZoom() if zoom != -10: self.control.SetZoom(zoom-1) self.key_pressed = KeyPressedEvent( - alt_down = event.m_altDown == 1, - control_down = event.m_controlDown == 1, - shift_down = event.m_shiftDown == 1, - key_code = event.m_keyCode, + alt_down = event.AltDown() == 1, + control_down = event.ControlDown() == 1, + shift_down = event.ShiftDown() == 1, + key_code = event.GetKeyCode(), event = event ) @@ -234,7 +252,7 @@ # save a reference to the original raw_input() function since # wx.py.shell dosent reassign it back to the original on destruction - self.raw_input = __builtin__.raw_input + self.raw_input = six.moves.builtins.raw_input super(PyShell,self).__init__(parent, id, pos, size, style, introText, locals, InterpClass, *args, **kwds) @@ -270,7 +288,7 @@ self.redirectStdout(False) self.redirectStderr(False) self.redirectStdin(False) - __builtin__.raw_input = self.raw_input + six.moves.builtins.raw_input = self.raw_input self.destroy() super(PyShellBase, self).Destroy() @@ -288,5 +306,3 @@ def flush(self): pass def close(self): pass def seek(self, pos, mode = 0): pass - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/resource_manager.py python-pyface-6.1.2/pyface/ui/wx/resource_manager.py --- python-pyface-4.5.2/pyface/ui/wx/resource_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/resource_manager.py 2019-05-03 08:18:50.000000000 +0000 @@ -21,7 +21,7 @@ import os import tempfile -from cStringIO import StringIO +from six.moves import cStringIO as StringIO # Major package imports. import wx diff -Nru python-pyface-4.5.2/pyface/ui/wx/single_choice_dialog.py python-pyface-6.1.2/pyface/ui/wx/single_choice_dialog.py --- python-pyface-4.5.2/pyface/ui/wx/single_choice_dialog.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/single_choice_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,95 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2016, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# +#------------------------------------------------------------------------------ +""" A dialog that allows the user to chose a single item from a list. """ + +import wx + +from traits.api import Any, Bool, List, Str, provides + +from pyface.i_single_choice_dialog import ISingleChoiceDialog, MSingleChoiceDialog +from .dialog import Dialog + + +@provides(ISingleChoiceDialog) +class SingleChoiceDialog(MSingleChoiceDialog, Dialog): + """ A dialog that allows the user to chose a single item from a list. """ + + #### 'ISingleChoiceDialog' interface ###################################### + + #: Whether or not the dialog can be cancelled (Wx Only). + cancel = Bool(True) + + #: List of objects to choose from. + choices = List(Any) + + #: The object chosen, if any. + choice = Any + + #: An optional attribute to use for the name of each object in the dialog. + name_attribute = Str + + #: The message to display to the user. + message = Str + + ########################################################################### + # Protected 'IDialog' interface. + ########################################################################### + + def _create_contents(self, parent): + """ Creates the window contents. """ + # In this case, wx does it all for us in 'wx.SingleChoiceDialog' + pass + + ########################################################################### + # 'IWindow' interface. + ########################################################################### + + def close(self): + """ Closes the window. """ + + # Get the chosen object. + if self.control is not None: + self.choice = self.choices[self.control.GetSelection()] + + # Let the window close as normal. + super(SingleChoiceDialog, self).close() + + ########################################################################### + # Protected 'IWidget' interface. + ########################################################################### + + def _create_control(self, parent): + """ Create the toolkit-specific control that represents the window. """ + + style = wx.DEFAULT_DIALOG_STYLE | wx.CLIP_CHILDREN | wx.OK + if self.cancel: + style |= wx.CANCEL + if self.resizeable: + style |= wx.RESIZE_BORDER + + dialog = wx.SingleChoiceDialog( + parent, + self.message, + self.title, + self._choice_strings(), + style, + self.position + ) + + if self.size != (-1, -1): + dialog.SetSize(self.size) + + return dialog diff -Nru python-pyface-4.5.2/pyface/ui/wx/splash_screen.py python-pyface-6.1.2/pyface/ui/wx/splash_screen.py --- python-pyface-4.5.2/pyface/ui/wx/splash_screen.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/splash_screen.py 2019-05-03 08:18:50.000000000 +0000 @@ -28,14 +28,11 @@ from traits.api import Any, Bool, Font, Instance, Int, provides from traits.api import Tuple, Unicode -# Private Enthought library imports. -# FIXME v3: This should be moved out of pyface. -from pyface.util.font_helper import new_font_like - # Local imports. from pyface.i_splash_screen import ISplashScreen, MSplashScreen from pyface.image_resource import ImageResource -from window import Window +from pyface.wx.util.font_helper import new_font_like +from .window import Window @provides(ISplashScreen) diff -Nru python-pyface-4.5.2/pyface/ui/wx/system_metrics.py python-pyface-6.1.2/pyface/ui/wx/system_metrics.py --- python-pyface-4.5.2/pyface/ui/wx/system_metrics.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/system_metrics.py 2019-05-03 08:18:50.000000000 +0000 @@ -60,7 +60,7 @@ # wx lies. color = wx.Colour(232, 232, 232) else: - color = wx.SystemSettings_GetColour(wx.SYS_COLOUR_MENUBAR).Get() + color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_MENUBAR).Get() return (color[0]/255., color[1]/255., color[2]/255.) diff -Nru python-pyface-4.5.2/pyface/ui/wx/tasks/advanced_editor_area_pane.py python-pyface-6.1.2/pyface/ui/wx/tasks/advanced_editor_area_pane.py --- python-pyface-4.5.2/pyface/ui/wx/tasks/advanced_editor_area_pane.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/tasks/advanced_editor_area_pane.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,22 @@ +# Standard library imports. +import sys + +# Enthought library imports. +from traits.api import provides + +# Local imports. +from pyface.tasks.i_advanced_editor_area_pane import IAdvancedEditorAreaPane +from editor_area_pane import EditorAreaPane + +############################################################################### +# 'AdvancedEditorAreaPane' class. +############################################################################### + +@provides(IAdvancedEditorAreaPane) +class AdvancedEditorAreaPane(EditorAreaPane): + """ The toolkit-specific implementation of an AdvancedEditorAreaPane. + + See the IAdvancedEditorAreaPane interface for API documentation. + """ + + # No additional functionality over the standard EditorAreaPane in wx yet. diff -Nru python-pyface-4.5.2/pyface/ui/wx/tasks/dock_pane.py python-pyface-6.1.2/pyface/ui/wx/tasks/dock_pane.py --- python-pyface-4.5.2/pyface/ui/wx/tasks/dock_pane.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/tasks/dock_pane.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,231 @@ +# Standard library imports +from contextlib import contextmanager +import logging + +# Enthought library imports. +from pyface.tasks.i_dock_pane import IDockPane, MDockPane +from traits.api import Bool, on_trait_change, Property, provides, Tuple, Str, Int + +# System library imports. +import wx +from pyface.wx.aui import aui + +# Local imports. +from .task_pane import TaskPane + +# Constants. +AREA_MAP = { 'left' : aui.AUI_DOCK_LEFT, + 'right' : aui.AUI_DOCK_RIGHT, + 'top' : aui.AUI_DOCK_TOP, + 'bottom' : aui.AUI_DOCK_BOTTOM } +INVERSE_AREA_MAP = dict((int(v), k) for k, v in AREA_MAP.items()) + +# Logging +logger = logging.getLogger(__name__) + + +@provides(IDockPane) +class DockPane(TaskPane, MDockPane): + """ The toolkit-specific implementation of a DockPane. + + See the IDockPane interface for API documentation. + """ + + # Keep a reference to the Aui pane name in order to update dock state + pane_name = Str + + # Whether the title bar of the pane is currently visible. + caption_visible = Bool(True) + + # AUI ring number; note that panes won't be movable out of their ring + # number. This is a way to isolate panes + dock_layer = Int(0) + + #### 'IDockPane' interface ################################################ + + size = Property(Tuple) + + #### Protected traits ##################################################### + + _receiving = Bool(False) + + ########################################################################### + # 'ITaskPane' interface. + ########################################################################### + + @classmethod + def get_hierarchy(cls, parent, indent=""): + lines = ["%s%s %s" % (indent, str(parent), parent.GetName())] + for child in parent.GetChildren(): + lines.append(cls.get_hierarchy(child, indent + " ")) + return "\n".join(lines) + + def create(self, parent): + """ Create and set the dock widget that contains the pane contents. + """ + # wx doesn't need a wrapper control, so the contents become the control + self.control = self.create_contents(parent) + + # hide the pane till the task gets activated, whereupon it will take + # its visibility from the task state + self.control.Hide() + + # Set the widget's object name. This important for AUI Manager state + # saving. Use the task ID and the pane ID to avoid collisions when a + # pane is present in multiple tasks attached to the same window. + self.pane_name = self.task.id + ':' + self.id + logger.debug("dock_pane.create: %s HIERARCHY:\n%s" % (self.pane_name, self.get_hierarchy(parent, " "))) + + def get_new_info(self): + info = aui.AuiPaneInfo().Name(self.pane_name).DestroyOnClose(False) + + # size? + + # Configure the dock widget according to the DockPane settings. + self.update_dock_area(info) + self.update_dock_features(info) + self.update_dock_title(info) + self.update_floating(info) + self.update_visible(info) + + return info + + def add_to_manager(self, row=None, pos=None, tabify_pane=None): + info = self.get_new_info() + if tabify_pane is not None: + target = tabify_pane.get_pane_info() + logger.debug("dock_pane.add_to_manager: Tabify! %s onto %s" % (self.pane_name, target.name)) + else: + target = None + if row is not None: + info.Row(row) + if pos is not None: + info.Position(pos) + self.task.window._aui_manager.AddPane(self.control, info, target=target) + + def validate_traits_from_pane_info(self): + """ Sync traits from the AUI pane info. + + Useful after perspective restore to make sure e.g. visibility state + is set correctly. + """ + info = self.get_pane_info() + self.visible = info.IsShown() + + def destroy(self): + """ Destroy the toolkit-specific control that represents the contents. + """ + if self.control is not None: + logger.debug("Destroying %s" % self.control) + self.task.window._aui_manager.DetachPane(self.control) + + # Some containers (e.g. TraitsDockPane) will destroy the control + # before we get here (e.g. traitsui.ui.UI.finish by way of + # TraitsDockPane.destroy), so check to see if it's already been + # destroyed. Fortunately, the Reparent in DetachPane still seems + # to work on a destroyed control. + if self.control: + self.control.Hide() + self.control.Destroy() + self.control = None + + ########################################################################### + # 'IDockPane' interface. + ########################################################################### + + def create_contents(self, parent): + """ Create and return the toolkit-specific contents of the dock pane. + """ + return wx.Window(parent, name=self.task.id + ':' + self.id) + + #### Trait property getters/setters ####################################### + + def _get_size(self): + if self.control is not None: + return self.control.GetSizeTuple() + return (-1, -1) + + #### Trait change handlers ################################################ + + def get_pane_info(self): + info = self.task.window._aui_manager.GetPane(self.pane_name) + return info + + def commit_layout(self, layout=True): + if layout: + self.task.window._aui_manager.Update() + else: + self.task.window._aui_manager.UpdateWithoutLayout() + + def commit_if_active(self, layout=True): + # Only attempt to commit the AUI changes if the area if the task is active. + main_window = self.task.window.control + if main_window and self.task == self.task.window.active_task: + self.commit_layout(layout) + else: + logger.debug("task not active so not committing...") + + def update_dock_area(self, info): + info.Direction(AREA_MAP[self.dock_area]) + logger.debug("info: dock_area=%s dir=%s" % (self.dock_area, info.dock_direction)) + + @on_trait_change('dock_area') + def _set_dock_area(self): + logger.debug("trait change: dock_area") + if self.control is not None: + info = self.get_pane_info() + self.update_dock_area(info) + self.commit_if_active() + + def update_dock_features(self, info): + info.CloseButton(self.closable) + info.Floatable(self.floatable) + info.Movable(self.movable) + info.CaptionVisible(self.caption_visible) + info.Layer(self.dock_layer) + + @on_trait_change('closable,floatable,movable,caption_visible,dock_layer') + def _set_dock_features(self): + if self.control is not None: + info = self.get_pane_info() + self.update_dock_features(info) + self.commit_if_active() + + def update_dock_title(self, info): + info.Caption(self.name) + + @on_trait_change('name') + def _set_dock_title(self): + if self.control is not None: + info = self.get_pane_info() + self.update_dock_title(info) + + # Don't need to refresh everything if only the name is changing + self.commit_if_active(False) + + def update_floating(self, info): + if self.floating: + info.Float() + else: + info.Dock() + + @on_trait_change('floating') + def _set_floating(self): + if self.control is not None: + info = self.get_pane_info() + self.update_floating(info) + self.commit_if_active() + + def update_visible(self, info): + if self.visible: + info.Show() + else: + info.Hide() + + @on_trait_change('visible') + def _set_visible(self): + logger.debug("_set_visible %s on pane=%s, control=%s" % (self.visible, self.pane_name, self.control)) + if self.control is not None: + info = self.get_pane_info() + self.update_visible(info) + self.commit_if_active() diff -Nru python-pyface-4.5.2/pyface/ui/wx/tasks/editor_area_pane.py python-pyface-6.1.2/pyface/ui/wx/tasks/editor_area_pane.py --- python-pyface-4.5.2/pyface/ui/wx/tasks/editor_area_pane.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/tasks/editor_area_pane.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,163 @@ +# Standard library imports. +import sys +import logging + +# Enthought library imports. +from pyface.tasks.i_editor_area_pane import IEditorAreaPane, \ + MEditorAreaPane +from traits.api import on_trait_change, provides + +# System library imports. +import wx +from pyface.wx.aui import aui, PyfaceAuiNotebook + +# Local imports. +from .task_pane import TaskPane + +# Logging +logger = logging.getLogger(__name__) + + +############################################################################### +# 'EditorAreaPane' class. +############################################################################### + +@provides(IEditorAreaPane) +class EditorAreaPane(TaskPane, MEditorAreaPane): + """ The toolkit-specific implementation of a EditorAreaPane. + + See the IEditorAreaPane interface for API documentation. + """ + + style = aui.AUI_NB_WINDOWLIST_BUTTON|aui.AUI_NB_TAB_MOVE|aui.AUI_NB_SCROLL_BUTTONS|aui.AUI_NB_CLOSE_ON_ACTIVE_TAB + + ########################################################################### + # 'TaskPane' interface. + ########################################################################### + + def create(self, parent): + """ Create and set the toolkit-specific control that represents the + pane. + """ + logger.debug("editor pane parent: %s" % parent) + # Create and configure the tab widget. + self.control = control = PyfaceAuiNotebook(parent, agwStyle=self.style) + + # Connect to the widget's signals. + control.Bind(aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self._update_active_editor) + control.Bind(aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self._close_requested) + + def destroy(self): + """ Destroy the toolkit-specific control that represents the pane. + """ + for editor in self.editors: + self.remove_editor(editor) + + super(EditorAreaPane, self).destroy() + + ########################################################################### + # 'IEditorAreaPane' interface. + ########################################################################### + + def activate_editor(self, editor): + """ Activates the specified editor in the pane. + """ + index = self.control.GetPageIndex(editor.control) + self.control.SetSelection(index) + + def add_editor(self, editor): + """ Adds an editor to the pane. + """ + editor.editor_area = self + editor.create(self.control) + self.control.AddPage(editor.control, self._get_label(editor)) + try: + index = self.control.GetPageIndex(editor.control) + self.control.SetPageToolTip(index, editor.tooltip) + except AttributeError: + pass + self.editors.append(editor) + self._update_tab_bar() + + # The EVT_AUINOTEBOOK_PAGE_CHANGED event is not sent when the first + # editor is added. + if len(self.editors) == 1: + self.active_editor = editor + + def remove_editor(self, editor): + """ Removes an editor from the pane. + """ + self.editors.remove(editor) + index = self.control.GetPageIndex(editor.control) + logger.debug("Removing page %d" % index) + self.control.RemovePage(index) + editor.destroy() + editor.editor_area = None + self._update_tab_bar() + if not self.editors: + self.active_editor = None + + ########################################################################### + # Protected interface. + ########################################################################### + + def _get_label(self, editor): + """ Return a tab label for an editor. + """ + label = editor.name + if editor.dirty: + label = '*' + label + if not label: + label = " " # bug in agw that fails on empty label + return label + + def _get_editor_with_control(self, control): + """ Return the editor with the specified control. + """ + for editor in self.editors: + if editor.control == control: + return editor + return None + + #### Trait change handlers ################################################ + + @on_trait_change('editors:[dirty, name]') + def _update_label(self, editor, name, new): + index = self.control.GetPageIndex(editor.control) + self.control.SetPageText(index, self._get_label(editor)) + + @on_trait_change('editors:tooltip') + def _update_tooltip(self, editor, name, new): + self.control.SetPageToolTip(editor.control, editor.tooltip) + + #### Signal handlers ###################################################### + + def _close_requested(self, evt): + index = evt.GetSelection() + logger.debug("_close_requested: index=%d" % index) + control = self.control.GetPage(index) + editor = self._get_editor_with_control(control) + + # Veto the event even though we are going to delete the tab, otherwise + # the notebook will delete the editor wx control and the call to + # editor.close() will fail. IEditorAreaPane.remove_editor() needs + # the control to exist so it can remove it from the list of managed + # editors. + evt.Veto() + editor.close() + + def _update_active_editor(self, evt): + index = evt.GetSelection() + logger.debug("index=%d" % index) + if index == wx.NOT_FOUND: + self.active_editor = None + else: + logger.debug("num pages=%d" % self.control.GetPageCount()) + control = self.control.GetPage(index) + self.active_editor = self._get_editor_with_control(control) + + @on_trait_change('hide_tab_bar') + def _update_tab_bar(self): + if self.control is not None: + visible = self.control.GetPageCount() > 1 if self.hide_tab_bar else True + pass # Can't actually hide the tab bar on wx.aui diff -Nru python-pyface-4.5.2/pyface/ui/wx/tasks/editor.py python-pyface-6.1.2/pyface/ui/wx/tasks/editor.py --- python-pyface-4.5.2/pyface/ui/wx/tasks/editor.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/tasks/editor.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,45 @@ +# Enthought library imports. +from pyface.tasks.i_editor import IEditor, MEditor +from traits.api import Bool, Property, provides + +# System library imports. +import wx + + +@provides(IEditor) +class Editor(MEditor): + """ The toolkit-specific implementation of a Editor. + + See the IEditor interface for API documentation. + """ + + + #### 'IEditor' interface ################################################## + + has_focus = Property(Bool) + + ########################################################################### + # 'IEditor' interface. + ########################################################################### + + def create(self, parent): + """ Create and set the toolkit-specific control that represents the + pane. + """ + self.control = wx.Window(parent, name="Editor") + + def destroy(self): + """ Destroy the toolkit-specific control that represents the pane. + """ + if self.control is not None: + self.control.Destroy() + self.control = None + + ########################################################################### + # Private interface. + ########################################################################### + + def _get_has_focus(self): + if self.control is not None: + return self.control.FindFocus() == self.control + return False diff -Nru python-pyface-4.5.2/pyface/ui/wx/tasks/main_window_layout.py python-pyface-6.1.2/pyface/ui/wx/tasks/main_window_layout.py --- python-pyface-4.5.2/pyface/ui/wx/tasks/main_window_layout.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/tasks/main_window_layout.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,167 @@ +# Standard library imports. +from itertools import combinations +import logging + +# Enthought library imports. +from traits.api import Any, HasTraits + +# Local imports. +from dock_pane import AREA_MAP, INVERSE_AREA_MAP +from pyface.tasks.task_layout import LayoutContainer, PaneItem, Tabbed, \ + Splitter, HSplitter, VSplitter + +# row/col orientation for AUI +ORIENTATION_NEEDS_NEW_ROW = { + 'horizontal' : { 'top': False, 'bottom': False, 'left': True, 'right': True}, + 'vertical': { 'top': True, 'bottom': True, 'left': False, 'right': False}, + } + + +# Logging. +logger = logging.getLogger(__name__) + + +class MainWindowLayout(HasTraits): + """ A class for applying declarative layouts to an AUI managed window. + """ + + ########################################################################### + # 'MainWindowLayout' interface. + ########################################################################### + + def get_layout(self, layout, window): + """ Get the layout by adding sublayouts to the specified DockLayout. + """ + logger.debug("get_layout: %s" % layout) + layout.perspective = window._aui_manager.SavePerspective() + logger.debug("get_layout: saving perspective %s" % layout.perspective) + + def set_layout(self, layout, window): + """ Applies a DockLayout to the window. + """ + logger.debug("set_layout: %s" % layout) + + if hasattr(layout, "perspective"): + self._set_layout_from_aui(layout, window) + return + + # Perform the layout. This will assign fixed sizes to the dock widgets + # to enforce size constraints specified in the PaneItems. + for name, direction in AREA_MAP.items(): + sublayout = getattr(layout, name) + if sublayout: + self.set_layout_for_area(sublayout, direction) + + self._add_dock_panes(window) + + def _add_dock_panes(self, window): + # Add all panes not assigned an area by the TaskLayout. + mgr = window._aui_manager + for dock_pane in self.state.dock_panes: + info = mgr.GetPane(dock_pane.pane_name) + if not info.IsOk(): + logger.debug("_add_dock_panes: managing pane %s" % dock_pane.pane_name) + dock_pane.add_to_manager() + else: + logger.debug("_add_dock_panes: arleady managed pane: %s" % dock_pane.pane_name) + + def _set_layout_from_aui(self, layout, window): + # The central pane will have already been added, but we need to add all + # of the dock panes to the manager before the call to LoadPerspective + logger.debug("_set_layout_from_aui: using saved perspective") + self._add_dock_panes(window) + logger.debug("_set_layout_from_aui: restoring perspective %s" % layout.perspective) + window._aui_manager.LoadPerspective(layout.perspective) + for dock_pane in self.state.dock_panes: + logger.debug("validating dock pane traits for %s" % dock_pane.id) + dock_pane.validate_traits_from_pane_info() + + def set_layout_for_area(self, layout, direction, row=None, pos=None): + """ Applies a LayoutItem to the specified dock area. + """ + # AUI doesn't have full, arbitrary row/col positions, nor infinitely + # splittable areas. Top and bottom docks are only splittable + # vertically, and within each vertical split each can be split + # horizontally and that's it. Similarly, left and right docks can + # only be split horizontally and within each horizontal split can be + # split vertically. + logger.debug("set_layout_for_area: %s" % INVERSE_AREA_MAP[direction]) + + if isinstance(layout, PaneItem): + dock_pane = self._get_dock_pane(layout) + if dock_pane is None: + raise MainWindowLayoutError("Unknown dock pane %r" % layout) + dock_pane.dock_area = INVERSE_AREA_MAP[direction] + logger.debug("layout size (%d,%d)" % (layout.width, layout.height)) + dock_pane.add_to_manager(row=row, pos=pos) + dock_pane.visible = True + + elif isinstance(layout, Tabbed): + active_pane = first_pane = None + for item in layout.items: + dock_pane = self._get_dock_pane(item) + dock_pane.dock_area = INVERSE_AREA_MAP[direction] + if item.id == layout.active_tab: + active_pane = dock_pane + dock_pane.add_to_manager(tabify_pane=first_pane) + if not first_pane: + first_pane = dock_pane + dock_pane.visible = True + + # Activate the appropriate tab, if possible. + if not active_pane: + # By default, AUI will activate the last widget. + active_pane = first_pane + if active_pane: + mgr = active_pane.task.window._aui_manager + info = active_pane.get_pane_info() + mgr.ShowPane(info.window, True) + + elif isinstance(layout, Splitter): + dock_area = INVERSE_AREA_MAP[direction] + needs_new_row = ORIENTATION_NEEDS_NEW_ROW[layout.orientation][dock_area] + if needs_new_row: + if row is None: + row = 0 + else: + row += 1 + for i, item in enumerate(layout.items): + self.set_layout_for_area(item, direction, row, pos) + row += 1 + else: + pos = 0 + for i, item in enumerate(layout.items): + self.set_layout_for_area(item, direction, row, pos) + pos += 1 + + else: + raise MainWindowLayoutError("Unknown layout item %r" % layout) + + ########################################################################### + # 'MainWindowLayout' abstract interface. + ########################################################################### + + def _get_dock_widget(self, pane): + """ Returns the QDockWidget associated with a PaneItem. + """ + raise NotImplementedError + + def _get_pane(self, dock_widget): + """ Returns a PaneItem for a QDockWidget. + """ + raise NotImplementedError + + def _get_dock_pane(self, pane): + """ Returns the DockPane associated with a PaneItem. + """ + for dock_pane in self.state.dock_panes: + if dock_pane.id == pane.id: + return dock_pane + return None + + +class MainWindowLayoutError(ValueError): + """ Exception raised when a malformed LayoutItem is passed to the + MainWindowLayout. + """ + pass diff -Nru python-pyface-4.5.2/pyface/ui/wx/tasks/split_editor_area_pane.py python-pyface-6.1.2/pyface/ui/wx/tasks/split_editor_area_pane.py --- python-pyface-4.5.2/pyface/ui/wx/tasks/split_editor_area_pane.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/tasks/split_editor_area_pane.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,22 @@ +# Standard library imports. +import sys + +# Enthought library imports. +from traits.api import provides + +# Local imports. +from pyface.tasks.i_editor_area_pane import IEditorAreaPane +from editor_area_pane import EditorAreaPane + +############################################################################### +# 'AdvancedEditorAreaPane' class. +############################################################################### + +@provides(IEditorAreaPane) +class SplitEditorAreaPane(EditorAreaPane): + """ The toolkit-specific implementation of an AdvancedEditorAreaPane. + + See the IAdvancedEditorAreaPane interface for API documentation. + """ + + # No additional functionality over the standard EditorAreaPane in wx yet. diff -Nru python-pyface-4.5.2/pyface/ui/wx/tasks/task_pane.py python-pyface-6.1.2/pyface/ui/wx/tasks/task_pane.py --- python-pyface-4.5.2/pyface/ui/wx/tasks/task_pane.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/tasks/task_pane.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,46 @@ +# Enthought library imports. +from pyface.tasks.i_task_pane import ITaskPane, MTaskPane +from traits.api import provides + +# System library imports. +import wx + +# Logging +import logging +logger = logging.getLogger(__name__) + + +@provides(ITaskPane) +class TaskPane(MTaskPane): + """ The toolkit-specific implementation of a TaskPane. + + See the ITaskPane interface for API documentation. + """ + + + ########################################################################### + # 'ITaskPane' interface. + ########################################################################### + + def create(self, parent): + """ Create and set the toolkit-specific control that represents the + pane. + """ + self.control = wx.Panel(parent) + + def destroy(self): + """ Destroy the toolkit-specific control that represents the pane. + """ + if self.control is not None: + logger.debug("Destroying %s" % self.control) + self.task.window._aui_manager.DetachPane(self.control) + + self.control.Hide() + self.control.Destroy() + self.control = None + + def set_focus(self): + """ Gives focus to the control that represents the pane. + """ + if self.control is not None: + self.control.SetFocus() diff -Nru python-pyface-4.5.2/pyface/ui/wx/tasks/task_window_backend.py python-pyface-6.1.2/pyface/ui/wx/tasks/task_window_backend.py --- python-pyface-4.5.2/pyface/ui/wx/tasks/task_window_backend.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/tasks/task_window_backend.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,198 @@ +# Standard library imports. +import logging + +# System library imports. +import wx +from pyface.wx.aui import aui + +# Enthought library imports. +from traits.api import Instance, List, Str + +# Local imports. +from main_window_layout import MainWindowLayout +from pyface.tasks.i_task_window_backend import MTaskWindowBackend +from pyface.tasks.task_layout import PaneItem, TaskLayout + +# Logging +logger = logging.getLogger(__name__) + + +class AUILayout(TaskLayout): + """ The layout for a main window's dock area using AUI Perspectives + """ + perspective = Str + +class TaskWindowBackend(MTaskWindowBackend): + """ The toolkit-specific implementation of a TaskWindowBackend. + + See the ITaskWindowBackend interface for API documentation. + """ + + #### Private interface #################################################### + + _main_window_layout = Instance(MainWindowLayout) + + ########################################################################### + # 'ITaskWindowBackend' interface. + ########################################################################### + + def create_contents(self, parent): + """ Create and return the TaskWindow's contents. + """ + # No extra control needed for wx (it's all handled by the AUIManager in + # the ApplicationWindow) but we do need to handle some events here + self.window._aui_manager.Bind(aui.EVT_AUI_PANE_CLOSE, self._pane_close_requested) + + def destroy(self): + """ Destroy the backend. + """ + pass + + def hide_task(self, state): + """ Assuming the specified TaskState is active, hide its controls. + """ + # Save the task's layout in case it is shown again later. + self.window._active_state.layout = self.get_layout() + + # Now hide its controls. + self.window._aui_manager.DetachPane(state.central_pane.control) + state.central_pane.control.Hide() + + for dock_pane in state.dock_panes: + logger.debug("hiding dock pane %s" % dock_pane.id) + self.window._aui_manager.DetachPane(dock_pane.control) + dock_pane.control.Hide() + + # Remove any tabbed notebooks left over after all the panes have been + # removed + self.window._aui_manager.UpdateNotebook() + + # Remove any still-left over stuff (i.e. toolbars) + for info in self.window._aui_manager.GetAllPanes(): + logger.debug("hiding remaining pane: %s" % info.name) + control = info.window + self.window._aui_manager.DetachPane(control) + control.Hide() + + def show_task(self, state): + """ Assuming no task is currently active, show the controls of the + specified TaskState. + """ + # Show the central pane. + info = aui.AuiPaneInfo().Caption('Central').Dockable(False).Floatable(False).Name('Central').CentrePane().Maximize() + logger.debug("adding central pane to %s" % self.window) + self.window._aui_manager.AddPane(state.central_pane.control, info) + self.window._aui_manager.Update() + + # Show the dock panes. + self._layout_state(state) + + def get_toolbars(self, task=None): + if task is None: + state = self.window._active_state + else: + state = self.window._get_state(task) + toolbars = [] + for tool_bar_manager in state.tool_bar_managers: + info = self.window._aui_manager.GetPane(tool_bar_manager.id) + toolbars.append(info) + return toolbars + + def show_toolbars(self, toolbars): + for info in toolbars: + info.Show() + self.window._aui_manager.Update() + + #### Methods for saving and restoring the layout ########################## + + def get_layout(self): + """ Returns a TaskLayout for the current state of the window. + """ + # Extract the layout from the main window. + layout = AUILayout(id=self.window._active_state.task.id) + self._main_window_layout.state = self.window._active_state + self._main_window_layout.get_layout(layout, self.window) + + return layout + + def set_layout(self, layout): + """ Applies a TaskLayout (which should be suitable for the active task) + to the window. + """ + self.window._active_state.layout = layout + self._layout_state(self.window._active_state) + self.window._aui_manager.Update() + + ########################################################################### + # Private interface. + ########################################################################### + + def _layout_state(self, state): + """ Layout the dock panes in the specified TaskState using its + TaskLayout. + """ +# # Assign the window's corners to the appropriate dock areas. +# for name, corner in CORNER_MAP.iteritems(): +# area = getattr(state.layout, name + '_corner') +# self.control.setCorner(corner, AREA_MAP[area]) + + # Add all panes in the TaskLayout. + self._main_window_layout.state = state + self._main_window_layout.set_layout(state.layout, self.window) + + #### Trait initializers ################################################### + + def __main_window_layout_default(self): + return TaskWindowLayout() + + #### Signal handlers ###################################################### + + def _pane_close_requested(self, evt): + pane = evt.GetPane() + logger.debug("_pane_close_requested: pane=%s" % pane.name) + for dock_pane in self.window.dock_panes: + logger.debug("_pane_close_requested: checking pane=%s" % dock_pane.pane_name) + if dock_pane.pane_name == pane.name: + logger.debug("_pane_close_requested: FOUND PANE!!!!!!") + dock_pane.visible = False + break + + def _focus_changed_signal(self, old, new): + if self.window.active_task: + panes = [ self.window.central_pane ] + self.window.dock_panes + for pane in panes: + if new and pane.control.isAncestorOf(new): + pane.has_focus = True + elif old and pane.control.isAncestorOf(old): + pane.has_focus = False + + +class TaskWindowLayout(MainWindowLayout): + """ A MainWindowLayout for a TaskWindow. + """ + + #### 'TaskWindowLayout' interface ######################################### + + consumed = List + state = Instance('pyface.tasks.task_window.TaskState') + + ########################################################################### + # 'MainWindowLayout' abstract interface. + ########################################################################### + + def _get_dock_widget(self, pane): + """ Returns the control associated with a PaneItem. + """ + for dock_pane in self.state.dock_panes: + if dock_pane.id == pane.id: + self.consumed.append(dock_pane.control) + return dock_pane.control + return None + + def _get_pane(self, dock_widget): + """ Returns a PaneItem for a control. + """ + for dock_pane in self.state.dock_panes: + if dock_pane.control == dock_widget: + return PaneItem(id=dock_pane.id) + return None diff -Nru python-pyface-4.5.2/pyface/ui/wx/timer/do_later.py python-pyface-6.1.2/pyface/ui/wx/timer/do_later.py --- python-pyface-4.5.2/pyface/ui/wx/timer/do_later.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/timer/do_later.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,6 +1,4 @@ -#------------------------------------------------------------------------------- -# -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2018, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -9,56 +7,10 @@ # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! -# -# Author: David C. Morrill -# Date: 05/18/2005 -# -#------------------------------------------------------------------------------- - -""" Provides a simple function for scheduling some code to run at some time in - the future (assumes application is wxPython based). """ +DoLaterTimer class -#------------------------------------------------------------------------------- -# Imports: -#------------------------------------------------------------------------------- - -import wx - -#------------------------------------------------------------------------------- -# 'DoLaterTimer' class: -#------------------------------------------------------------------------------- - -class DoLaterTimer ( wx.Timer ): - - # List of currently active timers: - active_timers = [] - - #--------------------------------------------------------------------------- - # Initializes the object: - #--------------------------------------------------------------------------- - - def __init__ ( self, interval, callable, args, kw_args ): - global active_timers - wx.Timer.__init__( self ) - for timer in self.active_timers: - if ((timer.callable == callable) and - (timer.args == args) and - (timer.kw_args == kw_args)): - timer.Start( interval, True ) - return - self.active_timers.append( self ) - self.callable = callable - self.args = args - self.kw_args = kw_args - self.Start( interval, True ) - - #--------------------------------------------------------------------------- - # Handles the timer pop event: - #--------------------------------------------------------------------------- - - def Notify ( self ): - global active_timers +Provided for backward compatibility. +""" - self.active_timers.remove( self ) - self.callable( *self.args, **self.kw_args ) +from pyface.timer.do_later import DoLaterTimer \ No newline at end of file diff -Nru python-pyface-4.5.2/pyface/ui/wx/timer/timer.py python-pyface-6.1.2/pyface/ui/wx/timer/timer.py --- python-pyface-4.5.2/pyface/ui/wx/timer/timer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/timer/timer.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,6 +1,4 @@ -#------------------------------------------------------------------------------- -# -# Copyright (c) 2006, Enthought, Inc. +# Copyright (c) 2006-18, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -11,49 +9,37 @@ # Thanks for using Enthought open source! # # Author: Prabhu Ramachandran -# -#------------------------------------------------------------------------------- - """A `wx.Timer` subclass that invokes a specified callback periodically. """ -# Standard library imports. import wx -###################################################################### -# `Timer` class. -class Timer(wx.Timer): - """Simple subclass of wx.Timer that allows the user to have a - function called periodically. - - Any exceptions raised in the callable are caught. If - `StopIteration` is raised the timer stops. If other exceptions are - encountered the timer is stopped and the exception re-raised. - """ - - def __init__(self, millisecs, callable, *args, **kw_args): - """Initialize instance to invoke the given `callable` with - given arguments and keyword args after every `millisecs` - (milliseconds). - """ - wx.Timer.__init__(self, id=wx.NewId()) - self.callable = callable - self.args = args - self.kw_args = kw_args - self.Start(millisecs) +from traits.api import Bool, Instance, Property + +from pyface.timer.i_timer import BaseTimer + + +class CallbackTimer(wx.Timer): + def __init__(self, timer): + super(CallbackTimer, self).__init__() + self.timer = timer def Notify(self): - """Overridden to call the given callable. Exceptions raised - in the callable are caught. If `StopIteration` is raised the - timer stops. If other exceptions are encountered the timer is - stopped and the exception re-raised. - """ - try: - self.callable(*self.args, **self.kw_args) - wx.GetApp().Yield(True) - except StopIteration: - self.Stop() - except: - self.Stop() - raise + self.timer.perform() + wx.GetApp().Yield(True) + + +class PyfaceTimer(BaseTimer): + """ Abstract base class for Wx toolkit timers. """ + + #: The wx.Timer for the PyfaceTimer. + _timer = Instance(wx.Timer) + + def _start(self): + self._timer.Start(int(self.interval * 1000)) + + def _stop(self): + self._timer.Stop() + def __timer_default(self): + return CallbackTimer(self) diff -Nru python-pyface-4.5.2/pyface/ui/wx/tree/tree.py python-pyface-6.1.2/pyface/ui/wx/tree/tree.py --- python-pyface-4.5.2/pyface/ui/wx/tree/tree.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/tree/tree.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,1286 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" A tree control with a model/ui architecture. """ + + +# Standard library imports. +import logging +import os + +# Major package imports. +import wx + +# Enthought library imports. +from traits.api import Any, Bool, Callable, Enum, Event, Instance +from traits.api import List, Property, Callable, Str, Trait, Tuple + +# Local imports. +from pyface.filter import Filter +from pyface.key_pressed_event import KeyPressedEvent +from pyface.sorter import Sorter +from pyface.tree.tree_model import TreeModel +from pyface.ui.wx.gui import GUI +from pyface.ui.wx.image_list import ImageList +from pyface.ui.wx.widget import Widget +from pyface.wx.drag_and_drop import PythonDropSource, PythonDropTarget + + +# Create a logger for this module. +logger = logging.getLogger(__name__) + + +class _Tree(wx.TreeCtrl): + """ The wx tree control that we delegate to. + + We use this derived class so that we can detect the destruction of the + tree and remove model listeners etc. + + """ + + ########################################################################### + # 'object' interface. + ########################################################################### + + def __init__(self, tree, parent, wxid, style): + """ Creates a new tree. """ + + # Base class constructor. + wx.TreeCtrl.__init__(self, parent, wxid, style=style) + + # The tree that we are the toolkit-specific delegate for. + self._tree = tree + + return + + def __del__(self): + """ Destructor. """ + + # Stop listenting to the model! + self._tree._remove_model_listeners(self._tree.model) + + return + + +class Tree(Widget): + """ A tree control with a model/ui architecture. """ + + # The default tree style. + STYLE = wx.TR_EDIT_LABELS | wx.TR_HAS_BUTTONS | wx.CLIP_CHILDREN + + #### 'Tree' interface ##################################################### + + # The tree's filters (empty if no filtering is required). + filters = List(Filter) + + # Mode for lines connecting tree nodes which emphasize hierarchy: + # 'appearance' - only on when lines look good, + # 'on' - always on, 'off' - always off + # NOTE: on and off are ignored in favor of show_lines for now + lines_mode = Enum('appearance', 'on', 'off') + + # The model that provides the data for the tree. + model = Instance(TreeModel, ()) + + # The root of the tree (this is for convenience, it just delegates to + # the tree's model). + root = Property(Any) + + # The objects currently selected in the tree. + selection = List + + # Selection mode. + selection_mode = Enum('single', 'extended') + + # Should an image be shown for each node? + show_images = Bool(True) + + # Should lines be drawn between levels in the tree. + show_lines = Bool(True) + + # Should the root of the tree be shown? + show_root = Bool(True) + + # The tree's sorter (None if no sorting is required). + sorter = Instance(Sorter) + + #### Events #### + + # A right-click occurred on the control (not a node!). + control_right_clicked = Event#(Point) + + # A key was pressed while the tree has focus. + key_pressed = Event(KeyPressedEvent) + + # A node has been activated (ie. double-clicked). + node_activated = Event#(Any) + + # A drag operation was started on a node. + node_begin_drag = Event#(Any) + + # A (non-leaf) node has been collapsed. + node_collapsed = Event#(Any) + + # A (non-leaf) node has been expanded. + node_expanded = Event#(Any) + + # A left-click occurred on a node. + # + # Tuple(node, point). + node_left_clicked = Event#(Tuple) + + # A right-click occurred on a node. + # + # Tuple(node, point) + node_right_clicked = Event#(Tuple) + + #### Private interface #################################################### + + # A name to distinguish the tree for debugging! + # + # fixme: This turns out to be kinda useful... Should 'Widget' have a name + # trait? + _name = Str('Anonymous tree') + + # An optional callback to detect the end of a label edit. This is + # useful because the callback will be invoked even if the node label was + # not actually changed. + _label_edit_callback = Trait(None, Callable, None) + + # Flag for allowing selection events to be ignored + _ignore_selection_events = Bool(False) + + ########################################################################### + # 'object' interface. + ########################################################################### + + def __init__(self, parent, image_size=(16, 16), **traits): + """ Creates a new tree. + + 'parent' is the toolkit-specific control that is the tree's parent. + + 'image_size' is a tuple in the form (int width, int height) that + specifies the size of the images (if required) displayed in the tree. + + """ + + # Base class constructors. + super(Tree, self).__init__(**traits) + + # Get our wx Id. + wxid = wx.NewId() + + # Create the toolkit-specific control. + self.control = tree = _Tree(self, parent, wxid,style=self._get_style()) + + # Wire up the wx tree events. + wx.EVT_CHAR(tree, self._on_char) + wx.EVT_LEFT_DOWN(tree, self._on_left_down) + # fixme: This is not technically correct as context menus etc should + # appear on a right up (or right click). Unfortunately, if we + # change this to 'EVT_RIGHT_UP' wx does not fire the event unless the + # right mouse button is double clicked 8^() Sad, but true! + wx.EVT_RIGHT_DOWN(tree, self._on_right_down) + # fixme: This is not technically correct as we would really like to use + # 'EVT_TREE_ITEM_ACTIVATED'. Unfortunately, (in 2.6 at least), it + # throws an exception when the 'Enter' key is pressed as the wx tree + # item Id in the event seems to be invalid. It also seems to cause + # any child frames that my be created in response to the event to + # appear *behind* the parent window, which is, errrr, not great ;^) + wx.EVT_LEFT_DCLICK(tree, self._on_tree_item_activated) + #wx.EVT_TREE_ITEM_ACTIVATED(tree, wxid, self._on_tree_item_activated) + wx.EVT_TREE_ITEM_COLLAPSING(tree, wxid, self._on_tree_item_collapsing) + wx.EVT_TREE_ITEM_COLLAPSED(tree, wxid, self._on_tree_item_collapsed) + wx.EVT_TREE_ITEM_EXPANDING(tree, wxid, self._on_tree_item_expanding) + wx.EVT_TREE_ITEM_EXPANDED(tree, wxid, self._on_tree_item_expanded) + wx.EVT_TREE_BEGIN_LABEL_EDIT(tree, wxid,self._on_tree_begin_label_edit) + wx.EVT_TREE_END_LABEL_EDIT(tree, wxid, self._on_tree_end_label_edit) + wx.EVT_TREE_BEGIN_DRAG(tree, wxid, self._on_tree_begin_drag) + wx.EVT_TREE_SEL_CHANGED(tree, wxid, self._on_tree_sel_changed) + wx.EVT_TREE_DELETE_ITEM(tree, wxid, self._on_tree_delete_item) + + # Enable the tree as a drag and drop target. + self.control.SetDropTarget(PythonDropTarget(self)) + + # The image list is a wxPython-ism that caches all images used in the + # control. + self._image_list = ImageList(image_size[0], image_size[1]) + if self.show_images: + tree.AssignImageList(self._image_list) + + # Mapping from node to wx tree item Ids. + self._node_to_id_map = {} + + # Add the root node. + if self.root is not None: + self._add_root_node(self.root) + + # Listen for changes to the model. + self._add_model_listeners(self.model) + + return + + ########################################################################### + # 'Tree' interface. + ########################################################################### + + #### Properties ########################################################### + + def _get_root(self): + """ Returns the root node of the tree. """ + + return self.model.root + + def _set_root(self, root): + """ Sets the root node of the tree. """ + + self.model.root = root + + return + + #### Methods ############################################################## + + def collapse(self, node): + """ Collapses the specified node. """ + + wxid = self._get_wxid(node) + if wxid is not None: + self.control.Collapse(wxid) + + return + + def edit_label(self, node, callback=None): + """ Edits the label of the specified node. + + If a callback is specified it will be called when the label edit + completes WHETHER OR NOT the label was actually changed. + + The callback must take exactly 3 arguments:- (tree, node, label) + + """ + + wxid = self._get_wxid(node) + if wxid is not None: + self._label_edit_callback = callback + self.control.EditLabel(wxid) + + return + + def expand(self, node): + """ Expands the specified node. """ + + wxid = self._get_wxid(node) + if wxid is not None: + self.control.Expand(wxid) + + return + + def expand_all(self): + """ Expands every node in the tree. """ + + if self.show_root: + self._expand_item(self._get_wxid(self.root)) + + else: + for child in self._get_children(self.root): + self._expand_item(self._get_wxid(child)) + + return + + def get_parent(self, node): + """ Returns the parent of a node. + + This will only work iff the node has been displayed in the tree. If it + hasn't then None is returned. + + """ + + # Has the node actually appeared in the tree yet? + wxid = self._get_wxid(node) + if wxid is not None: + pid = self.control.GetItemParent(wxid) + + # The item data is a tuple. The first element indicates whether or + # not we have already populated the item with its children. The + # second element is the actual item data. + populated, parent = self.control.GetPyData(pid) + + else: + parent = None + + return parent + + def is_expanded(self, node): + """ Returns True if the node is expanded, otherwise False. """ + + wxid = self._get_wxid(node) + if wxid is not None: + # If the root node is hidden then it is always expanded! + if node is self.root and not self.show_root: + is_expanded = True + + else: + is_expanded = self.control.IsExpanded(wxid) + + else: + is_expanded = False + + return is_expanded + + def is_selected(self, node): + """ Returns True if the node is selected, otherwise False. """ + + wxid = self._get_wxid(node) + if wxid is not None: + is_selected = self.control.IsSelected(wxid) + + else: + is_selected = False + + return is_selected + + def refresh(self, node): + """ Refresh the tree starting from the specified node. + + Call this when the structure of the content has changed DRAMATICALLY. + + """ + + # Has the node actually appeared in the tree yet? + pid = self._get_wxid(node) + if pid is not None: + # Delete all of the node's children and re-add them. + self.control.DeleteChildren(pid) + self.control.SetPyData(pid, (False, node)) + + # Does the node have any children? + has_children = self._has_children(node) + self.control.SetItemHasChildren(pid, has_children) + + # fixme: At least on Windows, wx does not fire an expanding + # event for a hidden root node, so we have to populate the node + # manually. + if node is self.root and not self.show_root: + # Add the child nodes. + for child in self._get_children(node): + self._add_node(pid, child) + + else: + # Expand it. + if self.control.IsExpanded(pid): + self.control.Collapse(pid) + + self.control.Expand(pid) + + return + + def select(self, node): + """ Selects the specified node. """ + + wxid = self._get_wxid(node) + if wxid is not None: + self.control.SelectItem(wxid) + + return + + def set_selection(self, list): + """ Selects the specified list of nodes. """ + logger.debug('Setting selection to [%s] within Tree [%s]', list, self) + + # Update the control to reflect the target list by unselecting + # everything and then selecting each item in the list. During this + # process, we want to avoid changing our own selection. + self._ignore_selection_events = True + self.control.UnselectAll() + for node in list: + try: + self.select(node) + except: + logger.exception('Unable to select node [%s]', node) + + self._ignore_selection_events = False + + # Update our selection to reflect the final selection state. + self.selection = self._get_selection() + + ########################################################################### + # 'PythonDropTarget' interface. + ########################################################################### + + def on_drag_over(self, x, y, obj, default_drag_result): + """ Called when a node is dragged over the tree. """ + + result = wx.DragNone + + # Find the node that we are dragging over... + node = self._get_drag_drop_node(x, y) + if node is not None: + # Ask the model if the node allows the object to be dropped onto + # it. + if self.model.can_drop(node, obj): + result = default_drag_result + + return result + + def on_drop(self, x, y, obj, default_drag_result): + """ Called when a node is dropped on the tree. """ + + # Find the node that we are dragging over... + node = self._get_drag_drop_node(x, y) + if node is not None: + self.model.drop(node, obj) + + return default_drag_result + + ########################################################################### + # Private interface. + ########################################################################### + + def _get_wxid(self, node): + """ Returns the wxid for the specified node. + + Returns None if the node has not yet appeared in the tree. + + """ + + # The model must generate a unique key for each node (unique within the + # model). + key = self.model.get_key(node) + + return self._node_to_id_map.get(key, None) + + def _set_wxid(self, node, wxid): + """ Sets the wxid for the specified node. """ + + # The model must generate a unique key for each node (unique within the + # model). + key = self.model.get_key(node) + + self._node_to_id_map[key] = wxid + + return + + def _remove_wxid(self, node): + """ Removes the wxid for the specified node. """ + + # The model must generate a unique key for each node (unique within the + # model). + key = self.model.get_key(node) + + try: + del self._node_to_id_map[key] + + except KeyError: + # fixme: No, really, this is a serious one... How do we get in this + # situation. It came up when using the canvas stuff... + logger.warn('removing node: %s' % str(node)) + + return + + def _get_style(self): + """ Returns the wx style flags for creating the tree control. """ + + # Start with the default flags. + style = self.STYLE + + # Turn lines off for appearance on *nix. + # ...for now, show_lines determines if lines are on or off, but + # eventually lines_mode may eliminate the need for show_lines + if self.lines_mode == 'appearance' and os.name == 'posix': + self.show_lines = False + + if not self.show_lines: + style = style | wx.TR_NO_LINES + + if not self.show_root: + # fixme: It looks a little weird, but it we don't have the + # 'lines at root' style then wx won't draw the expand/collapse + # image on non-leaf nodes at the root level 8^() + style = style | wx.TR_HIDE_ROOT | wx.TR_LINES_AT_ROOT + + if self.selection_mode != 'single': + style = style | wx.TR_MULTIPLE | wx.TR_EXTENDED + + return style + + def _add_model_listeners(self, model): + """ Adds listeners for model changes. """ + + # Listen for changes to the model. + model.on_trait_change(self._on_root_changed, 'root') + model.on_trait_change(self._on_nodes_changed, 'nodes_changed') + model.on_trait_change(self._on_nodes_inserted, 'nodes_inserted') + model.on_trait_change(self._on_nodes_removed, 'nodes_removed') + model.on_trait_change(self._on_nodes_replaced, 'nodes_replaced') + model.on_trait_change(self._on_structure_changed, 'structure_changed') + + return + + def _remove_model_listeners(self, model): + """ Removes listeners for model changes. """ + + # Unhook the model event listeners. + model.on_trait_change( + self._on_root_changed, 'root', remove=True + ) + + model.on_trait_change( + self._on_nodes_changed, 'nodes_changed', remove=True + ) + + model.on_trait_change( + self._on_nodes_inserted, 'nodes_inserted', remove=True + ) + + model.on_trait_change( + self._on_nodes_removed, 'nodes_removed', remove=True + ) + + model.on_trait_change( + self._on_nodes_replaced, 'nodes_replaced', remove=True + ) + + model.on_trait_change( + self._on_structure_changed, 'structure_changed', remove=True + ) + + return + + def _add_root_node(self, node): + """ Adds the root node. """ + + # Get the tree item image index and the label text. + image_index = self._get_image_index(node) + text = self._get_text(node) + + # Add the node. + wxid = self.control.AddRoot(text, image_index, image_index) + + # This gives the model a chance to wire up trait handlers etc. + self.model.add_listener(node) + + # If the root node is hidden, get its children. + if not self.show_root: + # Add the child nodes. + for child in self._get_children(node): + self._add_node(wxid, child) + + # Does the node have any children? + has_children = self._has_children(node) + self.control.SetItemHasChildren(wxid, has_children) + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data (which in our case is an arbitrary + # Python object provided by the tree model). + if self.show_root: + self.control.SetPyData(wxid, (not self.show_root, node)) + + # Make sure that we can find the node's Id. + self._set_wxid(node, wxid) + + # Automatically expand the root. + if self.show_root: + self.control.Expand(wxid) + + return + + def _add_node(self, pid, node): + """ Adds 'node' as a child of the node identified by 'pid'. + + If 'pid' is None then we are adding the root node. + + """ + + # Get the tree item image index and the label text. + image_index = self._get_image_index(node) + text = self._get_text(node) + + # Add the node. + wxid = self.control.AppendItem(pid, text, image_index, image_index) + + # This gives the model a chance to wire up trait handlers etc. + self.model.add_listener(node) + + # Does the node have any children? + has_children = self._has_children(node) + self.control.SetItemHasChildren(wxid, has_children) + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data (which in our case is an arbitrary + # Python object provided by the tree model). + self.control.SetPyData(wxid, (False, node)) + + # Make sure that we can find the node's Id. + self._set_wxid(node, wxid) + + return + + def _insert_node(self, pid, node, index): + """ Inserts 'node' as a child of the node identified by 'pid'. + + If 'pid' is None then we are adding the root node. + + """ + + # Get the tree item image index and the label text. + image_index = self._get_image_index(node) + text = self._get_text(node) + + # Add the node. + wxid = self.control.InsertItemBefore( + pid, index, text, image_index, image_index + ) + + # This gives the model a chance to wire up trait handlers etc. + self.model.add_listener(node) + + # Does the node have any children? + has_children = self._has_children(node) + self.control.SetItemHasChildren(wxid, has_children) + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data (which in our case is an arbitrary + # Python object provided by the tree model). + self.control.SetPyData(wxid, (False, node)) + + # Make sure that we can find the node's Id. + self._set_wxid(node, wxid) + + return + + def _remove_node(self, wxid, node): + """ Removes a node from the tree. """ + + # This gives the model a chance to remove trait handlers etc. + self.model.remove_listener(node) + + # Remove the reference to the item's data. + self._remove_wxid(node) + self.control.SetPyData(wxid, None) + + return + + def _update_node(self, wxid, node): + """ Updates the image and text of the specified node. """ + + # Get the tree item image index. + image_index = self._get_image_index(node) + self.control.SetItemImage(wxid, image_index, wx.TreeItemIcon_Normal) + self.control.SetItemImage(wxid, image_index, wx.TreeItemIcon_Selected) + + # Get the tree item text. + text = self._get_text(node) + self.control.SetItemText(wxid, text) + + return + + def _has_children(self, node): + """ Returns True if a node has children. """ + + # fixme: To be correct we *should* apply filtering here, but that + # seems to blow a hole throught models that have some efficient + # mechanism for determining whether or not they have children. There + # is also a precedent for doing it this way in Windoze, where a node + # gets marked as though it can be expanded, even thought when the + # expansion occurs, no children are present! + return self.model.has_children(node) + + def _get_children(self, node): + """ Get the children of a node. """ + + children = self.model.get_children(node) + + # Filtering.... + filtered_children = [] + for child in children: + for filter in self.filters: + if not filter.select(self, node, child): + break + + else: + filtered_children.append(child) + + # Sorting... + if self.sorter is not None: + self.sorter.sort(self, node, filtered_children) + + return filtered_children + + def _get_image_index(self, node): + """ Returns the tree item image index for a node. """ + + expanded = self.is_expanded(node) + selected = self.is_selected(node) + + # Get the image used to represent the node. + image = self.model.get_image(node, selected, expanded) + if image is not None: + image_index = self._image_list.GetIndex(image) + + else: + image_index = -1 + + return image_index + + def _get_drag_drop_node(self, x, y): + """ Returns the node that is being dragged/dropped on. + + Returns None if the cursor is not over the icon or label of a node. + + """ + + data, wxid, flags, point = self._hit_test((x, y)) + if data is not None: + populated, node = data + + else: + node = None + + return node + + def _get_text(self, node): + """ Returns the tree item text for a node. """ + + text = self.model.get_text(node) + if text is None: + text = '' + + return text + + def _unpack_event(self, event, wxid=None): + """ Unpacks the event to see whether a tree item was involved. """ + + try: + point = event.GetPosition() + + except: + point = event.GetPoint() + + return self._hit_test(point, wxid) + + def _hit_test(self, point, wxid=None): + """ Determines whether a point is within a node's label or icon. """ + + flags = wx.TREE_HITTEST_ONITEMLABEL + if (wxid is None) or (not wxid.IsOk()): + wxid, flags = self.control.HitTest(point) + + # Warning: On GTK we have to check the flags before we call 'GetPyData' + # because if we call it when the hit test returns 'nowhere' it will + # barf (on Windows it simply returns 'None' 8^() + if flags & wx.TREE_HITTEST_NOWHERE: + data = None + + elif flags & wx.TREE_HITTEST_ONITEMICON \ + or flags & wx.TREE_HITTEST_ONITEMLABEL: + + data = self.control.GetPyData(wxid) + + # fixme: Not sure why 'TREE_HITTEST_NOWHERE' doesn't catch everything! + else: + data = None + + return data, wxid, flags, point + + def _get_selection(self): + """ Returns a list of the selected nodes """ + + selection = [] + for wxid in self.control.GetSelections(): + data = self.control.GetPyData(wxid) + if data is not None: + populated, node = data + selection.append(self.model.get_selection_value(node)) + + return selection + + def _expand_item(self, wxid): + """ Recursively expand a tree item. """ + + self.control.Expand(wxid) + + cid, cookie = self.control.GetFirstChild(wxid) + while cid.IsOk(): + self._expand_item(cid) + cid, cookie = self.control.GetNextChild(wxid, cookie) + + return + + #### Trait event handlers ################################################# + + def _on_root_changed(self, root): + """ Called when the root of the model has changed. """ + + # Delete everything... + if self.control is not None: + self.control.DeleteAllItems() + + self._node_to_id_map = {} + + # ... and then add the root item back in. + if root is not None: + self._add_root_node(root) + + return + + def _on_nodes_changed(self, event): + """ Called when nodes have been changed. """ + + self._update_node(self._get_wxid(event.node), event.node) + + for child in event.children: + cid = self._get_wxid(child) + if cid is not None: + self._update_node(cid, child) + + return + + def _on_nodes_inserted(self, event): + """ Called when nodes have been inserted. """ + + parent = event.node + children = event.children + index = event.index + + # Has the node actually appeared in the tree yet? + pid = self._get_wxid(parent) + if pid is not None: + # The item data is a tuple. The first element indicates whether or + # not we have already populated the item with its children. The + # second element is the actual item data. + if self.show_root or parent is not self.root: + populated, node = self.control.GetPyData(pid) + + else: + populated = True + + # If the node is not yet populated then just get the children and + # add them. + if not populated: + for child in self._get_children(parent): + self._add_node(pid, child) + + # Otherwise, insert them. + else: + # An index of -1 means append! + if index == -1: + index = self.control.GetChildrenCount(pid, False) + + for child in children: + self._insert_node(pid, child, index) + index += 1 + + # The element is now populated! + if self.show_root or parent is not self.root: + self.control.SetPyData(pid, (True, parent)) + + # Does the node have any children now? + has_children = self.control.GetChildrenCount(pid) > 0 + self.control.SetItemHasChildren(pid, has_children) + + # If the node is not expanded then expand it. + if not self.is_expanded(parent): + self.expand(parent) + + return + + def _on_nodes_removed(self, event): + """ Called when nodes have been removed. """ + + parent = event.node + children = event.children + + # Has the node actually appeared in the tree yet? + pid = self._get_wxid(parent) + if pid is not None: + for child in event.children: + cid = self._get_wxid(child) + if cid is not None: + self.control.Delete(cid) + + # Does the node have any children left? + has_children = self.control.GetChildrenCount(pid) > 0 + self.control.SetItemHasChildren(pid, has_children) + + return + + def _on_nodes_replaced(self, event): + """ Called when nodes have been replaced. """ + + for old_child, new_child in zip(event.old_children, event.children): + cid = self._get_wxid(old_child) + if cid is not None: + # Remove listeners from the old node. + self.model.remove_listener(old_child) + + # Delete all of the node's children. + self.control.DeleteChildren(cid) + + # Update the visual appearance of the node. + self._update_node(cid, new_child) + + # Update the node data. + # + # The item data is a tuple. The first element indicates + # whether or not we have already populated the item with its + # children. The second element is the actual item data (which + # in our case is an arbitrary Python object provided by the + # tree model). + self.control.SetPyData(cid, (False, new_child)) + + # Remove the old node from the node to Id map. + self._remove_wxid(old_child) + + # Add the new node to the node to Id map. + self._set_wxid(new_child, cid) + + # Add listeners to the new node. + self.model.add_listener(new_child) + + # Does the new node have any children? + has_children = self._has_children(new_child) + self.control.SetItemHasChildren(cid, has_children) + + # Update the tree's selection (in case the old node that was replaced + # was selected, the selection should now include the new node). + self.selection = self._get_selection() + return + + def _on_structure_changed(self, event): + """ Called when the structure of a node has changed drastically. """ + + self.refresh(event.node) + + return + + #### wx event handlers #################################################### + + def _on_char(self, event): + """ Called when a key is pressed when the tree has focus. """ + + self.key_pressed = KeyPressedEvent( + alt_down = event.m_altDown == 1, + control_down = event.m_controlDown == 1, + shift_down = event.m_shiftDown == 1, + key_code = event.m_keyCode + ) + + event.Skip() + + return + + def _on_left_down(self, event): + """ Called when the left mouse button is clicked on the tree. """ + + data, id, flags, point = self._unpack_event(event) + + # Save point for tree_begin_drag method to workaround a bug in ?? when + # wx.TreeEvent.GetPoint returns only (0,0). This happens under linux + # when using wx-2.4.2.4, for instance. + self._point_left_clicked = point + + # Did the left click occur on a tree item? + if data is not None: + populated, node = data + + # Trait event notification. + self.node_left_clicked = node, point + + # Give other event handlers a chance. + event.Skip() + + return + + def _on_right_down(self, event): + """ Called when the right mouse button is clicked on the tree. """ + + data, id, flags, point = self._unpack_event(event) + + # Did the right click occur on a tree item? + if data is not None: + populated, node = data + + # Trait event notification. + self.node_right_clicked = node, point + + # Otherwise notify that the control itself was clicked + else: + self.control_right_clicked = point + + # Give other event handlers a chance. + event.Skip() + + return + + def _on_tree_item_activated(self, event): + """ Called when a tree item is activated (i.e., double clicked). """ + + # fixme: See the comment where the events are wired up for more + # information. + +## # Which item was activated? +## wxid = event.GetItem() + + # Which item was activated. + point = event.GetPosition() + wxid, flags = self.control.HitTest(point) + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + populated, node = self.control.GetPyData(wxid) + + # Trait event notiification. + self.node_activated = node + + return + + def _on_tree_item_collapsing(self, event): + """ Called when a tree item is about to collapse. """ + + # Which item is collapsing? + wxid = event.GetItem() + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + populated, node = self.control.GetPyData(wxid) + + # Give the model a chance to veto the collapse. + if not self.model.is_collapsible(node): + event.Veto() + + return + + def _on_tree_item_collapsed(self, event): + """ Called when a tree item has been collapsed. """ + + # Which item was collapsed? + wxid = event.GetItem() + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + populated, node = self.control.GetPyData(wxid) + + # Make sure that the item's 'closed' icon is displayed etc. + self._update_node(wxid, node) + + # Trait event notification. + self.node_collapsed = node + + return + + def _on_tree_item_expanding(self, event): + """ Called when a tree item is about to expand. """ + + # Which item is expanding? + wxid = event.GetItem() + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + populated, node = self.control.GetPyData(wxid) + + # Give the model a chance to veto the expansion. + if self.model.is_expandable(node): + # Lazily populate the item's children. + if not populated: + # Add the child nodes. + for child in self._get_children(node): + self._add_node(wxid, child) + + # The element is now populated! + self.control.SetPyData(wxid, (True, node)) + + else: + event.Veto() + + return + + def _on_tree_item_expanded(self, event): + """ Called when a tree item has been expanded. """ + + # Which item was expanded? + wxid = event.GetItem() + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + populated, node = self.control.GetPyData(wxid) + + # Make sure that the node's 'open' icon is displayed etc. + self._update_node(wxid, node) + + # Trait event notification. + self.node_expanded = node + + return + + def _on_tree_begin_label_edit(self, event): + """ Called when the user has started editing an item's label. """ + + wxid = event.GetItem() + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + populated, node = self.control.GetPyData(wxid) + + # Give the model a chance to veto the edit. + if not self.model.is_editable(node): + event.Veto() + + return + + def _on_tree_end_label_edit(self, event): + """ Called when the user has finished editing am item's label. """ + + wxid = event.GetItem() + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + populated, node = self.control.GetPyData(wxid) + + # Give the model a chance to veto the edit. + label = event.GetLabel() + + # Making sure the new label is not an empty string + + if label is not None and len(label) > 0 and \ + self.model.can_set_text(node, label): + def end_label_edit(): + """ Called to complete the label edit. """ + + # Set the node's text. + self.model.set_text(node, label) + + # If a label edit callback was specified (in the call to + # 'edit_label'), then call it). + if self._label_edit_callback is not None: + self._label_edit_callback(self, node, label) + + return + + # We use a deffered call here, because a name change can trigger + # the structure of a node to change, and hence the actual tree + # nodes might get moved/deleted before the label edit operation has + # completed. When this happens wx gets very confused! By using + # 'invoke_later' we allow the label edit to complete. + GUI.invoke_later(end_label_edit) + + else: + event.Veto() + + # If a label edit callback was specified (in the call to + # 'edit_label'), then call it). + if self._label_edit_callback is not None: + self._label_edit_callback(self, node, label) + + return + + def _on_tree_begin_drag(self, event): + """ Called when a drag operation is starting on a tree item. """ + + # Get the node, its id and the point where the event occurred. + data, wxid, flags, point = self._unpack_event(event, event.GetItem()) + + if point == (0,0): + # Apply workaround for GTK. + point = self.point_left_clicked + wxid, flags = self.HitTest(point) + data = self.control.GetPyData(wxid) + + if data is not None: + populated, node = data + + # Give the model a chance to veto the drag. + if self.model.is_draggable(node): + # We ask the model for the actual value to drag. + drag_value = self.model.get_drag_value(node) + + # fixme: This is a terrible hack to get the binding x passed + # during a drag operation. Bindings should probably *always* + # be dragged and our drag and drop mechanism should allow + # extendable ways to extract the actual data. + from pyface.wx.drag_and_drop import clipboard + clipboard.node = [node] + + # Make sure that the tree selection is updated before we start + # the drag. If we don't do this then if the first thing a + # user does is drag a tree item (i.e., without a separate click + # to select it first) then the selection appears empty. + self.selection = self._get_selection() + + # Start the drag. + PythonDropSource(self.control, drag_value, self) + + # Trait event notification. + self.node_begin_drag = node + + else: + event.Veto() + + return + + # fixme: This is part of the drag and drop hack... + def on_dropped(self): + """ Callback invoked when a drag/drop operation has completed. """ + + from pyface.wx.drag_and_drop import clipboard + clipboard.node = None + + return + + def _on_tree_sel_changed(self, event): + """ Called when the selection is changed. """ + + # Update our record of the selection to whatever was selected in the + # tree UNLESS we are ignoring selection events. + if not self._ignore_selection_events: + + # Trait notification. + self.selection = self._get_selection() + + return + + def _on_tree_delete_item(self, event): + """ Called when a tree item is being been deleted. """ + + # Which item is being deleted? + wxid = event.GetItem() + + # Check if GetPyData() returned a valid to tuple to unpack + # ...if so, remove the node from the tree, otherwise just return + # + # fixme: Whoever addeed this code (and the comment above) didn't say + # when this was occurring. This is method is called in response to a wx + # event to delete an item and hence the item data should never be None + # surely?!? Was it happening just on one platform?!? + data = self.control.GetPyData(wxid) + if data is not None: + # The item data is a tuple. The first element indicates whether or + # not we have already populated the item with its children. The + # second element is the actual item data. + populated, node = data + + # Remove the node. + self._remove_node(wxid, node) + + return + +#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/viewer/table_viewer.py python-pyface-6.1.2/pyface/ui/wx/viewer/table_viewer.py --- python-pyface-4.5.2/pyface/ui/wx/viewer/table_viewer.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/viewer/table_viewer.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,379 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" A viewer for tabular data. """ + + +# Major package imports. +import wx + +# Enthought library imports. +from traits.api import Color, Event, Instance, Trait + +# Local imports. +from pyface.ui.wx.image_list import ImageList +from pyface.viewer.content_viewer import ContentViewer +from pyface.viewer.table_column_provider import TableColumnProvider +from pyface.viewer.table_content_provider import TableContentProvider +from pyface.viewer.table_label_provider import TableLabelProvider + + +class TableViewer(ContentViewer): + """ A viewer for tabular data. """ + + # The content provider provides the actual table data. + content_provider = Instance(TableContentProvider) + + # The label provider provides, err, the labels for the items in the table + # (a label can have text and/or an image). + label_provider = Instance(TableLabelProvider, factory = TableLabelProvider) + + # The column provider provides information about the columns in the table + # (column headers, width etc). + column_provider=Trait(TableColumnProvider(),Instance(TableColumnProvider)) + + # The colours used to render odd and even numbered rows. + even_row_background = Color("white") + odd_row_background = Color((245, 245, 255)) + + # A row has been selected. + row_selected = Event + + # A row has been activated. + row_activated = Event + + # A drag operation was started on a node. + row_begin_drag = Event + + + def __init__(self, parent, image_size=(16, 16), **traits): + """ Creates a new table viewer. + + 'parent' is the toolkit-specific control that is the table's parent. + + 'image_size' is a tuple in the form (int width, int height) that + specifies the size of the images (if any) displayed in the table. + + """ + + # Base-class constructor. + super(TableViewer, self).__init__(**traits) + + # Create the toolkit-specific control. + self.control = table = _Table(parent, image_size, self) + + # Get our actual id. + wxid = table.GetId() + + # Table events. + wx.EVT_LIST_ITEM_SELECTED(table, wxid, self._on_item_selected) + wx.EVT_LIST_ITEM_ACTIVATED(table, wxid, self._on_item_activated) + wx.EVT_LIST_BEGIN_DRAG(table, wxid, self._on_list_begin_drag) + wx.EVT_LIST_BEGIN_RDRAG(table, wxid, self._on_list_begin_rdrag) + + wx.EVT_LIST_BEGIN_LABEL_EDIT( + table, wxid, self._on_list_begin_label_edit + ) + + wx.EVT_LIST_END_LABEL_EDIT( + table, wxid, self._on_list_end_label_edit + ) + + # fixme: Bug[732104] indicates that this event does not get fired + # in a virtual list control (it *does* get fired in a regular list + # control 8^(). + wx.EVT_LIST_ITEM_DESELECTED(table, wxid, self._on_item_deselected) + + # Create the widget! + self._create_widget(parent) + + # We use a dynamic handler instead of a static handler here, as we + # don't want to react if the input is set in the constructor. + self.on_trait_change(self._on_input_changed, 'input') + + return + + ########################################################################### + # 'TableViewer' interface. + ########################################################################### + + def select_row(self, row): + """ Select the specified row. """ + + self.control.SetItemState( + row, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED + ) + + self.control.SetItemState( + row, wx.LIST_STATE_FOCUSED, wx.LIST_STATE_FOCUSED + ) + + # Make sure that the selected row is visible. + fudge = max(0, row - 5) + self.EnsureVisible(fudge) + + # Trait event notification. + self.row_selected = row + + return + + ########################################################################### + # Trait event handlers. + ########################################################################### + + def _on_input_changed(self, obj, trait_name, old, new): + """ Called when the input is changed. """ + + # Update the table contents. + self._update_contents() + + if old is None: + self._update_column_widths() + + return + + ########################################################################### + # wx event handlers. + ########################################################################### + + def _on_item_selected(self, event): + """ Called when an item in the list is selected. """ + + # Get the index of the row that was selected (nice wx interface huh?!). + row = event.m_itemIndex + + # Trait event notification. + self.row_selected = row + + return + + # fixme: Bug[732104] indicates that this event does not get fired in a + # virtual list control (it *does* get fired in a regular list control 8^(). + def _on_item_deselected(self, event): + """ Called when an item in the list is selected. """ + + # Trait event notification. + self.row_selected = -1 + + return + + def _on_item_activated(self, event): + """ Called when an item in the list is activated. """ + + # Get the index of the row that was activated (nice wx interface!). + row = event.m_itemIndex + + # Trait event notification. + self.row_activated = row + + return + + def _on_list_begin_drag(self, event=None, is_rdrag=False): + """ Called when a drag operation is starting on a list item. """ + + # Trait notification. + self.row_begin_drag = event.GetIndex() + + return + + def _on_list_begin_rdrag(self, event=None): + """ Called when a drag operation is starting on a list item. """ + + self._on_list_begin_drag(event, True) + + return + + def _on_list_begin_label_edit(self, event=None): + """ Called when a label edit is started. """ + + event.Veto() + + return + + def _on_list_end_label_edit(self, event=None): + """ Called when a label edit is completed. """ + + return + + ########################################################################### + # Private interface. + ########################################################################### + + FORMAT_MAP = { + 'left' : wx.LIST_FORMAT_LEFT, + 'right' : wx.LIST_FORMAT_RIGHT, + 'center' : wx.LIST_FORMAT_CENTRE, + 'centre' : wx.LIST_FORMAT_CENTRE + } + + def _create_widget(self, parent): + """ Creates the widget. """ + + # Set up a default list item descriptor. + info = wx.ListItem() + info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT + + # Set the column headers. + for index in range(self.column_provider.column_count): + # Header text. + info.m_text = self.column_provider.get_label(self, index) + + # Alignment of header text AND ALL cells in the column. + alignment = self.column_provider.get_alignment(self, index) + info.m_format = self.FORMAT_MAP.get(alignment, wx.LIST_FORMAT_LEFT) + + self.control.InsertColumnInfo(index, info) + + # Update the table contents and the column widths. + self._update_contents() + self._update_column_widths() + + return + + def _update_contents(self): + """ Updates the table content. """ + + self._elements = [] + if self.input is not None: + # Filtering... + for element in self.content_provider.get_elements(self.input): + for filter in self.filters: + if not filter.select(self, self.input, element): + break + + else: + self._elements.append(element) + + # Sorting... + if self.sorter is not None: + self.sorter.sort(self, self.input, self._elements) + + # Setting this causes a refresh! + self.control.SetItemCount(len(self._elements)) + + return + + def _update_column_widths(self): + """ Updates the column widths. """ + + # Set all columns to be the size of their largest item, or the size of + # their header whichever is the larger. + for column in range(self.control.GetColumnCount()): + width = self.column_provider.get_width(self, column) + if width == -1: + width = self._get_column_width(column) + + self.control.SetColumnWidth(column, width) + + return + + def _get_column_width(self, column): + """ Return an appropriate width for the specified column. """ + + self.control.SetColumnWidth(column, wx.LIST_AUTOSIZE_USEHEADER) + header_width = self.control.GetColumnWidth(column) + + if self.control.GetItemCount() == 0: + width = header_width + + else: + self.control.SetColumnWidth(column, wx.LIST_AUTOSIZE) + data_width = self.control.GetColumnWidth(column) + + width = max(header_width, data_width) + + return width + + +class _Table(wx.ListCtrl): + """ The wx control that we use to implement the table viewer. """ + + # Default style. + STYLE = wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES | wx.STATIC_BORDER \ + | wx.LC_SINGLE_SEL | wx.LC_VIRTUAL | wx.LC_EDIT_LABELS \ + | wx.CLIP_CHILDREN + + def __init__(self, parent, image_size, viewer): + """ Creates a new table viewer. + + 'parent' is the toolkit-specific control that is the table's parent. + + 'image_size' is a tuple in the form (int width, int height) that + specifies the size of the icons (if any) displayed in the table. + + """ + + # The vierer that we are providing the control for. + self._viewer = viewer + + # Base-class constructor. + wx.ListCtrl.__init__(self, parent, -1, style=self.STYLE) + + # Table item images. + self._image_list = ImageList(image_size[0], image_size[1]) + self.AssignImageList(self._image_list, wx.IMAGE_LIST_SMALL) + + # Set up attributes to show alternate rows with a different background + # colour. + self._even_row_attribute = wx.ListItemAttr() + self._even_row_attribute.SetBackgroundColour( + self._viewer.even_row_background + ) + + self._odd_row_attribute = wx.ListItemAttr() + self._odd_row_attribute.SetBackgroundColour( + self._viewer.odd_row_background + ) + + return + + ########################################################################### + # Virtual 'ListCtrl' interface. + ########################################################################### + + def OnGetItemText(self, row, column_index): + """ Returns the text for the specified CELL. """ + + viewer = self._viewer + element = viewer._elements[row] + + return viewer.label_provider.get_text(viewer, element, column_index) + + def OnGetItemImage(self, row): + """ Returns the image for the specified ROW. """ + + viewer = self._viewer + element = viewer._elements[row] + + # Get the icon used to represent the node. + image = viewer.label_provider.get_image(viewer, element) + if image is not None: + image_index = self._image_list.GetIndex(image.absolute_path) + + else: + image_index = -1 + + return image_index + + def OnGetItemAttr(self, row): + """ Returns the attribute for the specified row. """ + + if row % 2 == 0: + attribute = self._even_row_attribute + + else: + attribute = self._odd_row_attribute + + return attribute + +#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/viewer/tree_viewer.py python-pyface-6.1.2/pyface/ui/wx/viewer/tree_viewer.py --- python-pyface-4.5.2/pyface/ui/wx/viewer/tree_viewer.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/viewer/tree_viewer.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,641 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" A viewer based on a tree control. """ + + +# Major package imports. +from __future__ import print_function +import wx + +# Enthought library imports. +from traits.api import Any, Bool, Enum, Event, Instance, List + +# Local imports. +from pyface.ui.wx.image_list import ImageList +from pyface.viewer.content_viewer import ContentViewer +from pyface.viewer.tree_content_provider import TreeContentProvider +from pyface.viewer.tree_label_provider import TreeLabelProvider +from pyface.wx.drag_and_drop import PythonDropSource + + +class TreeViewer(ContentViewer): + """ A viewer based on a tree control. """ + + # The default tree style. + STYLE = wx.TR_EDIT_LABELS | wx.TR_HAS_BUTTONS | wx.CLIP_CHILDREN + + #### 'TreeViewer' interface ############################################### + + # The content provider provides the actual tree data. + content_provider = Instance(TreeContentProvider) + + # The label provider provides, err, the labels for the items in the tree + # (a label can have text and/or an image). + label_provider = Instance(TreeLabelProvider, ()) + + # Selection mode (must be either of 'single' or 'extended'). + selection_mode = Enum('single', 'extended') + + # The currently selected elements. + selection = List + + # Should an image be shown for each element? + show_images = Bool(True) + + # Should the root of the tree be shown? + show_root = Bool(True) + + #### Events #### + + # An element has been activated (ie. double-clicked). + element_activated = Event + + # A drag operation was started on an element. + element_begin_drag = Event + + # An element that has children has been collapsed. + element_collapsed = Event + + # An element that has children has been expanded. + element_expanded = Event + + # A left-click occurred on an element. + element_left_clicked = Event + + # A right-click occurred on an element. + element_right_clicked = Event + + # A key was pressed while the tree is in focus. + key_pressed = Event + + ########################################################################### + # 'object' interface. + ########################################################################### + + def __init__(self, parent, image_size=(16, 16), **traits): + """ Creates a new tree viewer. + + 'parent' is the toolkit-specific control that is the tree's parent. + + 'image_size' is a tuple in the form (int width, int height) that + specifies the size of the label images (if any) displayed in the tree. + + """ + + # Base class constructor. + super(TreeViewer, self).__init__(**traits) + + # Create the toolkit-specific control. + self.control = tree = wx.TreeCtrl(parent, -1, style=self._get_style()) + + # Get our actual Id. + wxid = tree.GetId() + + # Wire up the wx tree events. + wx.EVT_CHAR(tree, self._on_char) + wx.EVT_LEFT_DOWN(tree, self._on_left_down) + wx.EVT_RIGHT_DOWN(tree, self._on_right_down) + wx.EVT_TREE_ITEM_ACTIVATED(tree, wxid, self._on_tree_item_activated) + wx.EVT_TREE_ITEM_COLLAPSED(tree, wxid, self._on_tree_item_collapsed) + wx.EVT_TREE_ITEM_COLLAPSING(tree, wxid, self._on_tree_item_collapsing) + wx.EVT_TREE_ITEM_EXPANDED(tree, wxid, self._on_tree_item_expanded) + wx.EVT_TREE_ITEM_EXPANDING(tree, wxid, self._on_tree_item_expanding) + wx.EVT_TREE_BEGIN_LABEL_EDIT(tree, wxid,self._on_tree_begin_label_edit) + wx.EVT_TREE_END_LABEL_EDIT(tree, wxid, self._on_tree_end_label_edit) + wx.EVT_TREE_BEGIN_DRAG(tree, wxid, self._on_tree_begin_drag) + wx.EVT_TREE_SEL_CHANGED(tree, wxid, self._on_tree_sel_changed) + + # The image list is a wxPython-ism that caches all images used in the + # control. + self._image_list = ImageList(image_size[0], image_size[1]) + if self.show_images: + tree.AssignImageList(self._image_list) + + # Mapping from element to wx tree item Ids. + self._element_to_id_map = {} + + # Add the root item. + if self.input is not None: + self._add_element(None, self.input) + + return + + ########################################################################### + # 'TreeViewer' interface. + ########################################################################### + + def is_expanded(self, element): + """ Returns True if the element is expanded, otherwise False. """ + + key = self._get_key(element) + + if key in self._element_to_id_map: + is_expanded = self.control.IsExpanded(self._element_to_id_map[key]) + + else: + is_expanded = False + + return is_expanded + + def is_selected(self, element): + """ Returns True if the element is selected, otherwise False. """ + + key = self._get_key(element) + + if key in self._element_to_id_map: + is_selected = self.control.IsSelected(self._element_to_id_map[key]) + + else: + is_selected = False + + return is_selected + + def refresh(self, element): + """ Refresh the tree starting from the specified element. + + Call this when the STRUCTURE of the content has changed. + + """ + + # Has the element actually appeared in the tree yet? + pid = self._element_to_id_map.get(self._get_key(element), None) + if pid is not None: + # The item data is a tuple. The first element indicates whether or + # not we have already populated the item with its children. The + # second element is the actual item data. + populated, element = self.control.GetPyData(pid) + + # fixme: We should find a cleaner way other than deleting all of + # the element's children and re-adding them! + self._delete_children(pid) + self.control.SetPyData(pid, (False, element)) + + # Does the element have any children? + has_children = self.content_provider.has_children(element) + self.control.SetItemHasChildren(pid, has_children) + + # Expand it. + self.control.Expand(pid) + + else: + print('**** pid is None!!! ****') + + return + + def update(self, element): + """ Update the tree starting from the specified element. + + Call this when the APPEARANCE of the content has changed. + + """ + + pid = self._element_to_id_map.get(self._get_key(element), None) + if pid is not None: + self._refresh_element(pid, element) + + for child in self.content_provider.get_children(element): + cid = self._element_to_id_map.get(self._get_key(child), None) + if cid is not None: + self._refresh_element(cid, child) + + return + + ########################################################################### + # Private interface. + ########################################################################### + + def _get_style(self): + """ Returns the wx style flags for creating the tree control. """ + + # Start with the default flags. + style = self.STYLE + + if not self.show_root: + style = style | wx.TR_HIDE_ROOT | wx.TR_LINES_AT_ROOT + + if self.selection_mode != 'single': + style = style | wx.TR_MULTIPLE | wx.TR_EXTENDED + + return style + + def _add_element(self, pid, element): + """ Adds 'element' as a child of the element identified by 'pid'. + + If 'pid' is None then we are adding the root element. + + """ + + # Get the tree item image index and text. + image_index = self._get_image_index(element) + text = self._get_text(element) + + # Add the element. + if pid is None: + wxid = self.control.AddRoot(text, image_index, image_index) + + else: + wxid = self.control.AppendItem(pid, text, image_index, image_index) + + # If we are adding the root element but the root is hidden, get its + # children. + if pid is None and not self.show_root: + children = self.content_provider.get_children(element) + for child in children: + self._add_element(wxid, child) + + # Does the element have any children? + has_children = self.content_provider.has_children(element) + self.control.SetItemHasChildren(wxid, has_children) + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + if pid is None: + if self.show_root: + self.control.SetPyData(wxid, (False, element)) + + else: + self.control.SetPyData(wxid, (False, element)) + + # Make sure that we can find the element's Id later. + self._element_to_id_map[self._get_key(element)] = wxid + + # If we are adding the root item then automatically expand it. + if pid is None and self.show_root: + self.control.Expand(wxid) + + return + + def _get_image_index(self, element): + """ Returns the tree item image index for an element. """ + + # Get the image used to represent the element. + image = self.label_provider.get_image(self, element) + if image is not None: + image_index = self._image_list.GetIndex(image.absolute_path) + + else: + image_index = -1 + + return image_index + + def _get_key(self, element): + """ Generate the key for the element to id map. """ + + try: + key = hash(element) + + except: + key = id(element) + + return key + + def _get_text(self, element): + """ Returns the tree item text for an element. """ + + text = self.label_provider.get_text(self, element) + if text is None: + text = '' + + return text + + def _refresh_element(self, wxid, element): + """ Refreshes the image and text of the specified element. """ + + # Get the tree item image index. + image_index = self._get_image_index(element) + self.control.SetItemImage(wxid, image_index, wx.TreeItemIcon_Normal) + self.control.SetItemImage(wxid, image_index, wx.TreeItemIcon_Selected) + + # Get the tree item text. + text = self._get_text(element) + self.control.SetItemText(wxid, text) + + # Does the item have any children? + has_children = self.content_provider.has_children(element) + self.control.SetItemHasChildren(wxid, has_children) + + return + + def _unpack_event(self, event): + """ Unpacks the event to see whether a tree element was involved. """ + + try: + point = event.GetPosition() + + except: + point = event.GetPoint() + + wxid, flags = self.control.HitTest(point) + + # Warning: On GTK we have to check the flags before we call 'GetPyData' + # because if we call it when the hit test returns 'nowhere' it will + # barf (on Windows it simply returns 'None' 8^() + if flags & wx.TREE_HITTEST_NOWHERE: + data = None + + else: + data = self.control.GetPyData(wxid) + + return data, wxid, flags, point + + def _get_selection(self): + """ Returns a list of the selected elements. """ + + elements = [] + for wxid in self.control.GetSelections(): + data = self.control.GetPyData(wxid) + if data is not None: + populated, element = data + elements.append(element) + + # 'data' can be None here if (for example) the element has been + # deleted. + # + # fixme: Can we stop this happening?!?!? + else: + pass + + return elements + + def _delete_children(self, pid): + """ Recursively deletes the children of the specified element. """ + + cookie = 0 + + (cid, cookie) = self.control.GetFirstChild(pid, cookie) + while cid.IsOk(): + # Recursively delete the child's children. + self._delete_children(cid) + + # Remove the reference to the item's data. + populated, element = self.control.GetPyData(cid) + del self._element_to_id_map[self._get_key(element)] + self.control.SetPyData(cid, None) + + # Next! + (cid, cookie) = self.control.GetNextChild(pid, cookie) + + self.control.DeleteChildren(pid) + + return + + #### Trait event handlers ################################################# + + def _input_changed(self): + """ Called when the tree's input has been changed. """ + + # Delete everything... + if self.control is not None: + self.control.DeleteAllItems() + + self._element_to_id_map = {} + + # ... and then add the root item back in. + if self.input is not None: + self._add_element(None, self.input) + + return + + def _element_begin_drag_changed(self, element): + """ Called when a drag is started on a element. """ + + # We ask the label provider for the actual value to drag. + drag_value = self.label_provider.get_drag_value(self, element) + + # Start the drag. + PythonDropSource(self.control, drag_value) + + return + + #### wx event handlers #################################################### + + def _on_right_down(self, event): + """ Called when the right mouse button is clicked on the tree. """ + + data, id, flags, point = self._unpack_event(event) + + # Did the right click occur on a tree item? + if data is not None: + populated, element = data + + # Trait notification. + self.element_right_clicked = (element, point) + + # Give other event handlers a chance. + event.Skip() + + return + + def _on_left_down(self, event): + """ Called when the left mouse button is clicked on the tree. """ + + data, wxid, flags, point = self._unpack_event(event) + + # Save point for tree_begin_drag method to workaround a bug in ?? when + # wx.TreeEvent.GetPoint returns only (0,0). This happens under linux + # when using wx-2.4.2.4, for instance. + self._point_left_clicked = point + + # Did the left click occur on a tree item? + if data is not None: + populated, element = data + + # Trait notification. + self.element_left_clicked = (element, point) + + # Give other event handlers a chance. + event.Skip() + + return + + def _on_tree_item_expanding(self, event): + """ Called when a tree item is about to expand. """ + + # Which item is expanding? + wxid = event.GetItem() + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + populated, element = self.control.GetPyData(wxid) + + # Give the label provider a chance to veto the expansion. + if self.label_provider.is_expandable(self, element): + # Lazily populate the item's children. + if not populated: + children = self.content_provider.get_children(element) + + # Sorting... + if self.sorter is not None: + self.sorter.sort(self, element, children) + + # Filtering.... + for child in children: + for filter in self.filters: + if not filter.select(self, element, child): + break + + else: + self._add_element(wxid, child) + + # The element is now populated! + self.control.SetPyData(wxid, (True, element)) + + else: + event.Veto() + + return + + def _on_tree_item_expanded(self, event): + """ Called when a tree item has been expanded. """ + + # Which item was expanded? + wxid = event.GetItem() + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + populated, element = self.control.GetPyData(wxid) + + # Make sure that the element's 'open' icon is displayed etc. + self._refresh_element(wxid, element) + + # Trait notification. + self.element_expanded = element + + return + + def _on_tree_item_collapsing(self, event): + """ Called when a tree item is about to collapse. """ + + # Which item is collapsing? + wxid = event.GetItem() + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + populated, element = self.control.GetPyData(wxid) + + # Give the label provider a chance to veto the collapse. + if not self.label_provider.is_collapsible(self, element): + event.Veto() + + return + + def _on_tree_item_collapsed(self, event): + """ Called when a tree item has been collapsed. """ + + # Which item was collapsed? + wxid = event.GetItem() + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + populated, element = self.control.GetPyData(wxid) + + # Make sure that the element's 'closed' icon is displayed etc. + self._refresh_element(wxid, element) + + # Trait notification. + self.element_collapsed = element + + return + + def _on_tree_item_activated(self, event): + """ Called when a tree item is activated (i.e., double clicked). """ + + # Which item was activated? + wxid = event.GetItem() + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + populated, element = self.control.GetPyData(wxid) + + # Trait notification. + self.element_activated = element + + return + + def _on_tree_sel_changed(self, event): + """ Called when the selection is changed. """ + + # Trait notification. + self.selection = self._get_selection() + + return + + def _on_tree_begin_drag(self, event): + """ Called when a drag operation is starting on a tree item. """ + + # Get the element, its id and the point where the event occurred. + data, wxid, flags, point = self._unpack_event(event) + + if point == (0,0): + # Apply workaround. + point = self._point_left_clicked + wxid, flags = self.control.HitTest(point) + data = self.control.GetPyData(wxid) + + if data is not None: + populated, element = data + + # Trait notification. + self.element_begin_drag = element + + return + + def _on_tree_begin_label_edit(self, event): + """ Called when the user has started editing an item's label. """ + + wxid = event.GetItem() + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + populated, element = self.control.GetPyData(wxid) + + # Give the label provider a chance to veto the edit. + if not self.label_provider.is_editable(self, element): + event.Veto() + + return + + def _on_tree_end_label_edit(self, event): + """ Called when the user has finished editing an item's label. """ + + wxid = event.GetItem() + + # The item data is a tuple. The first element indicates whether or not + # we have already populated the item with its children. The second + # element is the actual item data. + populated, element = self.control.GetPyData(wxid) + + # Give the label provider a chance to veto the edit. + label = event.GetLabel() + if not self.label_provider.set_text(self, element, label): + event.Veto() + + return + + def _on_char(self, event): + """ Called when a key is pressed when the tree has focus. """ + + # Trait notification. + self.key_pressed = event.GetKeyCode() + + return + +#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/widget.py python-pyface-6.1.2/pyface/ui/wx/widget.py --- python-pyface-4.5.2/pyface/ui/wx/widget.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/widget.py 2019-05-03 08:18:50.000000000 +0000 @@ -18,7 +18,7 @@ """ # Enthought library imports. -from traits.api import Any, HasTraits, provides +from traits.api import Any, Bool, HasTraits, provides # Local imports. from pyface.i_widget import IWidget, MWidget @@ -30,20 +30,49 @@ interface for the API documentation. """ + # 'IWidget' interface ---------------------------------------------------- - #### 'IWidget' interface ################################################## - + #: The toolkit specific control that represents the widget. control = Any + #: The control's optional parent control. parent = Any - ########################################################################### + #: Whether or not the control is visible + visible = Bool(True) + + #: Whether or not the control is enabled + enabled = Bool(True) + + # ------------------------------------------------------------------------ # 'IWidget' interface. - ########################################################################### + # ------------------------------------------------------------------------ + + def show(self, visible): + """ Show or hide the widget. + + Parameter + --------- + visible : bool + Visible should be ``True`` if the widget should be shown. + """ + self.visible = visible + if self.control is not None: + self.control.Show(visible) + + def enable(self, enabled): + """ Enable or disable the widget. + + Parameter + --------- + enabled : bool + The enabled state to set the widget to. + """ + self.enabled = enabled + if self.control is not None: + self.control.Enable(enabled) def destroy(self): if self.control is not None: self.control.Destroy() self.control = None - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/window.py python-pyface-6.1.2/pyface/ui/wx/window.py --- python-pyface-4.5.2/pyface/ui/wx/window.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/window.py 2019-06-14 11:44:07.000000000 +0000 @@ -1,6 +1,4 @@ -#------------------------------------------------------------------------------ -# -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2005-18, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -9,11 +7,6 @@ # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# -#------------------------------------------------------------------------------ - """ Enthought pyface package component """ @@ -21,14 +14,13 @@ import wx # Enthought library imports. -from traits.api import Any, Event, Property, provides, Unicode -from traits.api import Tuple +from traits.api import Event, Property, Tuple, Unicode, VetoableEvent, provides # Local imports. from pyface.i_window import IWindow, MWindow from pyface.key_pressed_event import KeyPressedEvent -from system_metrics import SystemMetrics -from widget import Widget +from .system_metrics import SystemMetrics +from .widget import Widget @provides(IWindow) @@ -37,8 +29,7 @@ interface for the API documentation. """ - - #### 'IWindow' interface ################################################## + # 'IWindow' interface ----------------------------------------------------- position = Property(Tuple) @@ -46,23 +37,32 @@ title = Unicode - #### Events ##### + # Window Events ---------------------------------------------------------- + #: The window has been opened. + opened = Event + + #: The window is about to open. + opening = VetoableEvent + + #: The window has been activated. activated = Event - closed = Event + #: The window has been closed. + closed = Event - closing = Event + #: The window is about to be closed. + closing = VetoableEvent + #: The window has been deactivated. deactivated = Event + #: A key was pressed while the window had focus. + # FIXME v3: This smells of a hack. What's so special about key presses? + # FIXME v3: Unicode key_pressed = Event(KeyPressedEvent) - opened = Event - - opening = Event - - #### Private interface #################################################### + # Private interface ------------------------------------------------------ # Shadow trait for position. _position = Tuple((-1, -1)) @@ -70,9 +70,9 @@ # Shadow trait for size. _size = Tuple((-1, -1)) - ########################################################################### + # ------------------------------------------------------------------------- # 'IWindow' interface. - ########################################################################### + # ------------------------------------------------------------------------- def activate(self): self.control.Iconize(False) @@ -81,20 +81,21 @@ def show(self, visible): self.control.Show(visible) - ########################################################################### + # ------------------------------------------------------------------------- # Protected 'IWindow' interface. - ########################################################################### + # ------------------------------------------------------------------------- def _add_event_listeners(self): - wx.EVT_ACTIVATE(self.control, self._wx_on_activate) - wx.EVT_CLOSE(self.control, self._wx_on_close) - wx.EVT_SIZE(self.control, self._wx_on_control_size) - wx.EVT_MOVE(self.control, self._wx_on_control_move) - wx.EVT_CHAR(self.control, self._wx_on_char) + self.control.Bind(wx.EVT_ACTIVATE, self._wx_on_activate) + self.control.Bind(wx.EVT_SHOW, self._wx_on_show) + self.control.Bind(wx.EVT_CLOSE, self._wx_on_close) + self.control.Bind(wx.EVT_SIZE, self._wx_on_control_size) + self.control.Bind(wx.EVT_MOVE, self._wx_on_control_move) + self.control.Bind(wx.EVT_CHAR, self._wx_on_char) - ########################################################################### + # ------------------------------------------------------------------------- # Protected 'IWidget' interface. - ########################################################################### + # ------------------------------------------------------------------------- def _create_control(self, parent): # create a basic window control @@ -102,19 +103,25 @@ style = wx.DEFAULT_FRAME_STYLE \ | wx.FRAME_NO_WINDOW_MENU \ | wx.CLIP_CHILDREN - control = wx.Frame( - parent, -1, self.title, style=style, size=self.size, + parent, + -1, + self.title, + style=style, + size=self.size, pos=self.position ) - control.SetBackgroundColour(SystemMetrics().dialog_background_color) + control.Enable(self.enabled) + + # XXX starting with self.visible true is generally a bad idea + control.Show(self.visible) return control - ########################################################################### + # ------------------------------------------------------------------------- # Private interface. - ########################################################################### + # ------------------------------------------------------------------------- def _get_position(self): """ Property getter for position. """ @@ -154,7 +161,7 @@ if self.control is not None: self.control.SetTitle(title) - #### wx event handlers #################################################### + # wx event handlers ------------------------------------------------------ def _wx_on_activate(self, event): """ Called when the frame is being activated or deactivated. """ @@ -164,6 +171,15 @@ else: self.deactivated = self + event.Skip() + + def _wx_on_show(self, event): + """ Called when the frame is being activated or deactivated. """ + + self.visible = event.IsShown() + + event.Skip() + def _wx_on_close(self, event): """ Called when the frame is being closed. """ @@ -198,13 +214,11 @@ """ Called when a key is pressed when the tree has focus. """ self.key_pressed = KeyPressedEvent( - alt_down = event.m_altDown == 1, - control_down = event.m_controlDown == 1, - shift_down = event.m_shiftDown == 1, - key_code = event.m_keyCode, - event = event + alt_down=event.m_altDown == 1, + control_down=event.m_controlDown == 1, + shift_down=event.m_shiftDown == 1, + key_code=event.m_keyCode, + event=event ) event.Skip() - -#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui/wx/workbench/workbench_window_layout.py python-pyface-6.1.2/pyface/ui/wx/workbench/workbench_window_layout.py --- python-pyface-4.5.2/pyface/ui/wx/workbench/workbench_window_layout.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/workbench/workbench_window_layout.py 2019-05-03 08:18:50.000000000 +0000 @@ -18,7 +18,7 @@ """ # Standard library imports. -import cPickle +import six.moves.cPickle import logging # Major package imports. @@ -30,16 +30,15 @@ from pyface.dock.api import DockControl, DockRegion, DockSection from pyface.dock.api import DockSizer from traits.api import Delegate -from traitsui.dockable_view_element import DockableViewElement # Mixin class imports. from pyface.workbench.i_workbench_window_layout import \ MWorkbenchWindowLayout # Local imports. -from editor_set_structure_handler import EditorSetStructureHandler -from view_set_structure_handler import ViewSetStructureHandler -from workbench_dock_window import WorkbenchDockWindow +from .editor_set_structure_handler import EditorSetStructureHandler +from .view_set_structure_handler import ViewSetStructureHandler +from .workbench_dock_window import WorkbenchDockWindow # Logging. @@ -248,17 +247,23 @@ return + def is_editor_area_visible(self): + dock_control = self._wx_view_dock_window.get_control( + self.editor_area_id, visible_only=False + ) + return dock_control.visible + #### Methods for saving and restoring the layout ########################## def get_view_memento(self): structure = self._wx_view_dock_window.get_structure() # We always return a clone. - return cPickle.loads(cPickle.dumps(structure)) + return six.moves.cPickle.loads(six.moves.cPickle.dumps(structure)) def set_view_memento(self, memento): # We always use a clone. - memento = cPickle.loads(cPickle.dumps(memento)) + memento = six.moves.cPickle.loads(six.moves.cPickle.dumps(memento)) # The handler knows how to resolve view Ids when setting the dock # window structure. @@ -645,6 +650,7 @@ # fixme: Should we roll the traits UI stuff into the default editor. if hasattr(editor, 'ui') and editor.ui is not None: + from traitsui.dockable_view_element import DockableViewElement # This makes the control draggable outside of the main window. #editor_dock_control.export = 'pyface.workbench.editor' editor_dock_control.dockable = DockableViewElement( @@ -695,6 +701,7 @@ # fixme: Should we roll the traits UI stuff into the default editor. if hasattr(view, 'ui') and view.ui is not None: + from traitsui.dockable_view_element import DockableViewElement # This makes the control draggable outside of the main window. #view_dock_control.export = 'pyface.workbench.view' diff -Nru python-pyface-4.5.2/pyface/ui/wx/xrc_dialog.py python-pyface-6.1.2/pyface/ui/wx/xrc_dialog.py --- python-pyface-4.5.2/pyface/ui/wx/xrc_dialog.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui/wx/xrc_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,122 @@ +#----------------------------------------------------------------------------- +# +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# Author: Scott Swarts +# +#----------------------------------------------------------------------------- + +"""A dialog that is loaded from an XRC resource file. +""" +from __future__ import absolute_import + +# Standard library imports. +import os.path + +# Major packages. +import wx +import wx.xrc + +# Enthought library imports +from traits.api import Instance, Str +import traits.util.resource + +# Local imports. +from .dialog import Dialog + + +############################################################################## +# class 'XrcDialog' +############################################################################## + +class XrcDialog(Dialog): + """A dialog that is loaded from an XRC resource file. + """ + + ########################################################################## + # Traits + ########################################################################## + + ### 'XrcDialog' interface ############################################ + + # Path to the xrc file relative to the class's module + xrc_file = Str + + # The ID of the dialog in the file + id = Str("dialog") + + # The resource object + resource = Instance(wx.xrc.XmlResource) + + ########################################################################## + # 'Dialog' interface + ########################################################################## + + def _create_control(self, parent): + """ + Creates the dialog and loads it in from the resource file. + """ + classpath = traits.util.resource.get_path( self ) + path = os.path.join( classpath, self.xrc_file ) + + self.resource = wx.xrc.XmlResource( path ) + return self.resource.LoadDialog(parent, self.id) + + def _create_contents(self, dialog): + """ + Calls add_handlers. The actual content is created + in _create_control by loading a resource file. + """ + # Wire up the standard buttons + # We change the ID on OK and CANCEL to the standard ids + # so we get the default behavior + okbutton = self.XRCCTRL("OK") + if okbutton is not None: + # Change the ID and set the handler + okbutton.SetId(wx.ID_OK) + wx.EVT_BUTTON(self.control, okbutton.GetId(), self._on_ok) + cancelbutton = self.XRCCTRL("CANCEL") + if cancelbutton is not None: + # Change the ID and set the handler + cancelbutton.SetId(wx.ID_CANCEL) + wx.EVT_BUTTON(self.control, cancelbutton.GetId(), self._on_cancel) + helpbutton = self.XRCCTRL("HELP") + if helpbutton is not None: + wx.EVT_BUTTON(self.control, helpbutton.GetId(), self._on_help) + + self._add_handlers() + + ########################################################################## + # 'XrcDialog' interface + ########################################################################## + + def XRCID(self, name): + """ + Returns the numeric widget id for the given name. + """ + return wx.xrc.XRCID(name) + + def XRCCTRL(self, name): + """ + Returns the control with the given name. + """ + return self.control.FindWindowById(self.XRCID(name)) + + def set_validator(self, name, validator): + """ + Sets the validator on the named control. + """ + self.XRCCTRL(name).SetValidator(validator) + + ########################################################################## + # 'XrcDialog' protected interface + ########################################################################## + + def _add_handlers(self): + """ + Override to add event handlers. + """ + return + +#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/ui_traits.py python-pyface-6.1.2/pyface/ui_traits.py --- python-pyface-4.5.2/pyface/ui_traits.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/ui_traits.py 2019-06-18 11:33:39.000000000 +0000 @@ -0,0 +1,265 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2016, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# +# Thanks for using Enthought open source! +# +# Author: Enthought Developers +# +#------------------------------------------------------------------------------ + +""" Defines common traits used within the pyface library. """ +import logging + +from traits.api import ABCHasStrictTraits, Enum, Range, TraitError, TraitType +from traits.trait_base import get_resource_path +try: + from traits.trait_handlers import CALLABLE_AND_ARGS_DEFAULT_VALUE +except ImportError: + CALLABLE_AND_ARGS_DEFAULT_VALUE = 7 +import six + + +logger = logging.getLogger(__name__) + +#------------------------------------------------------------------------------- +# Images +#------------------------------------------------------------------------------- + +image_resource_cache = {} +image_bitmap_cache = {} + + +def convert_image(value, level=3): + """ Converts a specified value to an ImageResource if possible. + """ + if not isinstance( value, six.string_types ): + return value + + key = value + is_pyface_image = value.startswith('@') + if not is_pyface_image: + search_path = get_resource_path(level) + key = '%s[%s]' % (value, search_path) + + result = image_resource_cache.get(key) + if result is None: + if is_pyface_image: + try: + from .image.image import ImageLibrary + result = ImageLibrary.image_resource(value) + except Exception as exc: + logger.error("Can't load image resource '%s'." % value) + logger.exception(exc) + result = None + else: + from pyface.image_resource import ImageResource + result = ImageResource(value, search_path=[search_path]) + + image_resource_cache[key] = result + + return result + + +def convert_bitmap(image_resource): + """ Converts an ImageResource to a bitmap using a cache. + """ + bitmap = image_bitmap_cache.get(image_resource) + if (bitmap is None) and (image_resource is not None): + image_bitmap_cache[image_resource] = bitmap = \ + image_resource.create_bitmap() + + return bitmap + + +class Image(TraitType): + """ Defines a trait whose value must be a ImageResource or a string + that can be converted to one. + """ + + # Define the default value for the trait: + default_value = None + + # A description of the type of value this trait accepts: + info_text = 'an ImageResource or string that can be used to define one' + + def __init__(self, value=None, **metadata): + """ Creates an Image trait. + + Parameters + ---------- + value : string or ImageResource + The default value for the Image, either an ImageResource object, + or a string from which an ImageResource object can be derived. + """ + super(Image, self).__init__(convert_image(value), **metadata) + + def validate(self, object, name, value): + """ Validates that a specified value is valid for this trait. + """ + from pyface.i_image_resource import IImageResource + + if value is None: + return None + + new_value = convert_image(value, 4) + if isinstance(new_value, IImageResource): + return new_value + + self.error(object, name, value) + + def create_editor(self): + """ Returns the default UI editor for the trait. + """ + from traitsui.editors.api import ImageEditor + return ImageEditor() + + +#------------------------------------------------------------------------------- +# Borders, Margins and Layout +#------------------------------------------------------------------------------- + +class BaseMB(ABCHasStrictTraits): + + def __init__(self, *args, **traits): + """ Map posiitonal arguments to traits. + + If one value is provided it is taken as the value for all sides. + If two values are provided, then the first argument is used for + left and right, while the second is used for top and bottom. + If 4 values are provided, then the arguments are mapped to + left, right, top, and bottom, respectively. + """ + n = len(args) + if n > 0: + if n == 1: + left = right = top = bottom = args[0] + elif n == 2: + left = right = args[0] + top = bottom = args[1] + elif n == 4: + left, right, top, bottom = args + else: + raise TraitError('0, 1, 2 or 4 arguments expected, but %d ' + 'specified' % n) + traits.update({'left': left, 'right': right, + 'top': top, 'bottom': bottom}) + + super(BaseMB, self).__init__(**traits) + + +class Margin(BaseMB): + + # The amount of padding/margin at the top: + top = Range(-32, 32, 0) + + # The amount of padding/margin at the bottom: + bottom = Range(-32, 32, 0) + + # The amount of padding/margin on the left: + left = Range(-32, 32, 0) + + # The amount of padding/margin on the right: + right = Range(-32, 32, 0) + + +class Border(BaseMB): + + # The amount of border at the top: + top = Range(0, 32, 0) + + # The amount of border at the bottom: + bottom = Range(0, 32, 0) + + # The amount of border on the left: + left = Range(0, 32, 0) + + # The amount of border on the right: + right = Range(0, 32, 0) + + +class HasMargin(TraitType): + """ Defines a trait whose value must be a Margin object or an integer or + tuple value that can be converted to one. + """ + + # The desired value class: + klass = Margin + + # Define the default value for the trait: + default_value = Margin(0) + + # A description of the type of value this trait accepts: + info_text = ('a Margin instance, or an integer in the range from -32 to 32 ' + 'or a tuple with 1, 2 or 4 integers in that range that can be ' + 'used to define one') + + def validate (self, object, name, value): + """ Validates that a specified value is valid for this trait. + """ + if isinstance(value, int): + try: + value = self.klass(value) + except Exception: + self.error(object, name, value) + elif isinstance(value, tuple): + try: + value = self.klass(*value) + except Exception: + self.error(object, name, value) + + if isinstance(value, self.klass): + return value + + self.error(object, name, value) + + def get_default_value(self): + """ Returns a tuple of the form: + (default_value_type, default_value) + which describes the default value for this trait. + """ + dv = self.default_value + dvt = self.default_value_type + if dvt < 0: + if isinstance(dv, int): + dv = self.klass(dv) + elif isinstance(dv, tuple): + dv = self.klass(*dv) + + if not isinstance(dv, self.klass): + return super(HasMargin, self).get_default_value() + + self.default_value_type = dvt = CALLABLE_AND_ARGS_DEFAULT_VALUE + dv = (self.klass, (), dv.trait_get()) + + return (dvt, dv) + + +class HasBorder(HasMargin): + """ Defines a trait whose value must be a Border object or an integer + or tuple value that can be converted to one. + """ + + # The desired value class: + klass = Border + + # Define the default value for the trait: + default_value = Border(0) + + # A description of the type of value this trait accepts: + info_text = ('a Border instance, or an integer in the range from 0 to 32 ' + 'or a tuple with 1, 2 or 4 integers in that range that can be ' + 'used to define one') + + +#: The position of an image relative to its associated text. +Position = Enum('left', 'right', 'above', 'below') + +#: The alignment of text within a control. +Alignment = Enum('default', 'left', 'center', 'right') diff -Nru python-pyface-4.5.2/pyface/util/fix_introspect_bug.py python-pyface-6.1.2/pyface/util/fix_introspect_bug.py --- python-pyface-4.5.2/pyface/util/fix_introspect_bug.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/util/fix_introspect_bug.py 2019-06-18 10:52:41.000000000 +0000 @@ -29,6 +29,7 @@ from wx.py import introspect import types +import six # The fixed function. def getAttributeNames(object, includeMagic=1, includeSingle=1, @@ -39,8 +40,8 @@ if not introspect.hasattrAlwaysReturnsTrue(object): # Add some attributes that don't always get picked up. special_attrs = ['__bases__', '__class__', '__dict__', '__name__', - 'func_closure', 'func_code', 'func_defaults', - 'func_dict', 'func_doc', 'func_globals', 'func_name'] + '__closure__', '__code__', '___kwdefaults__', + '__doc__', '__globals__'] attributes += [attr for attr in special_attrs \ if hasattr(object, attr)] # For objects that have traits, get all the trait names since @@ -72,12 +73,12 @@ # Remove duplicates from the attribute list. for item in attributes: dict[item] = None - attributes = dict.keys() + attributes = list(dict.keys()) # new-style swig wrappings can result in non-string attributes # e.g. ITK http://www.itk.org/ attributes = [attribute for attribute in attributes \ - if isinstance(attribute, basestring)] - attributes.sort(lambda x, y: cmp(x.upper(), y.upper())) + if isinstance(attribute, six.string_types)] + attributes.sort(key=lambda x: x.upper()) if not includeSingle: attributes = filter(lambda item: item[0]!='_' \ or item[1]=='_', attributes) @@ -116,7 +117,7 @@ attrdict[(key, 'dir', len(attributes))] = attributes # Get attributes from the object's dictionary, if it has one. try: - attributes = object.__dict__.keys() + attributes = list(object.__dict__.keys()) attributes.sort() except: # Must catch all because object might have __getattr__. pass diff -Nru python-pyface-4.5.2/pyface/util/font_helper.py python-pyface-6.1.2/pyface/util/font_helper.py --- python-pyface-4.5.2/pyface/util/font_helper.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/util/font_helper.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,27 +6,12 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -""" Utility functions for working with wx Fonts. """ - - -# Major package imports. -import wx - - -def new_font_like(font, **kw): - """ Creates a new font, like another one, only different. Maybe. """ - point_size = kw.get('point_size', font.GetPointSize()) - family = kw.get('family', font.GetFamily()) - style = kw.get('style', font.GetStyle()) - weight = kw.get('weight', font.GetWeight()) - underline = kw.get('underline', font.GetUnderlined()) - face_name = kw.get('face_name', font.GetFaceName()) +import logging - return wx.Font(point_size, family, style, weight, underline, face_name) +logger = logging.getLogger(__name__) +logger.warning( + 'DEPRECATED: pyface.util.font_helper, use pyface.wx.utils.font_helper instead. ' + 'Will be removed in Pyface 7.') -### EOF ####################################################################### +from pyface.wx.util.font_helper import * diff -Nru python-pyface-4.5.2/pyface/util/grid/api.py python-pyface-6.1.2/pyface/util/grid/api.py --- python-pyface-4.5.2/pyface/util/grid/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/util/grid/api.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,11 +6,12 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -from grid import Grid -from grid_column import GridColumn -from grid_model import GridModel -from grid_row import GridRow + +import logging + +logger = logging.getLogger(__name__) +logger.warning( + 'DEPRECATED: pyface.util.grid.api, use pyface.wx.grid.api instead. ' + 'Will be removed in Pyface 7.') + +from pyface.wx.grid.api import * diff -Nru python-pyface-4.5.2/pyface/util/grid/grid_column.py python-pyface-6.1.2/pyface/util/grid/grid_column.py --- python-pyface-4.5.2/pyface/util/grid/grid_column.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/util/grid/grid_column.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,27 +6,12 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -""" A description of a column in a grid. """ - - -# Enthought library imports. -from traits.api import Bool, HasTraits, Str - - -class GridColumn(HasTraits): - """ A description of a column in a grid. """ - - # Column header. - label = Str - # Type name of data allowed in the column. - type = Str +import logging - # Is the column read-only? - readonly = Bool(False) +logger = logging.getLogger(__name__) +logger.warning( + 'DEPRECATED: pyface.util.grid.grid_column, use pyface.wx.grid.grid_column instead. ' + 'Will be removed in Pyface 7.') -#### EOF ###################################################################### +from pyface.wx.grid.grid_column import * diff -Nru python-pyface-4.5.2/pyface/util/grid/grid_model.py python-pyface-6.1.2/pyface/util/grid/grid_model.py --- python-pyface-4.5.2/pyface/util/grid/grid_model.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/util/grid/grid_model.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,277 +6,12 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -""" A model that provides data for a grid. """ - -# Major package imports. -import wx -from wx.grid import PyGridTableBase, GridTableMessage, GRIDTABLE_NOTIFY_ROWS_APPENDED - -# Enthought library imports. -from traits.api import Any, Bool, HasTraits, Trait, Event, List -from traits.standard import false_trait, true_trait - -# Local imports. -from grid_column import GridColumn -from grid_row import GridRow - - -class GridModel(HasTraits): - """ A model that provides data for a grid. """ - - # fixme : factor this default model into "SimpleGridModel" or similar - # An optional 2-dimensional list/array containing the grid data. - data = Any - - # The rows in the model. - rows = List(GridRow) - - # The columns in the model. - columns = List(GridColumn) - - # Show row headers? - show_row_headers = Bool(True) - - # Show column headers? - show_column_headers = Bool(True) - - # Fired when the data in the model has changed. - model_changed = Event - - - def __init__(self, **traits): - """ Create a new grid model. """ - - # Base class constructors. - HasTraits.__init__(self, **traits) - - # The wx virtual table hook. - self._grid_table_base = _GridTableBase(self) - - if len(self.columns) == 0 and self.data is not None: - print "Building default table column model" - columns = [] - # Assume data is rectangular and use the length of the first row. - for i in range(len(self.data[0])): - columns.append(GridColumn(label=str(i))) - self.columns = columns - - return - - ########################################################################### - # 'wxPyGridTableBase' interface. - ########################################################################### - - def GetNumberRows(self): - """ Return the number of rows in the model. """ - - return len(self.data) - - def GetNumberCols(self): - """ Return the number of columns in the model. """ - - return len(self.columns) - - def IsEmptyCell(self, row, col): - """ Is the specified cell empty? """ - - try: - return not self.data[row][col] - - except IndexError: - return True - - # Get/Set values in the table. The Python versions of these methods can - # handle any data-type, (as long as the Editor and Renderer understands the - # type too,) not just strings as in the C++ version. - def GetValue(self, row, col): - """ Get the value at the specified row and column. """ - - try: - return self.data[row][col] - - except IndexError: - pass - - return '' - - def SetValue(self, row, col, value): - """ Set the value at the specified row and column. """ - - label = self.GetColLabelValue(col) - - try: - self.data[row][col] = value - - except IndexError: - # Add a new row. - self.data.append([0] * self.GetNumberCols()) - self.data[row][col] = value - - # Tell the grid that we've added a row. - # - # N.B wxGridTableMessage(table, whatWeDid, howMany) - message = GridTableMessage( - self, GRIDTABLE_NOTIFY_ROWS_APPENDED, 1 - ) - - # Trait event notification. - self.model_changed = message - - return - - def GetRowLabelValue(self, row): - """ Called when the grid needs to display a row label. """ - - return str(row) - - def GetColLabelValue(self, col): - """ Called when the grid needs to display a column label. """ - - return self.columns[col].label - - def GetTypeName(self, row, col): - """ Called to determine the kind of editor/renderer to use. - - This doesn't necessarily have to be the same type used natively by the - editor/renderer if they know how to convert. - - """ - - return self.columns[col].type - - def CanGetValueAs(self, row, col, type_name): - """ Called to determine how the data can be fetched. - - This allows you to enforce some type-safety in the grid. - - """ - - column_typename = self.GetTypeName(row, col) - - return type_name == column_typename - - def CanSetValueAs(self, row, col, type_name): - """ Called to determine how the data can be stored. - - This allows you to enforce some type-safety in the grid. - - """ - - return self.CanGetValueAs(row, col, type_name) - - def DeleteRows(self, pos, num_rows): - """ Called when the view is deleting rows. """ - - del self.data[pos:pos + num_rows] - - # Tell the grid that we've deleted some rows. - # - # N.B Because of a bug in wxPython we have to send a "rows appended" - # --- message with a negative number, instead of the "rows deleted" - # message 8^() TINSTAFS! - message = GridTableMessage( - self, GRIDTABLE_NOTIFY_ROWS_APPENDED, -num_rows - ) - - # Trait event notification. - self.model_changed = message - - return True - - -class _GridTableBase(PyGridTableBase): - """ A model that provides data for a grid. """ - - ########################################################################### - # 'object' interface. - ########################################################################### - - def __init__(self, model): - """ Creates a new table base. """ - - # Base class constructor. - PyGridTableBase.__init__(self) - - # The Pyface model that provides the data. - self.model = model - - return - - ########################################################################### - # 'wxPyGridTableBase' interface. - ########################################################################### - - def GetNumberRows(self): - """ Return the number of rows in the model. """ - - return self.model.GetNumberRows() - - def GetNumberCols(self): - """ Return the number of columns in the model. """ - - return self.model.GetNumberCols() - - def IsEmptyCell(self, row, col): - """ Is the specified cell empty? """ - - return self.model.IsEmptyCell(row, col) - - def GetValue(self, row, col): - """ Get the value at the specified row and column. """ - - return self.model.GetValue(row, col) - - def SetValue(self, row, col, value): - """ Set the value at the specified row and column. """ - - return self.model.SetValue(row, col, value) - - def GetRowLabelValue(self, row): - """ Called when the grid needs to display a row label. """ - - return self.model.GetRowLabelValue(row) - - def GetColLabelValue(self, col): - """ Called when the grid needs to display a column label. """ - - return self.model.GetColLabelValue(col) - - def GetTypeName(self, row, col): - """ Called to determine the kind of editor/renderer to use. - - This doesn't necessarily have to be the same type used natively by the - editor/renderer if they know how to convert. - - """ - - return self.model.GetTypeName(row, col) - - def CanGetValueAs(self, row, col, type_name): - """ Called to determine how the data can be fetched. - - This allows you to enforce some type-safety in the grid. - - """ - - return self.model.CanGetValueAs(row, col, type_name) - - def CanSetValueAs(self, row, col, type_name): - """ Called to determine how the data can be stored. - - This allows you to enforce some type-safety in the grid. - - """ - - return self.model.CanSetValueAs(row, col, type_name) - def DeleteRows(self, pos, num_rows): - """ Called when the view is deleting rows. """ +import logging - return self.model.DeleteRows(pos, num_rows) +logger = logging.getLogger(__name__) +logger.warning( + 'DEPRECATED: pyface.util.grid.grid_model, use pyface.wx.grid.grid_model instead. ' + 'Will be removed in Pyface 7.') -#### EOF ###################################################################### +from pyface.wx.grid.grid_model import * diff -Nru python-pyface-4.5.2/pyface/util/grid/grid.py python-pyface-6.1.2/pyface/util/grid/grid.py --- python-pyface-4.5.2/pyface/util/grid/grid.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/util/grid/grid.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,347 +6,12 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -""" A grid (spreadsheet) widget. """ - - -# Major package imports. -import wx -from wx.grid import Grid as wxGrid - - -# Local imports. -from grid_model import GridModel - - -class Grid(wxGrid): - """ A grid (spreadsheet) widget. """ - - def __init__(self, parent, model): - """ Constructor. """ - - # Base class constructor. - wxGrid.__init__(self, parent, -1) - - # The model that provides the data and row/column information. - self.model = None - - # Automatically size columns and rows to fit their content. - # - # fixme: wx seems sensitive to the location of these two lines. Put - # them *before* the call to 'SetTable', otherwise the grid takes - # forever to initialize! - ##self.AutoSizeColumns() - ##self.AutoSizeRows() - - # Don't display any extra space around the rows and columns. - self.SetMargins(0, 0) - - # Tell the grid to get its data from the model. - # - # N.B The terminology used in the wxPython API is a little confusing! - # --- The 'SetTable' method is actually setting the model used by - # the grid (which is the view)! - # - # The second parameter to 'SetTable' tells the grid to take ownership - # of the model and to destroy it when it is done. Otherwise you would - # need to keep a reference to the model and manually destroy it later - # (by calling it's Destroy method). - # - # fixme: We should create a default model if one is not supplied. - self.SetTable(model._grid_table_base, True) - model.on_trait_change(self._on_model_changed, 'model_changed') - - wx.grid.EVT_GRID_CELL_CHANGE(self, self._on_cell_change) - wx.grid.EVT_GRID_SELECT_CELL(self, self._on_select_cell) - - # This starts the cell editor on a double-click as well as on a second - # click. - wx.grid.EVT_GRID_CELL_LEFT_DCLICK(self, self._on_cell_left_dclick) - - # This pops up a context menu. - #wx.grid.EVT_GRID_CELL_RIGHT_CLICK(self, self._on_cell_right_click) - - # We handle key presses to change the behavior of the and - # keys to make manual data entry smoother. - wx.EVT_KEY_DOWN(self, self._on_key_down) - - # Initialize the row and column models. - self._initialize_rows(model) - self._initialize_columns(model) - self._initialize_fonts() - - return - - def _initialize_fonts(self): - """ Initialize the label fonts. """ - - self.SetLabelFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD)) - self.SetGridLineColour("blue") - self.SetColLabelAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) - self.SetRowLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTRE) - - return - - def _initialize_rows(self, model): - """ Initialize the row headers. """ - - if not model.show_row_headers: - self.SetRowLabelSize(0) - - else: - for index, row in enumerate(model.rows): - if row.readonly: - attr = wx.grid.GridCellAttr() - attr.SetReadOnly() - attr.SetRenderer(None) - attr.SetBackgroundColour('linen') - self.SetRowAttr(index, attr) - - return - - def _initialize_columns(self, model): - """ Initialize the column headers. """ - - if not model.show_column_headers: - self.SetColLabelSize(0) - - else: - for index, column in enumerate(model.columns): - if column.readonly: - attr = wx.grid.GridCellAttr() - attr.SetReadOnly() - attr.SetRenderer(None) - attr.SetBackgroundColour('linen') - self.SetColAttr(index, attr) - - return - - ########################################################################### - # wx event handlers. - ########################################################################### - - def _on_cell_change(self, evt): - """ Called when the contents of a cell have been changed. """ - - row = evt.GetRow() - col = evt.GetCol() - - ##print 'Cell changed at', row, col - value = self.GetTable().GetValue(row, col) - - ##print 'New value', value - ##print 'Type', type(value) - - evt.Skip() - - return - - def _on_select_cell(self, evt): - """ Called when the user has moved to another cell. """ - - ##row = evt.GetRow() - ##col = evt.GetCol() - - ##print 'Cell selected at', row, col - - evt.Skip() - - return - - def _on_cell_left_dclick(self, evt): - """ Called when the left mouse button was double-clicked. - - From the wxPython demo code:- - - 'I do this because I don't like the default behaviour of not starting - the cell editor on double clicks, but only a second click.' - - Fair enuff! - - """ - - if self.CanEnableCellControl(): - self.EnableCellEditControl() - - return - - def _on_cell_right_click(self, evt): - """ Called when a right click occurred in a cell. """ - - row = evt.GetRow() - - # The last row in the table is not part of the actual data, it is just - # there to allow the user to enter a new row. Hence they cannot delete - # it! - if row < self.GetNumberRows() - 1: - # Complete the edit on the current cell. - self.DisableCellEditControl() - - # Make the row the ONLY one selected. - self.SelectRow(row) - - # Popup a context menu allowing the user to delete the row. - menu = wx.Menu() - menu.Append(101, "Delete Row") - wx.EVT_MENU(self, 101, self._on_delete_row) - - self.PopupMenu(menu, evt.GetPosition()) - - return - - def _on_key_down(self, evt): - """ Called when a key is pressed. """ - - # This changes the behaviour of the and keys to make - # manual data entry smoother! - # - # Don't change the behavior if the key is pressed as this - # has meaning to the edit control. - key_code = evt.GetKeyCode() - if key_code == wx.WXK_RETURN and not evt.ControlDown(): - self._move_to_next_cell(evt.ShiftDown()) - - elif key_code == wx.WXK_TAB and not evt.ControlDown(): - if evt.ShiftDown(): - self._move_to_previous_cell() - - else: - self._move_to_next_cell() - - else: - evt.Skip() - - return - - def _on_delete_row(self, evt): - """ Called when the 'Delete Row' context menu item is selected. """ - - # Get the selected row (there must be exactly one at this point!). - selected_rows = self.GetSelectedRows() - if len(selected_rows) == 1: - self.DeleteRows(selected_rows[0], 1) - - return - - ########################################################################### - # Trait event handlers. - ########################################################################### - - def _on_model_changed(self, message): - """ Called when the model has changed. """ - - self.BeginBatch() - self.ProcessTableMessage(message) - self.EndBatch() - - return - - ########################################################################### - # 'Grid' interface. - ########################################################################### - - def Reset(self): - print 'Reset' - #attr = grid.GridCellAttr() - #renderer = MyRenderer() - #attr.SetRenderer(renderer) - - #self.SetColSize(0, 50) - #self.SetColAttr(0, attr) - - self.ForceRefresh() - - return - - - def ResetView(self, grid): - """ - (wxGrid) -> Reset the grid view. Call this to - update the grid if rows and columns have been added or deleted - """ - print '*************************VirtualModel.reset_view' - - grid = self - - grid.BeginBatch() - for current, new, delmsg, addmsg in [ - (self._rows, self.GetNumberRows(), GRIDTABLE_NOTIFY_ROWS_DELETED, GRIDTABLE_NOTIFY_ROWS_APPENDED), - (self._cols, self.GetNumberCols(), GRIDTABLE_NOTIFY_COLS_DELETED, GRIDTABLE_NOTIFY_COLS_APPENDED), - ]: - if new < current: - msg = GridTableMessage(self,delmsg,new,current-new) - grid.ProcessTableMessage(msg) - elif new > current: - msg = GridTableMessage(self,addmsg,new-current) - grid.ProcessTableMessage(msg) - self.UpdateValues(grid) - grid.EndBatch() - - self._rows = self.GetNumberRows() - self._cols = self.GetNumberCols() - - # update the renderers - # self._updateColAttrs(grid) - # self._updateRowAttrs(grid) too expensive to use on a large grid - - # update the scrollbars and the displayed part of the grid - grid.AdjustScrollbars() - grid.ForceRefresh() - - return - - - - ########################################################################### - # Protected interface. - ########################################################################### - - def _move_to_next_cell(self, expandSelection=False): - """ Move to the 'next' cell. """ - - # Complete the edit on the current cell. - self.DisableCellEditControl() - - # Try to move to the next column. - success = self.MoveCursorRight(expandSelection) - - # If the move failed then we must be at the end of a row. - if not success: - # Move to the first column in the next row. - newRow = self.GetGridCursorRow() + 1 - if newRow < self.GetNumberRows(): - self.SetGridCursor(newRow, 0) - self.MakeCellVisible(newRow, 0) - - else: - # This would be a good place to add a new row if your app - # needs to do that. - pass - - return success - - def _move_to_previous_cell(self, expandSelection=False): - """ Move to the 'previous' cell. """ - - # Complete the edit on the current cell. - self.DisableCellEditControl() - - # Try to move to the previous column (without expanding the current - # selection). - success = self.MoveCursorLeft(expandSelection) - # If the move failed then we must be at the start of a row. - if not success: - # Move to the last column in the previous row. - newRow = self.GetGridCursorRow() - 1 - if newRow >= 0: - self.SetGridCursor(newRow, self.GetNumberCols() - 1) - self.MakeCellVisible(newRow, self.GetNumberCols() - 1) +import logging - return +logger = logging.getLogger(__name__) +logger.warning( + 'DEPRECATED: pyface.util.grid.grid, use pyface.wx.grid.grid instead. ' + 'Will be removed in Pyface 7.') -#### EOF ###################################################################### +from pyface.wx.grid.grid import * diff -Nru python-pyface-4.5.2/pyface/util/grid/grid_row.py python-pyface-6.1.2/pyface/util/grid/grid_row.py --- python-pyface-4.5.2/pyface/util/grid/grid_row.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/util/grid/grid_row.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,26 +6,12 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -""" A description of a row in a grid. """ - - -# Enthought library imports. -from traits.api import HasTraits -from traits.standard import false_trait, true_trait - - -class GridRow(HasTraits): - """ A description of a row in a grid. """ - - def __init__(self, row_data): - """ Create a new row. """ - self.__dict__.update(row_data) +import logging - return +logger = logging.getLogger(__name__) +logger.warning( + 'DEPRECATED: pyface.util.grid.grid_row, use pyface.wx.grid.grid_row instead. ' + 'Will be removed in Pyface 7.') -#### EOF ###################################################################### +from pyface.wx.grid.grid_row import * diff -Nru python-pyface-4.5.2/pyface/util/grid/__init__.py python-pyface-6.1.2/pyface/util/grid/__init__.py --- python-pyface-4.5.2/pyface/util/grid/__init__.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/util/grid/__init__.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,7 +6,12 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ + +import logging + +logger = logging.getLogger(__name__) +logger.warning( + 'DEPRECATED: pyface.util.grid, use pyface.wx.grid instead. ' + 'Will be removed in Pyface 7.') + +from pyface.wx.grid import * diff -Nru python-pyface-4.5.2/pyface/util/guisupport.py python-pyface-6.1.2/pyface/util/guisupport.py --- python-pyface-4.5.2/pyface/util/guisupport.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/util/guisupport.py 2019-05-03 08:18:50.000000000 +0000 @@ -79,7 +79,7 @@ import wx app = wx.GetApp() if app is None: - if not kwargs.has_key('redirect'): + if 'redirect' not in kwargs: kwargs['redirect'] = False app = wx.PySimpleApp(*args, **kwargs) return app diff -Nru python-pyface-4.5.2/pyface/util/python_stc.py python-pyface-6.1.2/pyface/util/python_stc.py --- python-pyface-4.5.2/pyface/util/python_stc.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/util/python_stc.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,403 +6,12 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -import wx -from wx import stc - -import keyword - -#---------------------------------------------------------------------- - -demoText = """\ -## This version of the editor has been set up to edit Python source -## code. Here is a copy of wxPython/demo/Main.py to play with. - - -""" - -#---------------------------------------------------------------------- - - -if wx.Platform == '__WXMSW__': - faces = { 'times': 'Times New Roman', - 'mono' : 'Courier New', - 'helv' : 'Arial', - 'other': 'Comic Sans MS', - 'size' : 10, - 'size2': 8, - } -else: - faces = { 'times': 'Times', - 'mono' : 'Courier', - 'helv' : 'Helvetica', - 'other': 'new century schoolbook', - 'size' : 12, - 'size2': 10, - } - - -#---------------------------------------------------------------------- - -class PythonSTC(stc.StyledTextCtrl): - def __init__(self, parent, ID): - stc.StyledTextCtrl.__init__(self, parent, ID, - style = wx.NO_FULL_REPAINT_ON_RESIZE) - - self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN) - self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT) - - self.SetLexer(stc.STC_LEX_PYTHON) - self.SetKeyWords(0, " ".join(keyword.kwlist)) - - self.SetProperty("fold", "1") - self.SetProperty("tab.timmy.whinge.level", "1") - self.SetMargins(0,0) - - self.SetViewWhiteSpace(False) - #self.SetBufferedDraw(False) - - self.SetEdgeMode(stc.STC_EDGE_BACKGROUND) - self.SetEdgeColumn(78) - - # Setup a margin to hold fold markers - ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER? - self.SetFoldFlags(16) - #mic - #self.SetMarginType(2, stc.STC_MARGIN_SYMBOL) - #self.SetMarginMask(2, stc.STC_MASK_FOLDERS) - #self.SetMarginSensitive(2, True) - #self.SetMarginWidth(2, 12) - # line numbers in the margin - self.SetMarginType(1, stc.STC_MARGIN_NUMBER) - self.SetMarginWidth(1, 25) - - if 0: # simple folder marks, like the old version - self.MarkerDefine(stc.STC_MARKNUM_FOLDER, - stc.STC_MARK_ARROW, "navy", "navy") - self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, - stc.STC_MARK_ARROWDOWN, "navy", "navy") - # Set these to an invisible mark - self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, - stc.STC_MARK_BACKGROUND, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, - stc.STC_MARK_BACKGROUND, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, - stc.STC_MARK_BACKGROUND, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, - stc.STC_MARK_BACKGROUND, "white", "black") - - elif 0: # more involved "outlining" folder marks - self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, - stc.STC_MARK_BOXPLUSCONNECTED, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, - stc.STC_MARK_BOXMINUSCONNECTED, - "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, - stc.STC_MARK_TCORNER, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, - stc.STC_MARK_LCORNER, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, - stc.STC_MARK_VLINE, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDER, - stc.STC_MARK_BOXPLUS, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, - stc.STC_MARK_BOXMINUS, "white", "black") - - - stc.EVT_STC_UPDATEUI(self, ID, self.OnUpdateUI) - stc.EVT_STC_MARGINCLICK(self, ID, self.OnMarginClick) - - - # 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. - - self.StyleClearAll() - - # Global default styles for all languages - self.StyleSetSpec(stc.STC_STYLE_DEFAULT, - "face:%(helv)s,size:%(size)d" % faces) - self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, - "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces) - self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, - "face:%(other)s" % faces) - self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, - "fore:#FFFFFF,back:#0000FF,bold") - self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, - "fore:#000000,back:#FF0000,bold") - - # Python styles - # White space - self.StyleSetSpec(stc.STC_P_DEFAULT, - "fore:#808080,face:%(helv)s,size:%(size)d" % faces) - # Comment - self.StyleSetSpec(stc.STC_P_COMMENTLINE, - "fore:#007F00,face:%(other)s,size:%(size)d" % faces) - # Number - self.StyleSetSpec(stc.STC_P_NUMBER, - "fore:#007F7F,size:%(size)d" % faces) - # String - self.StyleSetSpec(stc.STC_P_STRING, - "fore:#7F007F,italic,face:%(times)s,size:%(size)d" % faces) - # Single quoted string - self.StyleSetSpec(stc.STC_P_CHARACTER, - "fore:#7F007F,italic,face:%(times)s,size:%(size)d" % faces) - # Keyword - self.StyleSetSpec(stc.STC_P_WORD, - "fore:#00007F,bold,size:%(size)d" % faces) - # Triple quotes - self.StyleSetSpec(stc.STC_P_TRIPLE, - "fore:#7F0000,size:%(size)d" % faces) - # Triple double quotes - self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, - "fore:#7F0000,size:%(size)d" % faces) - # Class name definition - self.StyleSetSpec(stc.STC_P_CLASSNAME, - "fore:#0000FF,bold,underline,size:%(size)d" % faces) - # Function or method name definition - self.StyleSetSpec(stc.STC_P_DEFNAME, - "fore:#007F7F,bold,size:%(size)d" % faces) - # Operators - self.StyleSetSpec(stc.STC_P_OPERATOR, - "bold,size:%(size)d" % faces) - # Identifiers - self.StyleSetSpec(stc.STC_P_IDENTIFIER, - "fore:#808080,face:%(helv)s,size:%(size)d" % faces) - # Comment-blocks - self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, - "fore:#7F7F7F,size:%(size)d" % faces) - # End of line where string is not closed - self.StyleSetSpec(stc.STC_P_STRINGEOL, - "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces) - - - self.SetCaretForeground("BLUE") - - wx.EVT_KEY_DOWN(self, self.OnKeyPressed) - - - def OnKeyPressed(self, event): - if self.CallTipActive(): - self.CallTipCancel() - - # KeyCode used to be a method. Now it is an integer. - # Handle either case. - if type(event.KeyCode) is int: - # wx2.8+ - key = event.KeyCode - else: - # wx2.6 - key = event.KeyCode() - - if key == 32 and event.ControlDown(): - pos = self.GetCurrentPos() - # Tips - if event.ShiftDown(): - self.CallTipSetBackground("yellow") - self.CallTipShow(pos, 'param1, param2') - # Code completion - else: - # fixme: What is this mess!!! - - #lst = [] - #for x in range(50000): - # lst.append('%05d' % x) - #st = " ".join(lst) - #print len(st) - #self.AutoCompShow(0, st) - - # fixme: What is this mess!!! - kw = keyword.kwlist[:] - kw.append("zzzzzz") - kw.append("aaaaa") - kw.append("__init__") - kw.append("zzaaaaa") - kw.append("zzbaaaa") - kw.append("this_is_a_longer_value") - kw.append("this_is_a_much_much_much_much_longer_value") - - kw.sort() # Python sorts are case sensitive - self.AutoCompSetIgnoreCase(False) # so this needs to match - - self.AutoCompShow(0, " ".join(kw)) - 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==stc.STC_P_OPERATOR): - braceAtCaret = caretPos - 1 - - # check after - if braceAtCaret < 0: - charAfter = self.GetCharAt(caretPos) - styleAfter = self.GetStyleAt(caretPos) - if (charAfter and - chr(charAfter) in "[]{}()" and - styleAfter == stc.STC_P_OPERATOR): - braceAtCaret = caretPos - - if braceAtCaret >= 0: - braceOpposite = self.BraceMatch(braceAtCaret) - - if braceAtCaret != -1 and braceOpposite == -1: - self.BraceBadLight(braceAtCaret) - else: - self.BraceHighlight(braceAtCaret, braceOpposite) - #pt = self.PointFromPosition(braceOpposite) - #self.Refresh(True, 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) & 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 FoldAll(self): - lineCount = self.GetLineCount() - expanding = True - - # find out if we are folding or unfolding - for lineNum in range(lineCount): - if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG: - expanding = not self.GetFoldExpanded(lineNum) - break; - - lineNum = 0 - while lineNum < lineCount: - level = self.GetFoldLevel(lineNum) - if level & stc.STC_FOLDLEVELHEADERFLAG and \ - (level & stc.STC_FOLDLEVELNUMBERMASK) == 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 & 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 - - -#---------------------------------------------------------------------- - -_USE_PANEL = 1 - -def runTest(frame, nb, log): - if not _USE_PANEL: - ed = p = stc.PythonSTC(nb, -1) - else: - p = wx.Panel(nb, -1, style = wx.NO_FULL_REPAINT_ON_RESIZE) - ed = PythonSTC(p, -1) - s = wx.BoxSizer(wx.HORIZONTAL) - s.Add(ed, 1, wx.EXPAND) - p.SetSizer(s) - p.SetAutoLayout(True) - - - ed.SetText(demoText + open('Main.py').read()) - ed.EmptyUndoBuffer() - ed.Colourise(0, -1) - - # line numbers in the margin - ed.SetMarginType(1, stc.STC_MARGIN_NUMBER) - ed.SetMarginWidth(1, 25) - - return p - - - -#---------------------------------------------------------------------- - - -overview = """\ - -Once again, no docs yet. Sorry. But this -and this should -be helpful. - -""" - -if __name__ == '__main__': - # fixme: This has been re-factored into not working. No run module. - import sys,os - import run - run.main(['', os.path.basename(sys.argv[0])]) +import logging -#---------------------------------------------------------------------- +logger = logging.getLogger(__name__) +logger.warning( + 'DEPRECATED: pyface.util.python_stc, use pyface.wx.python_stc instead. ' + 'Will be removed in Pyface 7.') +from pyface.wx.python_stc import * diff -Nru python-pyface-4.5.2/pyface/util/testing.py python-pyface-6.1.2/pyface/util/testing.py --- python-pyface-4.5.2/pyface/util/testing.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/util/testing.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,21 @@ +from functools import wraps + + +def has_traitsui(): + """ Is traitsui installed? """ + try: + import traitsui + except ImportError: + return False + return True + + +def skip_if_no_traitsui(test): + """ Decorator that skips test if traitsui not available """ + @wraps(test) + def new_test(self): + if has_traitsui(): + test(self) + else: + self.skipTest("Can't import traitsui.") + return new_test diff -Nru python-pyface-4.5.2/pyface/_version.py python-pyface-6.1.2/pyface/_version.py --- python-pyface-4.5.2/pyface/_version.py 2015-08-14 15:55:52.000000000 +0000 +++ python-pyface-6.1.2/pyface/_version.py 2019-07-22 09:15:04.000000000 +0000 @@ -1,7 +1,7 @@ # THIS FILE IS GENERATED FROM PYFACE SETUP.PY -version = '4.5.2' -full_version = '4.5.2' -git_revision = '91c4cba' +version = '6.1.2' +full_version = '6.1.2' +git_revision = 'Unknown' is_released = True if not is_released: diff -Nru python-pyface-4.5.2/pyface/viewer/api.py python-pyface-6.1.2/pyface/viewer/api.py --- python-pyface-4.5.2/pyface/viewer/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/viewer/api.py 2019-05-03 08:18:50.000000000 +0000 @@ -11,19 +11,23 @@ # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ -from column_provider import ColumnProvider -from content_provider import ContentProvider -from content_viewer import ContentViewer -from default_tree_content_provider import DefaultTreeContentProvider -from label_provider import LabelProvider -from table_column_provider import TableColumnProvider -from table_content_provider import TableContentProvider -from table_label_provider import TableLabelProvider -from table_viewer import TableViewer -from tree_content_provider import TreeContentProvider -from tree_label_provider import TreeLabelProvider -from tree_item import TreeItem -from tree_viewer import TreeViewer -from viewer import Viewer -from viewer_filter import ViewerFilter -from viewer_sorter import ViewerSorter +from __future__ import absolute_import + +from .column_provider import ColumnProvider +from .content_provider import ContentProvider +from .content_viewer import ContentViewer +from .default_tree_content_provider import DefaultTreeContentProvider +from .label_provider import LabelProvider +from .table_column_provider import TableColumnProvider +from .table_content_provider import TableContentProvider +from .table_label_provider import TableLabelProvider +from .tree_content_provider import TreeContentProvider +from .tree_label_provider import TreeLabelProvider +from .tree_item import TreeItem +from .viewer import Viewer +from .viewer_filter import ViewerFilter +from .viewer_sorter import ViewerSorter + +# these are only implemented in wx at the moment +from .table_viewer import TableViewer +from .tree_viewer import TreeViewer diff -Nru python-pyface-4.5.2/pyface/viewer/content_viewer.py python-pyface-6.1.2/pyface/viewer/content_viewer.py --- python-pyface-4.5.2/pyface/viewer/content_viewer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/viewer/content_viewer.py 2019-05-03 08:18:50.000000000 +0000 @@ -18,9 +18,9 @@ from traits.api import Any, Instance, List # Local imports. -from viewer import Viewer -from viewer_filter import ViewerFilter -from viewer_sorter import ViewerSorter +from .viewer import Viewer +from .viewer_filter import ViewerFilter +from .viewer_sorter import ViewerSorter class ContentViewer(Viewer): diff -Nru python-pyface-4.5.2/pyface/viewer/default_tree_content_provider.py python-pyface-6.1.2/pyface/viewer/default_tree_content_provider.py --- python-pyface-4.5.2/pyface/viewer/default_tree_content_provider.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/viewer/default_tree_content_provider.py 2019-05-03 08:18:50.000000000 +0000 @@ -15,7 +15,7 @@ # Local imports. -from tree_content_provider import TreeContentProvider +from .tree_content_provider import TreeContentProvider class DefaultTreeContentProvider(TreeContentProvider): diff -Nru python-pyface-4.5.2/pyface/viewer/table_column_provider.py python-pyface-6.1.2/pyface/viewer/table_column_provider.py --- python-pyface-4.5.2/pyface/viewer/table_column_provider.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/viewer/table_column_provider.py 2019-05-03 08:18:50.000000000 +0000 @@ -18,7 +18,7 @@ from traits.api import Int # Local imports. -from column_provider import ColumnProvider +from .column_provider import ColumnProvider class TableColumnProvider(ColumnProvider): diff -Nru python-pyface-4.5.2/pyface/viewer/table_content_provider.py python-pyface-6.1.2/pyface/viewer/table_content_provider.py --- python-pyface-4.5.2/pyface/viewer/table_content_provider.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/viewer/table_content_provider.py 2019-05-03 08:18:50.000000000 +0000 @@ -15,7 +15,7 @@ # Local imports. -from content_provider import ContentProvider +from .content_provider import ContentProvider class TableContentProvider(ContentProvider): diff -Nru python-pyface-4.5.2/pyface/viewer/table_label_provider.py python-pyface-6.1.2/pyface/viewer/table_label_provider.py --- python-pyface-4.5.2/pyface/viewer/table_label_provider.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/viewer/table_label_provider.py 2019-05-03 08:18:50.000000000 +0000 @@ -15,7 +15,7 @@ # Local imports. -from label_provider import LabelProvider +from .label_provider import LabelProvider class TableLabelProvider(LabelProvider): diff -Nru python-pyface-4.5.2/pyface/viewer/table_viewer.py python-pyface-6.1.2/pyface/viewer/table_viewer.py --- python-pyface-4.5.2/pyface/viewer/table_viewer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/viewer/table_viewer.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,374 +6,11 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ -""" A viewer for tabular data. """ - - -# Major package imports. -import wx - -# Enthought library imports. -from pyface.image_list import ImageList -from traits.api import Color, Event, Instance, Trait - -# Local imports. -from content_viewer import ContentViewer -from table_column_provider import TableColumnProvider -from table_content_provider import TableContentProvider -from table_label_provider import TableLabelProvider - - -class TableViewer(ContentViewer): - """ A viewer for tabular data. """ - - - # The content provider provides the actual table data. - content_provider = Instance(TableContentProvider) - - # The label provider provides, err, the labels for the items in the table - # (a label can have text and/or an image). - label_provider = Instance(TableLabelProvider, factory = TableLabelProvider) - - # The column provider provides information about the columns in the table - # (column headers, width etc). - column_provider=Trait(TableColumnProvider(),Instance(TableColumnProvider)) - - # The colours used to render odd and even numbered rows. - even_row_background = Color("white") - odd_row_background = Color((245, 245, 255)) - - # A row has been selected. - row_selected = Event - - # A row has been activated. - row_activated = Event - - # A drag operation was started on a node. - row_begin_drag = Event - - - def __init__(self, parent, image_size=(16, 16), **traits): - """ Creates a new table viewer. - - 'parent' is the toolkit-specific control that is the table's parent. - - 'image_size' is a tuple in the form (int width, int height) that - specifies the size of the images (if any) displayed in the table. - - """ - - # Base-class constructor. - super(TableViewer, self).__init__(**traits) - - # Create the toolkit-specific control. - self.control = table = _Table(parent, image_size, self) - - # Get our actual id. - wxid = table.GetId() - - # Table events. - wx.EVT_LIST_ITEM_SELECTED(table, wxid, self._on_item_selected) - wx.EVT_LIST_ITEM_ACTIVATED(table, wxid, self._on_item_activated) - wx.EVT_LIST_BEGIN_DRAG(table, wxid, self._on_list_begin_drag) - wx.EVT_LIST_BEGIN_RDRAG(table, wxid, self._on_list_begin_rdrag) - - wx.EVT_LIST_BEGIN_LABEL_EDIT( - table, wxid, self._on_list_begin_label_edit - ) - - wx.EVT_LIST_END_LABEL_EDIT( - table, wxid, self._on_list_end_label_edit - ) - - # fixme: Bug[732104] indicates that this event does not get fired - # in a virtual list control (it *does* get fired in a regular list - # control 8^(). - wx.EVT_LIST_ITEM_DESELECTED(table, wxid, self._on_item_deselected) - - # Create the widget! - self._create_widget(parent) - - # We use a dynamic handler instead of a static handler here, as we - # don't want to react if the input is set in the constructor. - self.on_trait_change(self._on_input_changed, 'input') - - return - - ########################################################################### - # 'TableViewer' interface. - ########################################################################### - - def select_row(self, row): - """ Select the specified row. """ - - self.control.SetItemState( - row, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED - ) - - self.control.SetItemState( - row, wx.LIST_STATE_FOCUSED, wx.LIST_STATE_FOCUSED - ) - - # Make sure that the selected row is visible. - fudge = max(0, row - 5) - self.EnsureVisible(fudge) - - # Trait event notification. - self.row_selected = row - - return - - ########################################################################### - # Trait event handlers. - ########################################################################### - - def _on_input_changed(self, obj, trait_name, old, new): - """ Called when the input is changed. """ - - # Update the table contents. - self._update_contents() - - if old is None: - self._update_column_widths() - - return - - ########################################################################### - # wx event handlers. - ########################################################################### - - def _on_item_selected(self, event): - """ Called when an item in the list is selected. """ - - # Get the index of the row that was selected (nice wx interface huh?!). - row = event.m_itemIndex - - # Trait event notification. - self.row_selected = row - - return - - # fixme: Bug[732104] indicates that this event does not get fired in a - # virtual list control (it *does* get fired in a regular list control 8^(). - def _on_item_deselected(self, event): - """ Called when an item in the list is selected. """ - - # Trait event notification. - self.row_selected = -1 - - return - - def _on_item_activated(self, event): - """ Called when an item in the list is activated. """ - - # Get the index of the row that was activated (nice wx interface!). - row = event.m_itemIndex - - # Trait event notification. - self.row_activated = row - - return - - def _on_list_begin_drag(self, event=None, is_rdrag=False): - """ Called when a drag operation is starting on a list item. """ - - # Trait notification. - self.row_begin_drag = event.GetIndex() - - return - - def _on_list_begin_rdrag(self, event=None): - """ Called when a drag operation is starting on a list item. """ - - self._on_list_begin_drag(event, True) - - return - - def _on_list_begin_label_edit(self, event=None): - """ Called when a label edit is started. """ - - event.Veto() - - return - - def _on_list_end_label_edit(self, event=None): - """ Called when a label edit is completed. """ - - return - - ########################################################################### - # Private interface. - ########################################################################### - - FORMAT_MAP = { - 'left' : wx.LIST_FORMAT_LEFT, - 'right' : wx.LIST_FORMAT_RIGHT, - 'center' : wx.LIST_FORMAT_CENTRE, - 'centre' : wx.LIST_FORMAT_CENTRE - } - - def _create_widget(self, parent): - """ Creates the widget. """ - - # Set up a default list item descriptor. - info = wx.ListItem() - info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT - - # Set the column headers. - for index in range(self.column_provider.column_count): - # Header text. - info.m_text = self.column_provider.get_label(self, index) - - # Alignment of header text AND ALL cells in the column. - alignment = self.column_provider.get_alignment(self, index) - info.m_format = self.FORMAT_MAP.get(alignment, wx.LIST_FORMAT_LEFT) - - self.control.InsertColumnInfo(index, info) - - # Update the table contents and the column widths. - self._update_contents() - self._update_column_widths() - - return - - def _update_contents(self): - """ Updates the table content. """ - - self._elements = [] - if self.input is not None: - # Filtering... - for element in self.content_provider.get_elements(self.input): - for filter in self.filters: - if not filter.select(self, self.input, element): - break - - else: - self._elements.append(element) - - # Sorting... - if self.sorter is not None: - self.sorter.sort(self, self.input, self._elements) - - # Setting this causes a refresh! - self.control.SetItemCount(len(self._elements)) - - return - - def _update_column_widths(self): - """ Updates the column widths. """ - - # Set all columns to be the size of their largest item, or the size of - # their header whichever is the larger. - for column in range(self.control.GetColumnCount()): - width = self.column_provider.get_width(self, column) - if width == -1: - width = self._get_column_width(column) - - self.control.SetColumnWidth(column, width) - - return - - def _get_column_width(self, column): - """ Return an appropriate width for the specified column. """ - - self.control.SetColumnWidth(column, wx.LIST_AUTOSIZE_USEHEADER) - header_width = self.control.GetColumnWidth(column) - - if self.control.GetItemCount() == 0: - width = header_width - - else: - self.control.SetColumnWidth(column, wx.LIST_AUTOSIZE) - data_width = self.control.GetColumnWidth(column) - - width = max(header_width, data_width) - - return width - - -class _Table(wx.ListCtrl): - """ The wx control that we use to implement the table viewer. """ - - # Default style. - STYLE = wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES | wx.STATIC_BORDER \ - | wx.LC_SINGLE_SEL | wx.LC_VIRTUAL | wx.LC_EDIT_LABELS \ - | wx.CLIP_CHILDREN - - def __init__(self, parent, image_size, viewer): - """ Creates a new table viewer. - - 'parent' is the toolkit-specific control that is the table's parent. - - 'image_size' is a tuple in the form (int width, int height) that - specifies the size of the icons (if any) displayed in the table. - - """ - - # The vierer that we are providing the control for. - self._viewer = viewer - - # Base-class constructor. - wx.ListCtrl.__init__(self, parent, -1, style=self.STYLE) - - # Table item images. - self._image_list = ImageList(image_size[0], image_size[1]) - self.AssignImageList(self._image_list, wx.IMAGE_LIST_SMALL) - - # Set up attributes to show alternate rows with a different background - # colour. - self._even_row_attribute = wx.ListItemAttr() - self._even_row_attribute.SetBackgroundColour( - self._viewer.even_row_background - ) - - self._odd_row_attribute = wx.ListItemAttr() - self._odd_row_attribute.SetBackgroundColour( - self._viewer.odd_row_background - ) - - return - - ########################################################################### - # Virtual 'ListCtrl' interface. - ########################################################################### - - def OnGetItemText(self, row, column_index): - """ Returns the text for the specified CELL. """ - - viewer = self._viewer - element = viewer._elements[row] - - return viewer.label_provider.get_text(viewer, element, column_index) - - def OnGetItemImage(self, row): - """ Returns the image for the specified ROW. """ - - viewer = self._viewer - element = viewer._elements[row] - - # Get the icon used to represent the node. - image = viewer.label_provider.get_image(viewer, element) - if image is not None: - image_index = self._image_list.GetIndex(image.absolute_path) - - else: - image_index = -1 - - return image_index - - def OnGetItemAttr(self, row): - """ Returns the attribute for the specified row. """ - - if row % 2 == 0: - attribute = self._even_row_attribute +""" A viewer based on a table control. """ - else: - attribute = self._odd_row_attribute - return attribute +# Import the toolkit specific version. +from __future__ import absolute_import -#### EOF ###################################################################### +from pyface.toolkit import toolkit_object +TableViewer = toolkit_object('viewer.table_viewer:TableViewer') diff -Nru python-pyface-4.5.2/pyface/viewer/tree_content_provider.py python-pyface-6.1.2/pyface/viewer/tree_content_provider.py --- python-pyface-4.5.2/pyface/viewer/tree_content_provider.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/viewer/tree_content_provider.py 2019-05-03 08:18:50.000000000 +0000 @@ -15,7 +15,7 @@ # Local imports. -from content_provider import ContentProvider +from .content_provider import ContentProvider class TreeContentProvider(ContentProvider): diff -Nru python-pyface-4.5.2/pyface/viewer/tree_label_provider.py python-pyface-6.1.2/pyface/viewer/tree_label_provider.py --- python-pyface-4.5.2/pyface/viewer/tree_label_provider.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/viewer/tree_label_provider.py 2019-05-03 08:18:50.000000000 +0000 @@ -15,7 +15,7 @@ # Local imports. -from label_provider import LabelProvider +from .label_provider import LabelProvider class TreeLabelProvider(LabelProvider): diff -Nru python-pyface-4.5.2/pyface/viewer/tree_viewer.py python-pyface-6.1.2/pyface/viewer/tree_viewer.py --- python-pyface-4.5.2/pyface/viewer/tree_viewer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/viewer/tree_viewer.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,5 +1,4 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2005, Enthought, Inc. +# Copyright (c) 2017, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD @@ -7,634 +6,11 @@ # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! -# -# Author: Enthought, Inc. -# Description: -#------------------------------------------------------------------------------ """ A viewer based on a tree control. """ -# Major package imports. -import wx - -# Enthought library imports. -from pyface.image_list import ImageList -from traits.api import Any, Bool, Enum, Event, Instance, List -from pyface.wx.drag_and_drop import PythonDropSource - -# Local imports. -from content_viewer import ContentViewer -from tree_content_provider import TreeContentProvider -from tree_label_provider import TreeLabelProvider - - -class TreeViewer(ContentViewer): - """ A viewer based on a tree control. """ - - # The default tree style. - STYLE = wx.TR_EDIT_LABELS | wx.TR_HAS_BUTTONS | wx.CLIP_CHILDREN - - #### 'TreeViewer' interface ############################################### - - # The content provider provides the actual tree data. - content_provider = Instance(TreeContentProvider) - - # The label provider provides, err, the labels for the items in the tree - # (a label can have text and/or an image). - label_provider = Instance(TreeLabelProvider, ()) - - # Selection mode (must be either of 'single' or 'extended'). - selection_mode = Enum('single', 'extended') - - # The currently selected elements. - selection = List - - # Should an image be shown for each element? - show_images = Bool(True) - - # Should the root of the tree be shown? - show_root = Bool(True) - - #### Events #### - - # An element has been activated (ie. double-clicked). - element_activated = Event - - # A drag operation was started on an element. - element_begin_drag = Event - - # An element that has children has been collapsed. - element_collapsed = Event - - # An element that has children has been expanded. - element_expanded = Event - - # A left-click occurred on an element. - element_left_clicked = Event - - # A right-click occurred on an element. - element_right_clicked = Event - - # A key was pressed while the tree is in focus. - key_pressed = Event - - ########################################################################### - # 'object' interface. - ########################################################################### - - def __init__(self, parent, image_size=(16, 16), **traits): - """ Creates a new tree viewer. - - 'parent' is the toolkit-specific control that is the tree's parent. - - 'image_size' is a tuple in the form (int width, int height) that - specifies the size of the label images (if any) displayed in the tree. - - """ - - # Base class constructor. - super(TreeViewer, self).__init__(**traits) - - # Create the toolkit-specific control. - self.control = tree = wx.TreeCtrl(parent, -1, style=self._get_style()) - - # Get our actual Id. - wxid = tree.GetId() - - # Wire up the wx tree events. - wx.EVT_CHAR(tree, self._on_char) - wx.EVT_LEFT_DOWN(tree, self._on_left_down) - wx.EVT_RIGHT_DOWN(tree, self._on_right_down) - wx.EVT_TREE_ITEM_ACTIVATED(tree, wxid, self._on_tree_item_activated) - wx.EVT_TREE_ITEM_COLLAPSED(tree, wxid, self._on_tree_item_collapsed) - wx.EVT_TREE_ITEM_COLLAPSING(tree, wxid, self._on_tree_item_collapsing) - wx.EVT_TREE_ITEM_EXPANDED(tree, wxid, self._on_tree_item_expanded) - wx.EVT_TREE_ITEM_EXPANDING(tree, wxid, self._on_tree_item_expanding) - wx.EVT_TREE_BEGIN_LABEL_EDIT(tree, wxid,self._on_tree_begin_label_edit) - wx.EVT_TREE_END_LABEL_EDIT(tree, wxid, self._on_tree_end_label_edit) - wx.EVT_TREE_BEGIN_DRAG(tree, wxid, self._on_tree_begin_drag) - wx.EVT_TREE_SEL_CHANGED(tree, wxid, self._on_tree_sel_changed) - - # The image list is a wxPython-ism that caches all images used in the - # control. - self._image_list = ImageList(image_size[0], image_size[1]) - if self.show_images: - tree.AssignImageList(self._image_list) - - # Mapping from element to wx tree item Ids. - self._element_to_id_map = {} - - # Add the root item. - if self.input is not None: - self._add_element(None, self.input) - - return - - ########################################################################### - # 'TreeViewer' interface. - ########################################################################### - - def is_expanded(self, element): - """ Returns True if the element is expanded, otherwise False. """ - - key = self._get_key(element) - - if key in self._element_to_id_map: - is_expanded = self.control.IsExpanded(self._element_to_id_map[key]) - - else: - is_expanded = False - - return is_expanded - - def is_selected(self, element): - """ Returns True if the element is selected, otherwise False. """ - - key = self._get_key(element) - - if key in self._element_to_id_map: - is_selected = self.control.IsSelected(self._element_to_id_map[key]) - - else: - is_selected = False - - return is_selected - - def refresh(self, element): - """ Refresh the tree starting from the specified element. - - Call this when the STRUCTURE of the content has changed. - - """ - - # Has the element actually appeared in the tree yet? - pid = self._element_to_id_map.get(self._get_key(element), None) - if pid is not None: - # The item data is a tuple. The first element indicates whether or - # not we have already populated the item with its children. The - # second element is the actual item data. - populated, element = self.control.GetPyData(pid) - - # fixme: We should find a cleaner way other than deleting all of - # the element's children and re-adding them! - self._delete_children(pid) - self.control.SetPyData(pid, (False, element)) - - # Does the element have any children? - has_children = self.content_provider.has_children(element) - self.control.SetItemHasChildren(pid, has_children) - - # Expand it. - self.control.Expand(pid) - - else: - print '**** pid is None!!! ****' - - return - - def update(self, element): - """ Update the tree starting from the specified element. - - Call this when the APPEARANCE of the content has changed. - - """ - - pid = self._element_to_id_map.get(self._get_key(element), None) - if pid is not None: - self._refresh_element(pid, element) - - for child in self.content_provider.get_children(element): - cid = self._element_to_id_map.get(self._get_key(child), None) - if cid is not None: - self._refresh_element(cid, child) - - return - - ########################################################################### - # Private interface. - ########################################################################### - - def _get_style(self): - """ Returns the wx style flags for creating the tree control. """ - - # Start with the default flags. - style = self.STYLE - - if not self.show_root: - style = style | wx.TR_HIDE_ROOT | wx.TR_LINES_AT_ROOT - - if self.selection_mode != 'single': - style = style | wx.TR_MULTIPLE | wx.TR_EXTENDED - - return style - - def _add_element(self, pid, element): - """ Adds 'element' as a child of the element identified by 'pid'. - - If 'pid' is None then we are adding the root element. - - """ - - # Get the tree item image index and text. - image_index = self._get_image_index(element) - text = self._get_text(element) - - # Add the element. - if pid is None: - wxid = self.control.AddRoot(text, image_index, image_index) - - else: - wxid = self.control.AppendItem(pid, text, image_index, image_index) - - # If we are adding the root element but the root is hidden, get its - # children. - if pid is None and not self.show_root: - children = self.content_provider.get_children(element) - for child in children: - self._add_element(wxid, child) - - # Does the element have any children? - has_children = self.content_provider.has_children(element) - self.control.SetItemHasChildren(wxid, has_children) - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - if pid is None: - if self.show_root: - self.control.SetPyData(wxid, (False, element)) - - else: - self.control.SetPyData(wxid, (False, element)) - - # Make sure that we can find the element's Id later. - self._element_to_id_map[self._get_key(element)] = wxid - - # If we are adding the root item then automatically expand it. - if pid is None and self.show_root: - self.control.Expand(wxid) - - return - - def _get_image_index(self, element): - """ Returns the tree item image index for an element. """ - - # Get the image used to represent the element. - image = self.label_provider.get_image(self, element) - if image is not None: - image_index = self._image_list.GetIndex(image.absolute_path) - - else: - image_index = -1 - - return image_index - - def _get_key(self, element): - """ Generate the key for the element to id map. """ - - try: - key = hash(element) - - except: - key = id(element) - - return key - - def _get_text(self, element): - """ Returns the tree item text for an element. """ - - text = self.label_provider.get_text(self, element) - if text is None: - text = '' - - return text - - def _refresh_element(self, wxid, element): - """ Refreshes the image and text of the specified element. """ - - # Get the tree item image index. - image_index = self._get_image_index(element) - self.control.SetItemImage(wxid, image_index, wx.TreeItemIcon_Normal) - self.control.SetItemImage(wxid, image_index, wx.TreeItemIcon_Selected) - - # Get the tree item text. - text = self._get_text(element) - self.control.SetItemText(wxid, text) - - # Does the item have any children? - has_children = self.content_provider.has_children(element) - self.control.SetItemHasChildren(wxid, has_children) - - return - - def _unpack_event(self, event): - """ Unpacks the event to see whether a tree element was involved. """ - - try: - point = event.GetPosition() - - except: - point = event.GetPoint() - - wxid, flags = self.control.HitTest(point) - - # Warning: On GTK we have to check the flags before we call 'GetPyData' - # because if we call it when the hit test returns 'nowhere' it will - # barf (on Windows it simply returns 'None' 8^() - if flags & wx.TREE_HITTEST_NOWHERE: - data = None - - else: - data = self.control.GetPyData(wxid) - - return data, wxid, flags, point - - def _get_selection(self): - """ Returns a list of the selected elements. """ - - elements = [] - for wxid in self.control.GetSelections(): - data = self.control.GetPyData(wxid) - if data is not None: - populated, element = data - elements.append(element) - - # 'data' can be None here if (for example) the element has been - # deleted. - # - # fixme: Can we stop this happening?!?!? - else: - pass - - return elements - - def _delete_children(self, pid): - """ Recursively deletes the children of the specified element. """ - - cookie = 0 - - (cid, cookie) = self.control.GetFirstChild(pid, cookie) - while cid.IsOk(): - # Recursively delete the child's children. - self._delete_children(cid) - - # Remove the reference to the item's data. - populated, element = self.control.GetPyData(cid) - del self._element_to_id_map[self._get_key(element)] - self.control.SetPyData(cid, None) - - # Next! - (cid, cookie) = self.control.GetNextChild(pid, cookie) - - self.control.DeleteChildren(pid) - - return - - #### Trait event handlers ################################################# - - def _input_changed(self): - """ Called when the tree's input has been changed. """ - - # Delete everything... - if self.control is not None: - self.control.DeleteAllItems() - - self._element_to_id_map = {} - - # ... and then add the root item back in. - if self.input is not None: - self._add_element(None, self.input) - - return - - def _element_begin_drag_changed(self, element): - """ Called when a drag is started on a element. """ - - # We ask the label provider for the actual value to drag. - drag_value = self.label_provider.get_drag_value(self, element) - - # Start the drag. - PythonDropSource(self.control, drag_value) - - return - - #### wx event handlers #################################################### - - def _on_right_down(self, event): - """ Called when the right mouse button is clicked on the tree. """ - - data, id, flags, point = self._unpack_event(event) - - # Did the right click occur on a tree item? - if data is not None: - populated, element = data - - # Trait notification. - self.element_right_clicked = (element, point) - - # Give other event handlers a chance. - event.Skip() - - return - - def _on_left_down(self, event): - """ Called when the left mouse button is clicked on the tree. """ - - data, wxid, flags, point = self._unpack_event(event) - - # Save point for tree_begin_drag method to workaround a bug in ?? when - # wx.TreeEvent.GetPoint returns only (0,0). This happens under linux - # when using wx-2.4.2.4, for instance. - self._point_left_clicked = point - - # Did the left click occur on a tree item? - if data is not None: - populated, element = data - - # Trait notification. - self.element_left_clicked = (element, point) - - # Give other event handlers a chance. - event.Skip() - - return - - def _on_tree_item_expanding(self, event): - """ Called when a tree item is about to expand. """ - - # Which item is expanding? - wxid = event.GetItem() - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - populated, element = self.control.GetPyData(wxid) - - # Give the label provider a chance to veto the expansion. - if self.label_provider.is_expandable(self, element): - # Lazily populate the item's children. - if not populated: - children = self.content_provider.get_children(element) - - # Sorting... - if self.sorter is not None: - self.sorter.sort(self, element, children) - - # Filtering.... - for child in children: - for filter in self.filters: - if not filter.select(self, element, child): - break - - else: - self._add_element(wxid, child) - - # The element is now populated! - self.control.SetPyData(wxid, (True, element)) - - else: - event.Veto() - - return - - def _on_tree_item_expanded(self, event): - """ Called when a tree item has been expanded. """ - - # Which item was expanded? - wxid = event.GetItem() - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - populated, element = self.control.GetPyData(wxid) - - # Make sure that the element's 'open' icon is displayed etc. - self._refresh_element(wxid, element) - - # Trait notification. - self.element_expanded = element - - return - - def _on_tree_item_collapsing(self, event): - """ Called when a tree item is about to collapse. """ - - # Which item is collapsing? - wxid = event.GetItem() - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - populated, element = self.control.GetPyData(wxid) - - # Give the label provider a chance to veto the collapse. - if not self.label_provider.is_collapsible(self, element): - event.Veto() - - return - - def _on_tree_item_collapsed(self, event): - """ Called when a tree item has been collapsed. """ - - # Which item was collapsed? - wxid = event.GetItem() - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - populated, element = self.control.GetPyData(wxid) - - # Make sure that the element's 'closed' icon is displayed etc. - self._refresh_element(wxid, element) - - # Trait notification. - self.element_collapsed = element - - return - - def _on_tree_item_activated(self, event): - """ Called when a tree item is activated (i.e., double clicked). """ - - # Which item was activated? - wxid = event.GetItem() - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - populated, element = self.control.GetPyData(wxid) - - # Trait notification. - self.element_activated = element - - return - - def _on_tree_sel_changed(self, event): - """ Called when the selection is changed. """ - - # Trait notification. - self.selection = self._get_selection() - - return - - def _on_tree_begin_drag(self, event): - """ Called when a drag operation is starting on a tree item. """ - - # Get the element, its id and the point where the event occurred. - data, wxid, flags, point = self._unpack_event(event) - - if point == (0,0): - # Apply workaround. - point = self._point_left_clicked - wxid, flags = self.control.HitTest(point) - data = self.control.GetPyData(wxid) - - if data is not None: - populated, element = data - - # Trait notification. - self.element_begin_drag = element - - return - - def _on_tree_begin_label_edit(self, event): - """ Called when the user has started editing an item's label. """ - - wxid = event.GetItem() - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - populated, element = self.control.GetPyData(wxid) - - # Give the label provider a chance to veto the edit. - if not self.label_provider.is_editable(self, element): - event.Veto() - - return - - def _on_tree_end_label_edit(self, event): - """ Called when the user has finished editing an item's label. """ - - wxid = event.GetItem() - - # The item data is a tuple. The first element indicates whether or not - # we have already populated the item with its children. The second - # element is the actual item data. - populated, element = self.control.GetPyData(wxid) - - # Give the label provider a chance to veto the edit. - label = event.GetLabel() - if not self.label_provider.set_text(self, element, label): - event.Veto() - - return - - def _on_char(self, event): - """ Called when a key is pressed when the tree has focus. """ - - # Trait notification. - self.key_pressed = event.GetKeyCode() - - return +# Import the toolkit specific version. +from __future__ import absolute_import -#### EOF ###################################################################### +from pyface.toolkit import toolkit_object +TreeViewer = toolkit_object('viewer.tree_viewer:TreeViewer') diff -Nru python-pyface-4.5.2/pyface/widget.py python-pyface-6.1.2/pyface/widget.py --- python-pyface-4.5.2/pyface/widget.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/widget.py 2019-05-03 08:18:50.000000000 +0000 @@ -15,7 +15,9 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object Widget = toolkit_object('widget:Widget') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/window.py python-pyface-6.1.2/pyface/window.py --- python-pyface-4.5.2/pyface/window.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/window.py 2019-05-03 08:18:50.000000000 +0000 @@ -15,7 +15,9 @@ # Import the toolkit specific version. -from toolkit import toolkit_object +from __future__ import absolute_import + +from .toolkit import toolkit_object Window = toolkit_object('window:Window') #### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/wizard/api.py python-pyface-6.1.2/pyface/wizard/api.py --- python-pyface-4.5.2/pyface/wizard/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wizard/api.py 2019-05-03 08:18:50.000000000 +0000 @@ -11,18 +11,18 @@ # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ -from i_wizard_page import IWizardPage -from wizard_page import WizardPage +from .i_wizard_page import IWizardPage +from .wizard_page import WizardPage -from i_wizard import IWizard -from wizard import Wizard +from .i_wizard import IWizard +from .wizard import Wizard -from i_wizard_controller import IWizardController -from wizard_controller import WizardController +from .i_wizard_controller import IWizardController +from .wizard_controller import WizardController -from chained_wizard import ChainedWizard -from chained_wizard_controller import ChainedWizardController +from .chained_wizard import ChainedWizard +from .chained_wizard_controller import ChainedWizardController # These are deprecated. Use Wizard and WizardController instead. -from simple_wizard import SimpleWizard -from simple_wizard_controller import SimpleWizardController +from .simple_wizard import SimpleWizard +from .simple_wizard_controller import SimpleWizardController diff -Nru python-pyface-4.5.2/pyface/wizard/chained_wizard_controller.py python-pyface-6.1.2/pyface/wizard/chained_wizard_controller.py --- python-pyface-4.5.2/pyface/wizard/chained_wizard_controller.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wizard/chained_wizard_controller.py 2019-05-03 08:18:50.000000000 +0000 @@ -18,8 +18,8 @@ from traits.api import Instance # Local imports. -from i_wizard_controller import IWizardController -from wizard_controller import WizardController +from .i_wizard_controller import IWizardController +from .wizard_controller import WizardController class ChainedWizardController(WizardController): diff -Nru python-pyface-4.5.2/pyface/wizard/chained_wizard.py python-pyface-6.1.2/pyface/wizard/chained_wizard.py --- python-pyface-4.5.2/pyface/wizard/chained_wizard.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wizard/chained_wizard.py 2019-05-03 08:18:50.000000000 +0000 @@ -18,8 +18,8 @@ from traits.api import Instance # Local imports. -from i_wizard import IWizard -from wizard import Wizard +from .i_wizard import IWizard +from .wizard import Wizard class ChainedWizard(Wizard): diff -Nru python-pyface-4.5.2/pyface/wizard/i_wizard_controller.py python-pyface-6.1.2/pyface/wizard/i_wizard_controller.py --- python-pyface-4.5.2/pyface/wizard/i_wizard_controller.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wizard/i_wizard_controller.py 2019-05-03 08:18:50.000000000 +0000 @@ -18,7 +18,7 @@ from traits.api import Bool, Interface, Instance, List # Local imports. -from i_wizard_page import IWizardPage +from .i_wizard_page import IWizardPage class IWizardController(Interface): diff -Nru python-pyface-4.5.2/pyface/wizard/i_wizard.py python-pyface-6.1.2/pyface/wizard/i_wizard.py --- python-pyface-4.5.2/pyface/wizard/i_wizard.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wizard/i_wizard.py 2019-05-03 08:18:50.000000000 +0000 @@ -19,8 +19,8 @@ from pyface.i_dialog import IDialog # Local imports. -from i_wizard_controller import IWizardController -from i_wizard_page import IWizardPage +from .i_wizard_controller import IWizardController +from .i_wizard_page import IWizardPage class IWizard(IDialog): diff -Nru python-pyface-4.5.2/pyface/wizard/simple_wizard_controller.py python-pyface-6.1.2/pyface/wizard/simple_wizard_controller.py --- python-pyface-4.5.2/pyface/wizard/simple_wizard_controller.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wizard/simple_wizard_controller.py 2019-05-03 08:18:50.000000000 +0000 @@ -15,7 +15,7 @@ # Local imports. -from wizard_controller import WizardController +from .wizard_controller import WizardController class SimpleWizardController(WizardController): pass diff -Nru python-pyface-4.5.2/pyface/wizard/simple_wizard.py python-pyface-6.1.2/pyface/wizard/simple_wizard.py --- python-pyface-4.5.2/pyface/wizard/simple_wizard.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wizard/simple_wizard.py 2019-05-03 08:18:50.000000000 +0000 @@ -15,7 +15,8 @@ # Local imports. -from wizard import Wizard +from .wizard import Wizard -class SimpleWizard(Wizard): pass +class SimpleWizard(Wizard): + pass diff -Nru python-pyface-4.5.2/pyface/wizard/wizard_controller.py python-pyface-6.1.2/pyface/wizard/wizard_controller.py --- python-pyface-4.5.2/pyface/wizard/wizard_controller.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wizard/wizard_controller.py 2019-05-03 08:18:50.000000000 +0000 @@ -18,8 +18,8 @@ from traits.api import Bool, HasTraits, Instance, List, Property, provides # Local imports. -from i_wizard_controller import IWizardController -from i_wizard_page import IWizardPage +from .i_wizard_controller import IWizardController +from .i_wizard_page import IWizardPage @provides(IWizardController) diff -Nru python-pyface-4.5.2/pyface/workbench/action/api.py python-pyface-6.1.2/pyface/workbench/action/api.py --- python-pyface-4.5.2/pyface/workbench/action/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/api.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,3 +1,5 @@ -from menu_bar_manager import MenuBarManager -from tool_bar_manager import ToolBarManager -from view_menu_manager import ViewMenuManager +from __future__ import absolute_import + +from .menu_bar_manager import MenuBarManager +from .tool_bar_manager import ToolBarManager +from .view_menu_manager import ViewMenuManager diff -Nru python-pyface-4.5.2/pyface/workbench/action/delete_user_perspective_action.py python-pyface-6.1.2/pyface/workbench/action/delete_user_perspective_action.py --- python-pyface-4.5.2/pyface/workbench/action/delete_user_perspective_action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/delete_user_perspective_action.py 2019-05-03 08:18:50.000000000 +0000 @@ -13,7 +13,7 @@ from pyface.api import YES # Local imports. -from user_perspective_action import UserPerspectiveAction +from .user_perspective_action import UserPerspectiveAction class DeleteUserPerspectiveAction(UserPerspectiveAction): @@ -77,4 +77,3 @@ return window.perspectives[index] #### EOF ##################################################################### - diff -Nru python-pyface-4.5.2/pyface/workbench/action/menu_bar_manager.py python-pyface-6.1.2/pyface/workbench/action/menu_bar_manager.py --- python-pyface-4.5.2/pyface/workbench/action/menu_bar_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/menu_bar_manager.py 2019-05-03 08:18:50.000000000 +0000 @@ -6,7 +6,7 @@ from traits.api import Instance # Local imports. -from action_controller import ActionController +from .action_controller import ActionController class MenuBarManager(BaseMenuBarManager): diff -Nru python-pyface-4.5.2/pyface/workbench/action/new_user_perspective_action.py python-pyface-6.1.2/pyface/workbench/action/new_user_perspective_action.py --- python-pyface-4.5.2/pyface/workbench/action/new_user_perspective_action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/new_user_perspective_action.py 2019-05-03 08:18:50.000000000 +0000 @@ -10,8 +10,8 @@ # Local imports. -from user_perspective_name import UserPerspectiveName -from workbench_action import WorkbenchAction +from .user_perspective_name import UserPerspectiveName +from .workbench_action import WorkbenchAction class NewUserPerspectiveAction(WorkbenchAction): @@ -52,4 +52,3 @@ return #### EOF ##################################################################### - diff -Nru python-pyface-4.5.2/pyface/workbench/action/perspective_menu_manager.py python-pyface-6.1.2/pyface/workbench/action/perspective_menu_manager.py --- python-pyface-4.5.2/pyface/workbench/action/perspective_menu_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/perspective_menu_manager.py 2019-05-03 08:18:50.000000000 +0000 @@ -6,13 +6,13 @@ from traits.api import Instance, List, on_trait_change # Local imports. -from delete_user_perspective_action import DeleteUserPerspectiveAction -from new_user_perspective_action import NewUserPerspectiveAction -from rename_user_perspective_action import RenameUserPerspectiveAction -from reset_all_perspectives_action import ResetAllPerspectivesAction -from reset_active_perspective_action import ResetActivePerspectiveAction -from save_as_user_perspective_action import SaveAsUserPerspectiveAction -from set_active_perspective_action import SetActivePerspectiveAction +from .delete_user_perspective_action import DeleteUserPerspectiveAction +from .new_user_perspective_action import NewUserPerspectiveAction +from .rename_user_perspective_action import RenameUserPerspectiveAction +from .reset_all_perspectives_action import ResetAllPerspectivesAction +from .reset_active_perspective_action import ResetActivePerspectiveAction +from .save_as_user_perspective_action import SaveAsUserPerspectiveAction +from .set_active_perspective_action import SetActivePerspectiveAction class PerspectiveMenuManager(MenuManager): @@ -96,7 +96,7 @@ # fixme: Not sure if alphabetic sorting is appropriate in all cases, # but it will do for now! perspectives = window.perspectives[:] - perspectives.sort(lambda x, y: cmp(x.name, y.name)) + perspectives.sort(key=lambda x:x.name) # For each perspective, create an action that sets the active # perspective to it. diff -Nru python-pyface-4.5.2/pyface/workbench/action/rename_user_perspective_action.py python-pyface-6.1.2/pyface/workbench/action/rename_user_perspective_action.py --- python-pyface-4.5.2/pyface/workbench/action/rename_user_perspective_action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/rename_user_perspective_action.py 2019-05-03 08:18:50.000000000 +0000 @@ -10,8 +10,8 @@ # Local imports. -from user_perspective_action import UserPerspectiveAction -from user_perspective_name import UserPerspectiveName +from .user_perspective_action import UserPerspectiveAction +from .user_perspective_name import UserPerspectiveName class RenameUserPerspectiveAction(UserPerspectiveAction): @@ -43,4 +43,3 @@ return #### EOF ##################################################################### - diff -Nru python-pyface-4.5.2/pyface/workbench/action/reset_active_perspective_action.py python-pyface-6.1.2/pyface/workbench/action/reset_active_perspective_action.py --- python-pyface-4.5.2/pyface/workbench/action/reset_active_perspective_action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/reset_active_perspective_action.py 2019-05-03 08:18:50.000000000 +0000 @@ -5,7 +5,7 @@ from pyface.api import YES # Local imports. -from workbench_action import WorkbenchAction +from .workbench_action import WorkbenchAction # The message used when confirming the action. diff -Nru python-pyface-4.5.2/pyface/workbench/action/reset_all_perspectives_action.py python-pyface-6.1.2/pyface/workbench/action/reset_all_perspectives_action.py --- python-pyface-4.5.2/pyface/workbench/action/reset_all_perspectives_action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/reset_all_perspectives_action.py 2019-05-03 08:18:50.000000000 +0000 @@ -5,7 +5,7 @@ from pyface.api import YES # Local imports. -from workbench_action import WorkbenchAction +from .workbench_action import WorkbenchAction # The message used when confirming the action. diff -Nru python-pyface-4.5.2/pyface/workbench/action/save_as_user_perspective_action.py python-pyface-6.1.2/pyface/workbench/action/save_as_user_perspective_action.py --- python-pyface-4.5.2/pyface/workbench/action/save_as_user_perspective_action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/save_as_user_perspective_action.py 2019-05-03 08:18:50.000000000 +0000 @@ -10,8 +10,8 @@ # Local imports. -from user_perspective_name import UserPerspectiveName -from workbench_action import WorkbenchAction +from .user_perspective_name import UserPerspectiveName +from .workbench_action import WorkbenchAction class SaveAsUserPerspectiveAction(WorkbenchAction): diff -Nru python-pyface-4.5.2/pyface/workbench/action/set_active_perspective_action.py python-pyface-6.1.2/pyface/workbench/action/set_active_perspective_action.py --- python-pyface-4.5.2/pyface/workbench/action/set_active_perspective_action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/set_active_perspective_action.py 2019-05-03 08:18:50.000000000 +0000 @@ -6,7 +6,7 @@ from traits.api import Delegate, Instance, on_trait_change # Local imports. -from workbench_action import WorkbenchAction +from .workbench_action import WorkbenchAction class SetActivePerspectiveAction(WorkbenchAction): diff -Nru python-pyface-4.5.2/pyface/workbench/action/setattr_action.py python-pyface-6.1.2/pyface/workbench/action/setattr_action.py --- python-pyface-4.5.2/pyface/workbench/action/setattr_action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/setattr_action.py 2019-05-03 08:18:50.000000000 +0000 @@ -5,7 +5,7 @@ from traits.api import Any, Str # Local imports. -from workbench_action import WorkbenchAction +from .workbench_action import WorkbenchAction class SetattrAction(WorkbenchAction): diff -Nru python-pyface-4.5.2/pyface/workbench/action/show_view_action.py python-pyface-6.1.2/pyface/workbench/action/show_view_action.py --- python-pyface-4.5.2/pyface/workbench/action/show_view_action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/show_view_action.py 2019-05-03 08:18:50.000000000 +0000 @@ -2,8 +2,8 @@ # Local imports. -from view_chooser import ViewChooser -from workbench_action import WorkbenchAction +from .view_chooser import ViewChooser +from .workbench_action import WorkbenchAction class ShowViewAction(WorkbenchAction): diff -Nru python-pyface-4.5.2/pyface/workbench/action/toggle_view_visibility_action.py python-pyface-6.1.2/pyface/workbench/action/toggle_view_visibility_action.py --- python-pyface-4.5.2/pyface/workbench/action/toggle_view_visibility_action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/toggle_view_visibility_action.py 2019-05-03 08:18:50.000000000 +0000 @@ -6,7 +6,7 @@ from traits.api import Delegate, Instance # Local imports. -from workbench_action import WorkbenchAction +from .workbench_action import WorkbenchAction class ToggleViewVisibilityAction(WorkbenchAction): diff -Nru python-pyface-4.5.2/pyface/workbench/action/tool_bar_manager.py python-pyface-6.1.2/pyface/workbench/action/tool_bar_manager.py --- python-pyface-4.5.2/pyface/workbench/action/tool_bar_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/tool_bar_manager.py 2019-05-03 08:18:50.000000000 +0000 @@ -6,7 +6,7 @@ from traits.api import Instance # Local imports. -from action_controller import ActionController +from .action_controller import ActionController class ToolBarManager(pyface.ToolBarManager): diff -Nru python-pyface-4.5.2/pyface/workbench/action/user_perspective_action.py python-pyface-6.1.2/pyface/workbench/action/user_perspective_action.py --- python-pyface-4.5.2/pyface/workbench/action/user_perspective_action.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/user_perspective_action.py 2019-05-03 08:18:50.000000000 +0000 @@ -13,7 +13,7 @@ from traits.api import on_trait_change # Local imports. -from workbench_action import WorkbenchAction +from .workbench_action import WorkbenchAction class UserPerspectiveAction(WorkbenchAction): diff -Nru python-pyface-4.5.2/pyface/workbench/action/user_perspective_name.py python-pyface-6.1.2/pyface/workbench/action/user_perspective_name.py --- python-pyface-4.5.2/pyface/workbench/action/user_perspective_name.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/user_perspective_name.py 2019-05-03 08:18:50.000000000 +0000 @@ -12,6 +12,7 @@ # Enthought library imports. from traits.api import Bool, HasTraits, Trait, TraitError, Constant from traitsui.api import View, Item, VGroup +import six #### Trait definitions ######################################################## @@ -19,7 +20,7 @@ def not_empty_string(object, name, value): """a not-empty string""" - if isinstance(value, basestring) and (value.strip() != ''): + if isinstance(value, six.string_types) and (value.strip() != ''): return value raise TraitError diff -Nru python-pyface-4.5.2/pyface/workbench/action/view_chooser.py python-pyface-6.1.2/pyface/workbench/action/view_chooser.py --- python-pyface-4.5.2/pyface/workbench/action/view_chooser.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/view_chooser.py 2019-07-20 11:46:59.000000000 +0000 @@ -41,7 +41,7 @@ # Collate the window's views into categories. categories_by_name = self._get_categories_by_name(object) - categories = categories_by_name.values() + categories = list(categories_by_name.values()) categories.sort(key=lambda category: category.name) return categories @@ -73,7 +73,7 @@ for adaptation we would have to work out a way for the rest of the 'TreeNode' code to access the adapter, not the original object. We could, of course override every method, but that seems a little, errr, tedious. - We could probably do with something like in the PyFace tree where there + We could probably do with something like in the Pyface tree where there is a method that returns the actual object that we want to manipulate. """ diff -Nru python-pyface-4.5.2/pyface/workbench/action/view_menu_manager.py python-pyface-6.1.2/pyface/workbench/action/view_menu_manager.py --- python-pyface-4.5.2/pyface/workbench/action/view_menu_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/action/view_menu_manager.py 2019-07-20 11:46:59.000000000 +0000 @@ -10,9 +10,9 @@ from traits.api import on_trait_change # Local imports. -from perspective_menu_manager import PerspectiveMenuManager -from show_view_action import ShowViewAction -from toggle_view_visibility_action import ToggleViewVisibilityAction +from .perspective_menu_manager import PerspectiveMenuManager +from .show_view_action import ShowViewAction +from .toggle_view_visibility_action import ToggleViewVisibilityAction # Logging. @@ -103,7 +103,7 @@ def _clear_group(self, group): """ Remove all items in a group. """ - # fixme: Fix this API in PyFace so there is only one call! + # fixme: Fix this API in Pyface so there is only one call! group.destroy() group.clear() @@ -129,7 +129,7 @@ """ Initializes a group containing the view 'togglers'. """ views = window.views[:] - views.sort(None, lambda view: view.name) + views.sort(key=lambda view: view.name) for view in views: # fixme: It seems a little smelly to be reaching in to the window diff -Nru python-pyface-4.5.2/pyface/workbench/api.py python-pyface-6.1.2/pyface/workbench/api.py --- python-pyface-4.5.2/pyface/workbench/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/api.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,20 +1,22 @@ -from i_editor import IEditor -from editor import Editor +from __future__ import absolute_import -from i_editor_manager import IEditorManager -from editor_manager import EditorManager +from .i_editor import IEditor +from .editor import Editor -from i_perspective import IPerspective -from perspective import Perspective -from perspective_item import PerspectiveItem +from .i_editor_manager import IEditorManager +from .editor_manager import EditorManager -from i_view import IView -from view import View +from .i_perspective import IPerspective +from .perspective import Perspective +from .perspective_item import PerspectiveItem -from i_workbench import IWorkbench -from workbench import Workbench +from .i_view import IView +from .view import View -from workbench_window import WorkbenchWindow +from .i_workbench import IWorkbench +from .workbench import Workbench -from traits_ui_editor import TraitsUIEditor -from traits_ui_view import TraitsUIView +from .workbench_window import WorkbenchWindow + +from .traits_ui_editor import TraitsUIEditor +from .traits_ui_view import TraitsUIView diff -Nru python-pyface-4.5.2/pyface/workbench/debug/api.py python-pyface-6.1.2/pyface/workbench/debug/api.py --- python-pyface-4.5.2/pyface/workbench/debug/api.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/debug/api.py 2019-05-03 08:18:50.000000000 +0000 @@ -1 +1,4 @@ -from debug_view import DebugView +from __future__ import absolute_import + + +from .debug_view import DebugView diff -Nru python-pyface-4.5.2/pyface/workbench/editor_manager.py python-pyface-6.1.2/pyface/workbench/editor_manager.py --- python-pyface-4.5.2/pyface/workbench/editor_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/editor_manager.py 2019-05-03 08:18:50.000000000 +0000 @@ -7,8 +7,8 @@ from traits.api import HasTraits, Instance, provides # Local imports. -from i_editor_manager import IEditorManager -from traits_ui_editor import TraitsUIEditor +from .i_editor_manager import IEditorManager +from .traits_ui_editor import TraitsUIEditor @provides(IEditorManager) diff -Nru python-pyface-4.5.2/pyface/workbench/i_editor.py python-pyface-6.1.2/pyface/workbench/i_editor.py --- python-pyface-4.5.2/pyface/workbench/i_editor.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/i_editor.py 2019-05-03 08:18:50.000000000 +0000 @@ -21,7 +21,7 @@ from traits.api import provides # Local imports. -from i_workbench_part import IWorkbenchPart, MWorkbenchPart +from .i_workbench_part import IWorkbenchPart, MWorkbenchPart class IEditor(IWorkbenchPart): diff -Nru python-pyface-4.5.2/pyface/workbench/__init__.py python-pyface-6.1.2/pyface/workbench/__init__.py --- python-pyface-4.5.2/pyface/workbench/__init__.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/__init__.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,8 @@ +import warnings + +warnings.warn( + PendingDeprecationWarning( + "Workbench will be moved from pyface.workbench to apptools.workbench " + "in Pyface 7.0.0" + ), stacklevel=2 +) diff -Nru python-pyface-4.5.2/pyface/workbench/i_perspective.py python-pyface-6.1.2/pyface/workbench/i_perspective.py --- python-pyface-4.5.2/pyface/workbench/i_perspective.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/i_perspective.py 2019-05-03 08:18:50.000000000 +0000 @@ -5,7 +5,7 @@ from traits.api import Bool, Interface, List, Str, Tuple # Local imports. -from perspective_item import PerspectiveItem +from .perspective_item import PerspectiveItem class IPerspective(Interface): diff -Nru python-pyface-4.5.2/pyface/workbench/i_view.py python-pyface-6.1.2/pyface/workbench/i_view.py --- python-pyface-4.5.2/pyface/workbench/i_view.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/i_view.py 2019-05-03 08:18:50.000000000 +0000 @@ -22,9 +22,9 @@ from traits.util.camel_case import camel_case_to_words # Local imports. -from i_perspective_item import IPerspectiveItem -from i_workbench_part import IWorkbenchPart, MWorkbenchPart -from perspective_item import PerspectiveItem +from .i_perspective_item import IPerspectiveItem +from .i_workbench_part import IWorkbenchPart, MWorkbenchPart +from .perspective_item import PerspectiveItem # Logging. logger = logging.getLogger(__name__) diff -Nru python-pyface-4.5.2/pyface/workbench/i_workbench.py python-pyface-6.1.2/pyface/workbench/i_workbench.py --- python-pyface-4.5.2/pyface/workbench/i_workbench.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/i_workbench.py 2019-05-03 08:18:50.000000000 +0000 @@ -6,9 +6,9 @@ from traits.api import provides, VetoableEvent # Local imports. -from user_perspective_manager import UserPerspectiveManager -from window_event import WindowEvent, VetoableWindowEvent -from workbench_window import WorkbenchWindow +from .user_perspective_manager import UserPerspectiveManager +from .window_event import WindowEvent, VetoableWindowEvent +from .workbench_window import WorkbenchWindow class IWorkbench(Interface): diff -Nru python-pyface-4.5.2/pyface/workbench/i_workbench_window_layout.py python-pyface-6.1.2/pyface/workbench/i_workbench_window_layout.py --- python-pyface-4.5.2/pyface/workbench/i_workbench_window_layout.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/i_workbench_window_layout.py 2019-05-03 08:18:50.000000000 +0000 @@ -19,8 +19,8 @@ from traits.api import provides # Local imports. -from i_editor import IEditor -from i_view import IView +from .i_editor import IEditor +from .i_view import IView class IWorkbenchWindowLayout(Interface): diff -Nru python-pyface-4.5.2/pyface/workbench/perspective_item.py python-pyface-6.1.2/pyface/workbench/perspective_item.py --- python-pyface-4.5.2/pyface/workbench/perspective_item.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/perspective_item.py 2019-05-03 08:18:50.000000000 +0000 @@ -5,7 +5,7 @@ from traits.api import Enum, Float, HasTraits, provides, Str # Local imports. -from i_perspective_item import IPerspectiveItem +from .i_perspective_item import IPerspectiveItem @provides(IPerspectiveItem) diff -Nru python-pyface-4.5.2/pyface/workbench/perspective.py python-pyface-6.1.2/pyface/workbench/perspective.py --- python-pyface-4.5.2/pyface/workbench/perspective.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/perspective.py 2019-05-03 08:18:50.000000000 +0000 @@ -8,8 +8,8 @@ from traits.api import Bool, HasTraits, List, provides, Str, Tuple # Local imports. -from i_perspective import IPerspective -from perspective_item import PerspectiveItem +from .i_perspective import IPerspective +from .perspective_item import PerspectiveItem # Logging. diff -Nru python-pyface-4.5.2/pyface/workbench/tests/test_workbench_window.py python-pyface-6.1.2/pyface/workbench/tests/test_workbench_window.py --- python-pyface-4.5.2/pyface/workbench/tests/test_workbench_window.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/tests/test_workbench_window.py 2019-06-14 12:22:56.000000000 +0000 @@ -0,0 +1,166 @@ +import mock +import tempfile +import shutil +import os +import unittest + +from traits.testing.unittest_tools import UnittestTools + +from pyface.workbench.perspective import Perspective +from pyface.workbench.api import Workbench +from pyface.workbench.user_perspective_manager import UserPerspectiveManager +from pyface.workbench.workbench_window import (WorkbenchWindow, + WorkbenchWindowLayout, + WorkbenchWindowMemento) + + +class TestWorkbenchWindowUserPerspective(unittest.TestCase, UnittestTools): + + def setUp(self): + # A perspective with show_editor_area switched on + self.with_editor = Perspective(show_editor_area=True, + id="test_id", name="test_name") + + # A perspective with show_editor_area switched off + self.without_editor = Perspective(show_editor_area=False, + id="test_id2", name="test_name2") + + # Where the state file should be saved + self.state_location = tempfile.mkdtemp(dir="./") + + # Make sure the temporary directory is removed + self.addCleanup(self.rm_tempdir) + + def rm_tempdir(self): + shutil.rmtree(self.state_location) + + def get_workbench_with_window(self): + workbench = Workbench() + workbench_window = WorkbenchWindow() + workbench.windows = [workbench_window] + + # Saved perspectives should go to the temporary directory + workbench.state_location = self.state_location + + # Mock the layout for the workbench window + workbench_window.layout = mock.MagicMock(spec=WorkbenchWindowLayout) + workbench_window.layout.window = workbench_window + + return workbench, workbench_window + + def show_perspective(self, workbench_window, perspective): + workbench_window.active_perspective = perspective + workbench_window.layout.is_editor_area_visible = mock.MagicMock( + return_value=perspective.show_editor_area) + + def test_editor_area_with_perspectives(self): + """ Test show_editor_area is respected while switching perspective""" + + # The workbench and workbench window with layout mocked + workbench, workbench_window = self.get_workbench_with_window() + workbench.active_window = workbench_window + + # Add perspectives + workbench.user_perspective_manager.add(self.with_editor) + workbench.user_perspective_manager.add(self.without_editor) + + # There are the methods we want to test if they are called + workbench_window.show_editor_area = mock.MagicMock() + workbench_window.hide_editor_area = mock.MagicMock() + + # Mock more things for initialing the Workbench Window + workbench_window._memento = WorkbenchWindowMemento() + workbench_window._initial_layout = workbench_window._memento + + # Show a perspective with an editor area + self.show_perspective(workbench_window, self.with_editor) + + # show_editor_area should be called + self.assertTrue(workbench_window.show_editor_area.called) + + # Show a perspective withOUT an editor area + workbench_window.hide_editor_area.reset_mock() + self.show_perspective(workbench_window, self.without_editor) + + # hide_editor_area should be called + self.assertTrue(workbench_window.hide_editor_area.called) + + # The with_editor has been seen so this will be restored from the memento + workbench_window.show_editor_area.reset_mock() + self.show_perspective(workbench_window, self.with_editor) + + # show_editor_area should be called + self.assertTrue(workbench_window.show_editor_area.called) + + def test_editor_area_restore_from_saved_state(self): + """ Test if show_editor_area is restored properly from saved state """ + + # The workbench and workbench window with layout mocked + workbench, workbench_window = self.get_workbench_with_window() + workbench.active_window = workbench_window + + # Add perspectives + workbench.user_perspective_manager.add(self.with_editor) + workbench.user_perspective_manager.add(self.without_editor) + + # Mock for initialising the workbench window + workbench_window._memento = WorkbenchWindowMemento() + workbench_window._initial_layout = workbench_window._memento + + # Mock layout functions for pickling + # We only care about show_editor_area and not the layout in this test + layout_functions = {"get_view_memento.return_value": (0, (None, None)), + "get_editor_memento.return_value": (0, (None, None)), + "get_toolkit_memento.return_value": (0, dict(geometry=""))} + + workbench_window.layout.configure_mock(**layout_functions) + + # The following records perspective mementos to workbench_window._memento + self.show_perspective(workbench_window, self.without_editor) + self.show_perspective(workbench_window, self.with_editor) + + # Save the window layout to a state file + workbench._save_window_layout(workbench_window) + + # We only needed the state file for this test + del workbench_window + del workbench + + # We create another workbench which uses the state location + # and we test if we can retore the saved perspective correctly + workbench, workbench_window = self.get_workbench_with_window() + + # Mock window factory since we already created a workbench window + workbench.window_factory = mock.MagicMock(return_value=workbench_window) + + # There are the methods we want to test if they are called + workbench_window.show_editor_area = mock.MagicMock() + workbench_window.hide_editor_area = mock.MagicMock() + + # This restores the perspectives and mementos + workbench.create_window() + + # Create contents + workbench_window._create_contents(mock.Mock()) + + # Perspective mementos should be restored + self.assertIn(self.with_editor.id, workbench_window._memento.perspective_mementos) + self.assertIn(self.without_editor.id, workbench_window._memento.perspective_mementos) + + # Since the with_editor perspective is used last, + # it should be used as initial perspective + self.assertTrue(workbench_window.show_editor_area.called) + + # Try restoring the perspective without editor + # The restored perspectives are not the same instance as before + # We need to get them using their id + perspective_without_editor = workbench_window.get_perspective_by_id( + self.without_editor.id) + + # Show the perspective with editor area + workbench_window.hide_editor_area.reset_mock() + self.show_perspective(workbench_window, perspective_without_editor) + + # make sure hide_editor_area is called + self.assertTrue(workbench_window.hide_editor_area.called) + diff -Nru python-pyface-4.5.2/pyface/workbench/traits_ui_editor.py python-pyface-6.1.2/pyface/workbench/traits_ui_editor.py --- python-pyface-4.5.2/pyface/workbench/traits_ui_editor.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/traits_ui_editor.py 2019-05-03 08:18:50.000000000 +0000 @@ -6,10 +6,9 @@ # Enthought library imports. from traits.api import Instance, Str -from traitsui.api import UI # Local imports. -from editor import Editor +from .editor import Editor # Logging. @@ -24,7 +23,7 @@ # The traits UI that represents the editor. # # The framework sets this to the value returned by 'create_ui'. - ui = Instance(UI) + ui = Instance("traitsui.ui.UI") # The name of the traits UI view used to create the UI (if not specified, # the default traits UI view is used). diff -Nru python-pyface-4.5.2/pyface/workbench/traits_ui_view.py python-pyface-6.1.2/pyface/workbench/traits_ui_view.py --- python-pyface-4.5.2/pyface/workbench/traits_ui_view.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/traits_ui_view.py 2019-05-03 08:18:50.000000000 +0000 @@ -6,10 +6,9 @@ # Enthought library imports. from traits.api import Any, Instance, Str -from traitsui.api import UI # Local imports. -from view import View +from .view import View # Logging. @@ -28,7 +27,7 @@ # The traits UI that represents the view. # # The framework sets this to the value returned by 'create_ui'. - ui = Instance(UI) + ui = Instance('traitsui.ui.UI') # The name of the traits UI view used to create the UI (if not specified, # the default traits UI view is used). diff -Nru python-pyface-4.5.2/pyface/workbench/user_perspective_manager.py python-pyface-6.1.2/pyface/workbench/user_perspective_manager.py --- python-pyface-4.5.2/pyface/workbench/user_perspective_manager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/user_perspective_manager.py 2019-05-03 08:18:50.000000000 +0000 @@ -51,7 +51,7 @@ """ Property getter. """ # Get all of the current perspective ids: - ids = self.id_to_perspective.keys() + ids = list(self.id_to_perspective.keys()) # If there are none: if len( ids ) == 0: @@ -69,7 +69,7 @@ if self._id_to_perspective is None: self._id_to_perspective = dic = {} try: - fh = file( self.file_name, 'r' ) + fh = open( self.file_name, 'r' ) for line in fh: data = line.split( ':', 1 ) if len( data ) == 2: @@ -88,7 +88,7 @@ def _get_perspectives ( self ): """ Property getter. """ - return self.id_to_perspective.values() + return list(self.id_to_perspective.values()) def _get_file_name ( self ): """ Property getter. """ @@ -123,7 +123,7 @@ clone.id = '__user_perspective_%09d__' % self.next_id # Set any traits specified as keyword arguments. - clone.set(**traits) + clone.trait_set(**traits) # Add the perspective to the map. self.id_to_perspective[clone.id] = clone @@ -131,7 +131,8 @@ # fixme: This needs to be pushed into the window API!!!!!!! window._memento.perspective_mementos[clone.id] = ( window.layout.get_view_memento(), - window.active_view and window.active_view.id or None + window.active_view and window.active_view.id or None, + window.layout.is_editor_area_visible() ) # Update the persistent file information. @@ -206,7 +207,7 @@ """ Update the persistent file information. """ try: - fh = file( self.file_name, 'w' ) + fh = open( self.file_name, 'w' ) fh.write( '\n'.join( [ '%s: %s' % ( p.id, p.name ) for p in self.perspectives ] ) ) fh.close() diff -Nru python-pyface-4.5.2/pyface/workbench/window_event.py python-pyface-6.1.2/pyface/workbench/window_event.py --- python-pyface-4.5.2/pyface/workbench/window_event.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/window_event.py 2019-05-03 08:18:50.000000000 +0000 @@ -5,7 +5,7 @@ from traits.api import HasTraits, Instance, Vetoable # Local imports. -from workbench_window import WorkbenchWindow +from .workbench_window import WorkbenchWindow class WindowEvent(HasTraits): @@ -23,4 +23,3 @@ pass #### EOF ###################################################################### - diff -Nru python-pyface-4.5.2/pyface/workbench/workbench.py python-pyface-6.1.2/pyface/workbench/workbench.py --- python-pyface-4.5.2/pyface/workbench/workbench.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/workbench.py 2019-05-03 08:18:50.000000000 +0000 @@ -2,7 +2,7 @@ # Standard library imports. -import cPickle +import six.moves.cPickle import logging import os @@ -14,11 +14,11 @@ from traits.api import VetoableEvent # Local imports. -from i_editor_manager import IEditorManager -from i_workbench import IWorkbench -from user_perspective_manager import UserPerspectiveManager -from workbench_window import WorkbenchWindow -from window_event import WindowEvent, VetoableWindowEvent +from .i_editor_manager import IEditorManager +from .i_workbench import IWorkbench +from .user_perspective_manager import UserPerspectiveManager +from .workbench_window import WorkbenchWindow +from .window_event import WindowEvent, VetoableWindowEvent # Logging. @@ -315,8 +315,8 @@ # If the memento class itself has been modified then there # is a chance that the unpickle will fail. If so then we just # carry on as if there was no memento! - f = file(filename, 'r') - memento = cPickle.load(f) + f = open(filename, 'rb') + memento = six.moves.cPickle.load(f) f.close() # The memento doesn't actually get used until the window is @@ -334,8 +334,8 @@ """ Save the window layout. """ # Save the window layout. - f = file(os.path.join(self.state_location, 'window_memento'), 'w') - cPickle.dump(window.get_memento(), f) + f = open(os.path.join(self.state_location, 'window_memento'), 'wb') + six.moves.cPickle.dump(window.get_memento(), f) f.close() return diff -Nru python-pyface-4.5.2/pyface/workbench/workbench_window.py python-pyface-6.1.2/pyface/workbench/workbench_window.py --- python-pyface-4.5.2/pyface/workbench/workbench_window.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/workbench/workbench_window.py 2019-05-03 08:18:50.000000000 +0000 @@ -7,18 +7,18 @@ # Enthought library imports. from pyface.api import ApplicationWindow, GUI from traits.api import Callable, Constant, Delegate, Event, Instance -from traits.api import List, Str, Tuple, Unicode, Vetoable +from traits.api import List, Str, Tuple, Unicode, Vetoable, Undefined from traits.api import on_trait_change, provides # Local imports. -from i_editor import IEditor -from i_editor_manager import IEditorManager -from i_perspective import IPerspective -from i_view import IView -from i_workbench_part import IWorkbenchPart -from perspective import Perspective -from workbench_window_layout import WorkbenchWindowLayout -from workbench_window_memento import WorkbenchWindowMemento +from .i_editor import IEditor +from .i_editor_manager import IEditorManager +from .i_perspective import IPerspective +from .i_view import IView +from .i_workbench_part import IWorkbenchPart +from .perspective import Perspective +from .workbench_window_layout import WorkbenchWindowLayout +from .workbench_window_memento import WorkbenchWindowMemento # Logging. @@ -568,7 +568,8 @@ # The layout of the active perspective. self._memento.perspective_mementos[self.active_perspective.id] = ( self.layout.get_view_memento(), - self.active_view and self.active_view.id or None + self.active_view and self.active_view.id or None, + self.layout.is_editor_area_visible() ) # The layout of the editor area. @@ -727,7 +728,8 @@ # Save the current layout of the perspective. self._memento.perspective_mementos[perspective.id] = ( self.layout.get_view_memento(), - self.active_view and self.active_view.id or None + self.active_view and self.active_view.id or None, + self.layout.is_editor_area_visible() ) return @@ -737,15 +739,25 @@ # If the perspective has been seen before then restore it. memento = self._memento.perspective_mementos.get(new.id) + if memento is not None: # Show the editor area? - if new.show_editor_area: + # We need to set the editor area before setting the views + if len(memento) == 2: + logger.warning("Restoring perspective from an older version.") + editor_area_visible = True + else: + editor_area_visible = memento[2] + + # Show the editor area if it is set to be visible + if editor_area_visible: self.show_editor_area() else: self.hide_editor_area() self.active_editor = None - view_memento, active_view_id = memento + # Now set the views + view_memento, active_view_id = memento[:2] self.layout.set_view_memento(view_memento) # Make sure the active part, view and editor reflect the new @@ -768,12 +780,12 @@ # perspective. self.active_view = None - # Show the editor area? - if new.show_editor_area: - self.show_editor_area() - else: - self.hide_editor_area() - self.active_editor = None + # Show the editor area? + if new.show_editor_area: + self.show_editor_area() + else: + self.hide_editor_area() + self.active_editor = None # Inform the perspective that it has been shown. new.show(self) @@ -881,6 +893,9 @@ def _on_editor_closed(self, editor): """ Dynamic trait change handler. """ + if editor is None or editor is Undefined: + return + index = self.editors.index(editor) del self.editors[index] if editor is self.active_editor: diff -Nru python-pyface-4.5.2/pyface/wx/aui.py python-pyface-6.1.2/pyface/wx/aui.py --- python-pyface-4.5.2/pyface/wx/aui.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/aui.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,293 @@ +# Standard library imports. +import logging + +import os + +# Major package imports. +import wx + +# Logger. +logger = logging.getLogger(__name__) + +# Multiple AUI versions are no longer supported; the C version in wx.aui is not +# capable of supporting the windowing flexibility needed by tasks. Therefore, +# only AGW's pure-python AUI implementation is used. + +from wx.lib.agw import aui + +# AGW's library does need some patching for some usability differences desired +# for pyface but not for the standard wxPython version + +class PyfaceAuiNotebook(aui.AuiNotebook): + if wx.version() >= '3.': + SetPageToolTip = aui.AuiNotebook.SetPageTooltip + GetPageToolTip = aui.AuiNotebook.GetPageTooltip + + +class PyfaceAuiManager(aui.AuiManager): + # The standard AuiManager dock resizing attempts to adjust all the docks to + # provide some sort of best fit, but when there are more than two panes in + # a dock it isn't very intuitive. The modifications to these three methods + # tries to keep as many sizers fixes as it can and only adjust the one that + # is added. + + def CalculateDockSizerLimits(self, dock): + # Replacement for default calculation for min/max dock sizes. Instead + # of adjusting the sizes of all the docks, only adjusts one to make the + # dock insertion process a little more like what the user expected. + + docks, panes = aui.CopyDocksAndPanes2(self._docks, self._panes) + + sash_size = self._art.GetMetric(aui.AUI_DOCKART_SASH_SIZE) + caption_size = self._art.GetMetric(aui.AUI_DOCKART_CAPTION_SIZE) + opposite_size = self.GetOppositeDockTotalSize(docks, dock.dock_direction) + + for tmpDock in docks: + + if tmpDock.dock_direction == dock.dock_direction and \ + tmpDock.dock_layer == dock.dock_layer and \ + tmpDock.dock_row == dock.dock_row: + + tmpDock.size = 1 + break + neighbor_docks = [] + horizontal = dock.dock_direction == aui.AUI_DOCK_LEFT or dock.dock_direction == aui.AUI_DOCK_RIGHT + right_or_down = dock.dock_direction == aui.AUI_DOCK_RIGHT or dock.dock_direction == aui.AUI_DOCK_BOTTOM + for d in docks: + if d.dock_direction == dock.dock_direction and d.dock_layer == dock.dock_layer: + if horizontal: + neighbor_docks.append((d.rect.x, d.rect.width)) + else: + neighbor_docks.append((d.rect.y, d.rect.height)) + neighbor_docks.sort() + + sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False) + client_size = self._frame.GetClientSize() + sizer.SetDimension(0, 0, client_size.x, client_size.y) + sizer.Layout() + + for part in uiparts: + + part.rect = wx.RectPS(part.sizer_item.GetPosition(), part.sizer_item.GetSize()) + if part.type == aui.AuiDockUIPart.typeDock: + part.dock.rect = part.rect + + sizer.Destroy() + new_dock = None + + for tmpDock in docks: + if tmpDock.dock_direction == dock.dock_direction and \ + tmpDock.dock_layer == dock.dock_layer and \ + tmpDock.dock_row == dock.dock_row: + + new_dock = tmpDock + break + + partnerDock = self.GetPartnerDock(dock) + + if partnerDock: + if horizontal: + pos = dock.rect.x + size = dock.rect.width + else: + pos = dock.rect.y + size = dock.rect.height + + min_pos = pos + max_pos = pos + size + if right_or_down: + for p, s in neighbor_docks: + if p >= pos: + max_pos = p + s - sash_size + break + else: + min_pos = p + sash_size + else: + for p, s in neighbor_docks: + if p > pos: + max_pos = p + s - sash_size + break + else: + min_pos = p + sash_size + + return min_pos, max_pos + + direction = new_dock.dock_direction + + if direction == aui.AUI_DOCK_LEFT: + minPix = new_dock.rect.x + new_dock.rect.width + maxPix = client_size.x - opposite_size - sash_size + + elif direction == aui.AUI_DOCK_TOP: + minPix = new_dock.rect.y + new_dock.rect.height + maxPix = client_size.y - opposite_size - sash_size + + elif direction == aui.AUI_DOCK_RIGHT: + minPix = opposite_size + maxPix = new_dock.rect.x - sash_size + + elif direction == aui.AUI_DOCK_BOTTOM: + minPix = opposite_size + maxPix = new_dock.rect.y - sash_size + + return minPix, maxPix + + def GetPartnerDockFromPos(self, dock, point): + """Get the neighboring dock located at the given position, used to + find the other dock that is going to change size when resizing the + specified dock. + """ + horizontal = dock.dock_direction == aui.AUI_DOCK_LEFT or dock.dock_direction == aui.AUI_DOCK_RIGHT + right_or_down = dock.dock_direction == aui.AUI_DOCK_RIGHT or dock.dock_direction == aui.AUI_DOCK_BOTTOM + if horizontal: + pos = point.x + else: + pos = point.y + neighbor_docks = [] + for d in self._docks: + if d.dock_direction == dock.dock_direction and d.dock_layer == dock.dock_layer: + if horizontal: + neighbor_docks.append((d.rect.x, d.rect.width, d)) + else: + neighbor_docks.append((d.rect.y, d.rect.height, d)) + neighbor_docks.sort() + last = None + if right_or_down: + for p, s, d in neighbor_docks: + if pos < p + s: + if d.dock_row == dock.dock_row: + d = last + break + last = d + else: + neighbor_docks.reverse() + for p, s, d in neighbor_docks: + if pos > p: + if d.dock_row == dock.dock_row: + d = last + break + last = d + return d + + def RestrictResize(self, clientPt, screenPt, createDC): + """ Common method between :meth:`DoEndResizeAction` and :meth:`OnLeftUp_Resize`. """ + + dock = self._action_part.dock + pane = self._action_part.pane + + if createDC: + if wx.Platform == "__WXMAC__": + dc = wx.ClientDC(self._frame) + else: + dc = wx.ScreenDC() + + aui.DrawResizeHint(dc, self._action_rect) + self._action_rect = wx.Rect() + + newPos = clientPt - self._action_offset + + if self._action_part.type == aui.AuiDockUIPart.typeDockSizer: + minPix, maxPix = self.CalculateDockSizerLimits(dock) + else: + if not self._action_part.pane: + return + minPix, maxPix = self.CalculatePaneSizerLimits(dock, pane) + + if self._action_part.orientation == wx.HORIZONTAL: + newPos.y = aui.Clip(newPos.y, minPix, maxPix) + else: + newPos.x = aui.Clip(newPos.x, minPix, maxPix) + + if self._action_part.type == aui.AuiDockUIPart.typeDockSizer: + partner = self.GetPartnerDockFromPos(dock, newPos) + sash_size = self._art.GetMetric(aui.AUI_DOCKART_SASH_SIZE) + button_size = self._art.GetMetric(aui.AUI_DOCKART_PANE_BUTTON_SIZE) + new_dock_size = 0 + direction = dock.dock_direction + + if direction == aui.AUI_DOCK_LEFT: + new_dock_size = newPos.x - dock.rect.x + + elif direction == aui.AUI_DOCK_TOP: + new_dock_size = newPos.y - dock.rect.y + + elif direction == aui.AUI_DOCK_RIGHT: + new_dock_size = dock.rect.x + dock.rect.width - newPos.x - sash_size + + elif direction == aui.AUI_DOCK_BOTTOM: + new_dock_size = dock.rect.y + dock.rect.height - newPos.y - sash_size + + delta = new_dock_size - dock.size + if delta < -dock.size + sash_size: + delta = -dock.size + sash_size + elif -button_size < delta < button_size: + delta = button_size * (1 if delta > 0 else -1) + + if partner: + if delta > partner.size - sash_size: + delta = partner.size - sash_size + partner.size -= delta + dock.size += delta + self.Update() + + else: + + # determine the new pixel size that the user wants + # this will help us recalculate the pane's proportion + if dock.IsHorizontal(): + oldPixsize = pane.rect.width + newPixsize = oldPixsize + newPos.x - self._action_part.rect.x + + else: + oldPixsize = pane.rect.height + newPixsize = oldPixsize + newPos.y - self._action_part.rect.y + + totalPixsize, totalProportion = self.GetTotalPixSizeAndProportion(dock) + partnerPane = self.GetPartnerPane(dock, pane) + + # prevent division by zero + if totalPixsize <= 0 or totalProportion <= 0 or not partnerPane: + return + + # adjust for the surplus + while (oldPixsize > 0 and totalPixsize > 10 and \ + oldPixsize*totalProportion/totalPixsize < pane.dock_proportion): + + totalPixsize -= 1 + + # calculate the new proportion of the pane + + newProportion = newPixsize*totalProportion/totalPixsize + newProportion = aui.Clip(newProportion, 1, totalProportion) + deltaProp = newProportion - pane.dock_proportion + + if partnerPane.dock_proportion - deltaProp < 1: + deltaProp = partnerPane.dock_proportion - 1 + newProportion = pane.dock_proportion + deltaProp + + # borrow the space from our neighbor pane to the + # right or bottom (depending on orientation) + partnerPane.dock_proportion -= deltaProp + pane.dock_proportion = newProportion + + self.Update() + + return True + + def UpdateWithoutLayout(self): + """If the layout in the AUI manager is not changing, this can be called + to refresh all the panes but preventing a big time usage doing a re- + layout that isn't necessary. + """ + pane_count = len(self._panes) + + for ii in range(pane_count): + p = self._panes[ii] + if p.window and p.IsShown() and p.IsDocked(): + p.window.Refresh() + p.window.Update() + + if wx.Platform == "__WXMAC__": + self._frame.Refresh() + else: + self.Repaint() diff -Nru python-pyface-4.5.2/pyface/wx/clipboard.py python-pyface-6.1.2/pyface/wx/clipboard.py --- python-pyface-4.5.2/pyface/wx/clipboard.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/clipboard.py 2019-05-03 08:18:50.000000000 +0000 @@ -11,8 +11,9 @@ #------------------------------------------------------------------------------ import logging -logging.warn('DEPRECATED: pyface.wx.clipboard, ' - 'use pyface.api instead.') + +logger = logging.getLogger() +logger.warning('DEPRECATED: pyface.wx.clipboard, use pyface.api instead.') from pyface.ui.wx.clipboard import Clipboard clipboard = Clipboard() diff -Nru python-pyface-4.5.2/pyface/wx/drag_and_drop.py python-pyface-6.1.2/pyface/wx/drag_and_drop.py --- python-pyface-4.5.2/pyface/wx/drag_and_drop.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/drag_and_drop.py 2019-05-03 08:18:50.000000000 +0000 @@ -14,10 +14,17 @@ """ Drag and drop utilities. """ # Standard library imports. -import inspect +import six +if six.PY2: + from inspect import getargspec +else: + # avoid deprecation warning + from inspect import getfullargspec as getargspec + # Major package imports. import wx +import six class Clipboard: @@ -33,6 +40,38 @@ clipboard.data = None +class FileDropSource(wx.DropSource): + """ Represents a draggable file. + """ + + def __init__(self, source, files): + """ Initializes the object. + """ + self.handler = None + self.allow_move = True + + # Put the data to be dragged on the clipboard: + clipboard.data = files + clipboard.source = source + clipboard.drop_source = self + + data_object = wx.FileDataObject() + if isinstance(files, six.text_type): + files = [files] + + for file in files: + data_object.AddFile(file) + + # Create the drop source and begin the drag and drop operation: + super(FileDropSource, self).__init__(source) + self.SetData(data_object) + self.result = self.DoDragDrop(True) + + def on_dropped(self, drag_result): + """ Called when the data has been dropped. """ + return + + class FileDropTarget(wx.FileDropTarget): """ Drop target for files. """ @@ -107,7 +146,7 @@ # For backward compatibility we accept handler functions # with either 1 or 3 args, including self. If there are # 3 args then we pass the data and the drag_result. - args = inspect.getargspec(self.handler.on_dropped)[0] + args = getargspec(self.handler.on_dropped)[0] if len(args) == 3: self.handler.on_dropped(clipboard.data, drag_result) else: @@ -119,7 +158,7 @@ # For backward compatibility we accept handler functions # with either 0 or 2 args. If there are 2 args then # we pass the data and drag_result - args = inspect.getargspec(self.handler)[0] + args = getargspec(self.handler)[0] if len(args)==2: self.handler(clipboard.data, drag_result) else: diff -Nru python-pyface-4.5.2/pyface/wx/grid/api.py python-pyface-6.1.2/pyface/wx/grid/api.py --- python-pyface-4.5.2/pyface/wx/grid/api.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/grid/api.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,19 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +from __future__ import absolute_import + +from .grid import Grid +from .grid_column import GridColumn +from .grid_model import GridModel +from .grid_row import GridRow diff -Nru python-pyface-4.5.2/pyface/wx/grid/grid_column.py python-pyface-6.1.2/pyface/wx/grid/grid_column.py --- python-pyface-4.5.2/pyface/wx/grid/grid_column.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/grid/grid_column.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,33 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" A description of a column in a grid. """ + + +# Enthought library imports. +from traits.api import Bool, HasTraits, Str + + +class GridColumn(HasTraits): + """ A description of a column in a grid. """ + + # Column header. + label = Str + + # Type name of data allowed in the column. + type = Str + + # Is the column read-only? + readonly = Bool(False) + +#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/wx/grid/grid_model.py python-pyface-6.1.2/pyface/wx/grid/grid_model.py --- python-pyface-4.5.2/pyface/wx/grid/grid_model.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/grid/grid_model.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,283 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" A model that provides data for a grid. """ + +# Major package imports. +from __future__ import print_function +import wx +from wx.grid import PyGridTableBase, GridTableMessage, GRIDTABLE_NOTIFY_ROWS_APPENDED + +# Enthought library imports. +from traits.api import Any, Bool, HasTraits, Trait, Event, List + +# Local imports. +from .grid_column import GridColumn +from .grid_row import GridRow + + +class GridModel(HasTraits): + """ A model that provides data for a grid. """ + + # fixme : factor this default model into "SimpleGridModel" or similar + # An optional 2-dimensional list/array containing the grid data. + data = Any + + # The rows in the model. + rows = List(GridRow) + + # The columns in the model. + columns = List(GridColumn) + + # Show row headers? + show_row_headers = Bool(True) + + # Show column headers? + show_column_headers = Bool(True) + + # Fired when the data in the model has changed. + model_changed = Event + + + def __init__(self, **traits): + """ Create a new grid model. """ + + # Base class constructors. + HasTraits.__init__(self, **traits) + + # The wx virtual table hook. + self._grid_table_base = _GridTableBase(self) + + if len(self.columns) == 0 and self.data is not None: + print("Building default table column model") + columns = [] + # Assume data is rectangular and use the length of the first row. + for i in range(len(self.data[0])): + columns.append(GridColumn(label=str(i))) + self.columns = columns + + return + + ########################################################################### + # 'wxPyGridTableBase' interface. + ########################################################################### + + def GetNumberRows(self): + """ Return the number of rows in the model. """ + + return len(self.data) + + def GetNumberCols(self): + """ Return the number of columns in the model. """ + + return len(self.columns) + + def IsEmptyCell(self, row, col): + """ Is the specified cell empty? """ + + try: + return not self.data[row][col] + + except IndexError: + return True + + # Get/Set values in the table. The Python versions of these methods can + # handle any data-type, (as long as the Editor and Renderer understands the + # type too,) not just strings as in the C++ version. + def GetValue(self, row, col): + """ Get the value at the specified row and column. """ + + try: + return self.data[row][col] + + except IndexError: + pass + + return '' + + def SetValue(self, row, col, value): + """ Set the value at the specified row and column. """ + + label = self.GetColLabelValue(col) + + try: + self.data[row][col] = value + + except IndexError: + # Add a new row. + self.data.append([0] * self.GetNumberCols()) + self.data[row][col] = value + + # Tell the grid that we've added a row. + # + # N.B wxGridTableMessage(table, whatWeDid, howMany) + message = GridTableMessage( + self, GRIDTABLE_NOTIFY_ROWS_APPENDED, 1 + ) + + # Trait event notification. + self.model_changed = message + + return + + def GetRowLabelValue(self, row): + """ Called when the grid needs to display a row label. """ + + return str(row) + + def GetColLabelValue(self, col): + """ Called when the grid needs to display a column label. """ + + return self.columns[col].label + + def GetTypeName(self, row, col): + """ Called to determine the kind of editor/renderer to use. + + This doesn't necessarily have to be the same type used natively by the + editor/renderer if they know how to convert. + + """ + + return self.columns[col].type + + def CanGetValueAs(self, row, col, type_name): + """ Called to determine how the data can be fetched. + + This allows you to enforce some type-safety in the grid. + + """ + + column_typename = self.GetTypeName(row, col) + + return type_name == column_typename + + def CanSetValueAs(self, row, col, type_name): + """ Called to determine how the data can be stored. + + This allows you to enforce some type-safety in the grid. + + """ + + return self.CanGetValueAs(row, col, type_name) + + def DeleteRows(self, pos, num_rows): + """ Called when the view is deleting rows. """ + + del self.data[pos:pos + num_rows] + + # Tell the grid that we've deleted some rows. + # + # N.B Because of a bug in wxPython we have to send a "rows appended" + # --- message with a negative number, instead of the "rows deleted" + # message 8^() TINSTAFS! + message = GridTableMessage( + self, GRIDTABLE_NOTIFY_ROWS_APPENDED, -num_rows + ) + + # Trait event notification. + self.model_changed = message + + return True + + +class _GridTableBase(PyGridTableBase): + """ A model that provides data for a grid. """ + + ########################################################################### + # 'object' interface. + ########################################################################### + + def __init__(self, model): + """ Creates a new table base. """ + + # Base class constructor. + PyGridTableBase.__init__(self) + + # The Pyface model that provides the data. + self.model = model + + return + + ########################################################################### + # 'wxPyGridTableBase' interface. + ########################################################################### + + def GetNumberRows(self): + """ Return the number of rows in the model. """ + + return self.model.GetNumberRows() + + def GetNumberCols(self): + """ Return the number of columns in the model. """ + + return self.model.GetNumberCols() + + def IsEmptyCell(self, row, col): + """ Is the specified cell empty? """ + + return self.model.IsEmptyCell(row, col) + + def GetValue(self, row, col): + """ Get the value at the specified row and column. """ + + return self.model.GetValue(row, col) + + def SetValue(self, row, col, value): + """ Set the value at the specified row and column. """ + + return self.model.SetValue(row, col, value) + + def GetRowLabelValue(self, row): + """ Called when the grid needs to display a row label. """ + + return self.model.GetRowLabelValue(row) + + def GetColLabelValue(self, col): + """ Called when the grid needs to display a column label. """ + + return self.model.GetColLabelValue(col) + + def GetTypeName(self, row, col): + """ Called to determine the kind of editor/renderer to use. + + This doesn't necessarily have to be the same type used natively by the + editor/renderer if they know how to convert. + + """ + + return self.model.GetTypeName(row, col) + + def CanGetValueAs(self, row, col, type_name): + """ Called to determine how the data can be fetched. + + This allows you to enforce some type-safety in the grid. + + """ + + return self.model.CanGetValueAs(row, col, type_name) + + def CanSetValueAs(self, row, col, type_name): + """ Called to determine how the data can be stored. + + This allows you to enforce some type-safety in the grid. + + """ + + return self.model.CanSetValueAs(row, col, type_name) + + def DeleteRows(self, pos, num_rows): + """ Called when the view is deleting rows. """ + + return self.model.DeleteRows(pos, num_rows) + +#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/wx/grid/grid.py python-pyface-6.1.2/pyface/wx/grid/grid.py --- python-pyface-4.5.2/pyface/wx/grid/grid.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/grid/grid.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,354 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" A grid (spreadsheet) widget. """ + + +# Major package imports. +from __future__ import print_function +import wx +from wx.grid import Grid as wxGrid + + +# Local imports. +from .grid_model import GridModel + + +class Grid(wxGrid): + """ A grid (spreadsheet) widget. """ + + def __init__(self, parent, model): + """ Constructor. """ + + # Base class constructor. + wxGrid.__init__(self, parent, -1) + + # The model that provides the data and row/column information. + self.model = None + + # Automatically size columns and rows to fit their content. + # + # fixme: wx seems sensitive to the location of these two lines. Put + # them *before* the call to 'SetTable', otherwise the grid takes + # forever to initialize! + ##self.AutoSizeColumns() + ##self.AutoSizeRows() + + # Don't display any extra space around the rows and columns. + self.SetMargins(0, 0) + + # Tell the grid to get its data from the model. + # + # N.B The terminology used in the wxPython API is a little confusing! + # --- The 'SetTable' method is actually setting the model used by + # the grid (which is the view)! + # + # The second parameter to 'SetTable' tells the grid to take ownership + # of the model and to destroy it when it is done. Otherwise you would + # need to keep a reference to the model and manually destroy it later + # (by calling it's Destroy method). + # + # fixme: We should create a default model if one is not supplied. + self.SetTable(model._grid_table_base, True) + model.on_trait_change(self._on_model_changed, 'model_changed') + + wx.grid.EVT_GRID_CELL_CHANGE(self, self._on_cell_change) + wx.grid.EVT_GRID_SELECT_CELL(self, self._on_select_cell) + + # This starts the cell editor on a double-click as well as on a second + # click. + wx.grid.EVT_GRID_CELL_LEFT_DCLICK(self, self._on_cell_left_dclick) + + # This pops up a context menu. + #wx.grid.EVT_GRID_CELL_RIGHT_CLICK(self, self._on_cell_right_click) + + # We handle key presses to change the behavior of the and + # keys to make manual data entry smoother. + wx.EVT_KEY_DOWN(self, self._on_key_down) + + # Initialize the row and column models. + self._initialize_rows(model) + self._initialize_columns(model) + self._initialize_fonts() + + return + + def _initialize_fonts(self): + """ Initialize the label fonts. """ + + self.SetLabelFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD)) + self.SetGridLineColour("blue") + self.SetColLabelAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) + self.SetRowLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTRE) + + return + + def _initialize_rows(self, model): + """ Initialize the row headers. """ + + if not model.show_row_headers: + self.SetRowLabelSize(0) + + else: + for index, row in enumerate(model.rows): + if row.readonly: + attr = wx.grid.GridCellAttr() + attr.SetReadOnly() + attr.SetRenderer(None) + attr.SetBackgroundColour('linen') + self.SetRowAttr(index, attr) + + return + + def _initialize_columns(self, model): + """ Initialize the column headers. """ + + if not model.show_column_headers: + self.SetColLabelSize(0) + + else: + for index, column in enumerate(model.columns): + if column.readonly: + attr = wx.grid.GridCellAttr() + attr.SetReadOnly() + attr.SetRenderer(None) + attr.SetBackgroundColour('linen') + self.SetColAttr(index, attr) + + return + + ########################################################################### + # wx event handlers. + ########################################################################### + + def _on_cell_change(self, evt): + """ Called when the contents of a cell have been changed. """ + + row = evt.GetRow() + col = evt.GetCol() + + ##print 'Cell changed at', row, col + value = self.GetTable().GetValue(row, col) + + ##print 'New value', value + ##print 'Type', type(value) + + evt.Skip() + + return + + def _on_select_cell(self, evt): + """ Called when the user has moved to another cell. """ + + ##row = evt.GetRow() + ##col = evt.GetCol() + + ##print 'Cell selected at', row, col + + evt.Skip() + + return + + def _on_cell_left_dclick(self, evt): + """ Called when the left mouse button was double-clicked. + + From the wxPython demo code:- + + 'I do this because I don't like the default behaviour of not starting + the cell editor on double clicks, but only a second click.' + + Fair enuff! + + """ + + if self.CanEnableCellControl(): + self.EnableCellEditControl() + + return + + def _on_cell_right_click(self, evt): + """ Called when a right click occurred in a cell. """ + + row = evt.GetRow() + + # The last row in the table is not part of the actual data, it is just + # there to allow the user to enter a new row. Hence they cannot delete + # it! + if row < self.GetNumberRows() - 1: + # Complete the edit on the current cell. + self.DisableCellEditControl() + + # Make the row the ONLY one selected. + self.SelectRow(row) + + # Popup a context menu allowing the user to delete the row. + menu = wx.Menu() + menu.Append(101, "Delete Row") + wx.EVT_MENU(self, 101, self._on_delete_row) + + self.PopupMenu(menu, evt.GetPosition()) + + return + + def _on_key_down(self, evt): + """ Called when a key is pressed. """ + + # This changes the behaviour of the and keys to make + # manual data entry smoother! + # + # Don't change the behavior if the key is pressed as this + # has meaning to the edit control. + key_code = evt.GetKeyCode() + if key_code == wx.WXK_RETURN and not evt.ControlDown(): + self._move_to_next_cell(evt.ShiftDown()) + + elif key_code == wx.WXK_TAB and not evt.ControlDown(): + if evt.ShiftDown(): + self._move_to_previous_cell() + + else: + self._move_to_next_cell() + + else: + evt.Skip() + + return + + def _on_delete_row(self, evt): + """ Called when the 'Delete Row' context menu item is selected. """ + + # Get the selected row (there must be exactly one at this point!). + selected_rows = self.GetSelectedRows() + if len(selected_rows) == 1: + self.DeleteRows(selected_rows[0], 1) + + return + + ########################################################################### + # Trait event handlers. + ########################################################################### + + def _on_model_changed(self, message): + """ Called when the model has changed. """ + + self.BeginBatch() + self.ProcessTableMessage(message) + self.EndBatch() + + return + + ########################################################################### + # 'Grid' interface. + ########################################################################### + + def Reset(self): + print('Reset') + #attr = grid.GridCellAttr() + #renderer = MyRenderer() + #attr.SetRenderer(renderer) + + #self.SetColSize(0, 50) + #self.SetColAttr(0, attr) + + self.ForceRefresh() + + return + + + def ResetView(self, grid): + """ + (wxGrid) -> Reset the grid view. Call this to + update the grid if rows and columns have been added or deleted + """ + print('*************************VirtualModel.reset_view') + + grid = self + + grid.BeginBatch() + for current, new, delmsg, addmsg in [ + (self._rows, self.GetNumberRows(), GRIDTABLE_NOTIFY_ROWS_DELETED, GRIDTABLE_NOTIFY_ROWS_APPENDED), + (self._cols, self.GetNumberCols(), GRIDTABLE_NOTIFY_COLS_DELETED, GRIDTABLE_NOTIFY_COLS_APPENDED), + ]: + if new < current: + msg = GridTableMessage(self,delmsg,new,current-new) + grid.ProcessTableMessage(msg) + elif new > current: + msg = GridTableMessage(self,addmsg,new-current) + grid.ProcessTableMessage(msg) + self.UpdateValues(grid) + grid.EndBatch() + + self._rows = self.GetNumberRows() + self._cols = self.GetNumberCols() + + # update the renderers + # self._updateColAttrs(grid) + # self._updateRowAttrs(grid) too expensive to use on a large grid + + # update the scrollbars and the displayed part of the grid + grid.AdjustScrollbars() + grid.ForceRefresh() + + return + + + + ########################################################################### + # Protected interface. + ########################################################################### + + def _move_to_next_cell(self, expandSelection=False): + """ Move to the 'next' cell. """ + + # Complete the edit on the current cell. + self.DisableCellEditControl() + + # Try to move to the next column. + success = self.MoveCursorRight(expandSelection) + + # If the move failed then we must be at the end of a row. + if not success: + # Move to the first column in the next row. + newRow = self.GetGridCursorRow() + 1 + if newRow < self.GetNumberRows(): + self.SetGridCursor(newRow, 0) + self.MakeCellVisible(newRow, 0) + + else: + # This would be a good place to add a new row if your app + # needs to do that. + pass + + return success + + def _move_to_previous_cell(self, expandSelection=False): + """ Move to the 'previous' cell. """ + + # Complete the edit on the current cell. + self.DisableCellEditControl() + + # Try to move to the previous column (without expanding the current + # selection). + success = self.MoveCursorLeft(expandSelection) + + # If the move failed then we must be at the start of a row. + if not success: + # Move to the last column in the previous row. + newRow = self.GetGridCursorRow() - 1 + if newRow >= 0: + self.SetGridCursor(newRow, self.GetNumberCols() - 1) + self.MakeCellVisible(newRow, self.GetNumberCols() - 1) + + return + +#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/wx/grid/grid_row.py python-pyface-6.1.2/pyface/wx/grid/grid_row.py --- python-pyface-4.5.2/pyface/wx/grid/grid_row.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/grid/grid_row.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,31 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" A description of a row in a grid. """ + + +# Enthought library imports. +from traits.api import HasTraits + + +class GridRow(HasTraits): + """ A description of a row in a grid. """ + + def __init__(self, row_data): + """ Create a new row. """ + + self.__dict__.update(row_data) + + return + +#### EOF ###################################################################### diff -Nru python-pyface-4.5.2/pyface/wx/grid/__init__.py python-pyface-6.1.2/pyface/wx/grid/__init__.py --- python-pyface-4.5.2/pyface/wx/grid/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/grid/__init__.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,13 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ diff -Nru python-pyface-4.5.2/pyface/wx/image_list.py python-pyface-6.1.2/pyface/wx/image_list.py --- python-pyface-4.5.2/pyface/wx/image_list.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/image_list.py 2019-05-03 08:18:50.000000000 +0000 @@ -16,6 +16,7 @@ # Major package imports. import wx +import six # fixme: rename to 'CachedImageList'?!? @@ -50,7 +51,7 @@ # If the icon is a string then it is the filename of some kind of # image (e.g 'foo.gif', 'image/foo.png' etc). - if isinstance(filename, basestring): + if isinstance(filename, six.string_types): # Try the cache first. index = self._cache.get(filename) if index is None: diff -Nru python-pyface-4.5.2/pyface/wx/pager.py python-pyface-6.1.2/pyface/wx/pager.py --- python-pyface-4.5.2/pyface/wx/pager.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/pager.py 2019-05-03 08:18:50.000000000 +0000 @@ -16,7 +16,7 @@ # Major package imports. import wx -from wx.lib.scrolledpanel import wxScrolledPanel +from wx.lib.scrolledpanel import ScrolledPanel as wxScrolledPanel class Pager(wxScrolledPanel): diff -Nru python-pyface-4.5.2/pyface/wx/python_stc.py python-pyface-6.1.2/pyface/wx/python_stc.py --- python-pyface-4.5.2/pyface/wx/python_stc.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/python_stc.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,409 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +import wx +from wx import stc + +import keyword + +#---------------------------------------------------------------------- + +demoText = """\ +## This version of the editor has been set up to edit Python source +## code. Here is a copy of wxPython/demo/Main.py to play with. + + +""" + +#---------------------------------------------------------------------- + + +if wx.Platform == '__WXMSW__': + faces = { 'times': 'Times New Roman', + 'mono' : 'Courier New', + 'helv' : 'Arial', + 'other': 'Comic Sans MS', + 'size' : 10, + 'size2': 8, + } +else: + faces = { 'times': 'Times', + 'mono' : 'Courier', + 'helv' : 'Helvetica', + 'other': 'new century schoolbook', + 'size' : 12, + 'size2': 10, + } + + +#---------------------------------------------------------------------- + +class PythonSTC(stc.StyledTextCtrl): + def __init__(self, parent, ID): + stc.StyledTextCtrl.__init__(self, parent, ID, + style = wx.NO_FULL_REPAINT_ON_RESIZE) + + self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN) + self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT) + + self.SetLexer(stc.STC_LEX_PYTHON) + self.SetKeyWords(0, " ".join(keyword.kwlist)) + + self.SetProperty("fold", "1") + self.SetProperty("tab.timmy.whinge.level", "1") + self.SetMargins(0,0) + + self.SetViewWhiteSpace(False) + #self.SetBufferedDraw(False) + + self.SetEdgeMode(stc.STC_EDGE_BACKGROUND) + self.SetEdgeColumn(78) + + # Setup a margin to hold fold markers + ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER? + self.SetFoldFlags(16) + #mic + #self.SetMarginType(2, stc.STC_MARGIN_SYMBOL) + #self.SetMarginMask(2, stc.STC_MASK_FOLDERS) + #self.SetMarginSensitive(2, True) + #self.SetMarginWidth(2, 12) + # line numbers in the margin + self.SetMarginType(1, stc.STC_MARGIN_NUMBER) + self.SetMarginWidth(1, 25) + + if 0: # simple folder marks, like the old version + self.MarkerDefine(stc.STC_MARKNUM_FOLDER, + stc.STC_MARK_ARROW, "navy", "navy") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, + stc.STC_MARK_ARROWDOWN, "navy", "navy") + # Set these to an invisible mark + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, + stc.STC_MARK_BACKGROUND, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, + stc.STC_MARK_BACKGROUND, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, + stc.STC_MARK_BACKGROUND, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, + stc.STC_MARK_BACKGROUND, "white", "black") + + elif 0: # more involved "outlining" folder marks + self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, + stc.STC_MARK_BOXPLUSCONNECTED, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, + stc.STC_MARK_BOXMINUSCONNECTED, + "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, + stc.STC_MARK_TCORNER, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, + stc.STC_MARK_LCORNER, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, + stc.STC_MARK_VLINE, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDER, + stc.STC_MARK_BOXPLUS, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, + stc.STC_MARK_BOXMINUS, "white", "black") + + + stc.EVT_STC_UPDATEUI(self, ID, self.OnUpdateUI) + stc.EVT_STC_MARGINCLICK(self, ID, self.OnMarginClick) + + + # 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. + + self.StyleClearAll() + + # Global default styles for all languages + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, + "face:%(helv)s,size:%(size)d" % faces) + self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, + "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces) + self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, + "face:%(other)s" % faces) + self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, + "fore:#FFFFFF,back:#0000FF,bold") + self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, + "fore:#000000,back:#FF0000,bold") + + # Python styles + # White space + self.StyleSetSpec(stc.STC_P_DEFAULT, + "fore:#808080,face:%(helv)s,size:%(size)d" % faces) + # Comment + self.StyleSetSpec(stc.STC_P_COMMENTLINE, + "fore:#007F00,face:%(other)s,size:%(size)d" % faces) + # Number + self.StyleSetSpec(stc.STC_P_NUMBER, + "fore:#007F7F,size:%(size)d" % faces) + # String + self.StyleSetSpec(stc.STC_P_STRING, + "fore:#7F007F,italic,face:%(times)s,size:%(size)d" % faces) + # Single quoted string + self.StyleSetSpec(stc.STC_P_CHARACTER, + "fore:#7F007F,italic,face:%(times)s,size:%(size)d" % faces) + # Keyword + self.StyleSetSpec(stc.STC_P_WORD, + "fore:#00007F,bold,size:%(size)d" % faces) + # Triple quotes + self.StyleSetSpec(stc.STC_P_TRIPLE, + "fore:#7F0000,size:%(size)d" % faces) + # Triple double quotes + self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, + "fore:#7F0000,size:%(size)d" % faces) + # Class name definition + self.StyleSetSpec(stc.STC_P_CLASSNAME, + "fore:#0000FF,bold,underline,size:%(size)d" % faces) + # Function or method name definition + self.StyleSetSpec(stc.STC_P_DEFNAME, + "fore:#007F7F,bold,size:%(size)d" % faces) + # Operators + self.StyleSetSpec(stc.STC_P_OPERATOR, + "bold,size:%(size)d" % faces) + # Identifiers + self.StyleSetSpec(stc.STC_P_IDENTIFIER, + "fore:#808080,face:%(helv)s,size:%(size)d" % faces) + # Comment-blocks + self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, + "fore:#7F7F7F,size:%(size)d" % faces) + # End of line where string is not closed + self.StyleSetSpec(stc.STC_P_STRINGEOL, + "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces) + + + self.SetCaretForeground("BLUE") + + wx.EVT_KEY_DOWN(self, self.OnKeyPressed) + + + def OnKeyPressed(self, event): + if self.CallTipActive(): + self.CallTipCancel() + + # KeyCode used to be a method. Now it is an integer. + # Handle either case. + if type(event.KeyCode) is int: + # wx2.8+ + key = event.KeyCode + else: + # wx2.6 + key = event.KeyCode() + + if key == 32 and event.ControlDown(): + pos = self.GetCurrentPos() + # Tips + if event.ShiftDown(): + self.CallTipSetBackground("yellow") + self.CallTipShow(pos, 'param1, param2') + # Code completion + else: + # fixme: What is this mess!!! + + #lst = [] + #for x in range(50000): + # lst.append('%05d' % x) + #st = " ".join(lst) + #print len(st) + #self.AutoCompShow(0, st) + + # fixme: What is this mess!!! + kw = keyword.kwlist[:] + kw.append("zzzzzz") + kw.append("aaaaa") + kw.append("__init__") + kw.append("zzaaaaa") + kw.append("zzbaaaa") + kw.append("this_is_a_longer_value") + kw.append("this_is_a_much_much_much_much_longer_value") + + kw.sort() # Python sorts are case sensitive + self.AutoCompSetIgnoreCase(False) # so this needs to match + + self.AutoCompShow(0, " ".join(kw)) + 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==stc.STC_P_OPERATOR): + braceAtCaret = caretPos - 1 + + # check after + if braceAtCaret < 0: + charAfter = self.GetCharAt(caretPos) + styleAfter = self.GetStyleAt(caretPos) + if (charAfter and + chr(charAfter) in "[]{}()" and + styleAfter == stc.STC_P_OPERATOR): + braceAtCaret = caretPos + + if braceAtCaret >= 0: + braceOpposite = self.BraceMatch(braceAtCaret) + + if braceAtCaret != -1 and braceOpposite == -1: + self.BraceBadLight(braceAtCaret) + else: + self.BraceHighlight(braceAtCaret, braceOpposite) + #pt = self.PointFromPosition(braceOpposite) + #self.Refresh(True, 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) & 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 FoldAll(self): + lineCount = self.GetLineCount() + expanding = True + + # find out if we are folding or unfolding + for lineNum in range(lineCount): + if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG: + expanding = not self.GetFoldExpanded(lineNum) + break; + + lineNum = 0 + while lineNum < lineCount: + level = self.GetFoldLevel(lineNum) + if level & stc.STC_FOLDLEVELHEADERFLAG and \ + (level & stc.STC_FOLDLEVELNUMBERMASK) == 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 & 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 + + +#---------------------------------------------------------------------- + +_USE_PANEL = 1 + +def runTest(frame, nb, log): + if not _USE_PANEL: + ed = p = stc.PythonSTC(nb, -1) + else: + p = wx.Panel(nb, -1, style = wx.NO_FULL_REPAINT_ON_RESIZE) + ed = PythonSTC(p, -1) + s = wx.BoxSizer(wx.HORIZONTAL) + s.Add(ed, 1, wx.EXPAND) + p.SetSizer(s) + p.SetAutoLayout(True) + + + ed.SetText(demoText + open('Main.py').read()) + ed.EmptyUndoBuffer() + ed.Colourise(0, -1) + + # line numbers in the margin + ed.SetMarginType(1, stc.STC_MARGIN_NUMBER) + ed.SetMarginWidth(1, 25) + + return p + + + +#---------------------------------------------------------------------- + + +overview = """\ + +Once again, no docs yet. Sorry. But this +and this should +be helpful. + +""" + + +if __name__ == '__main__': + # fixme: This has been re-factored into not working. No run module. + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])]) + +#---------------------------------------------------------------------- + diff -Nru python-pyface-4.5.2/pyface/wx/shell.py python-pyface-6.1.2/pyface/wx/shell.py --- python-pyface-4.5.2/pyface/wx/shell.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/shell.py 2019-05-03 08:18:50.000000000 +0000 @@ -17,6 +17,7 @@ SourceForge project page at http://sourceforge.net/projects/pycrust/. Sponsored by Orbtech - Your source for Python programming expertise.""" +from __future__ import print_function __author__ = "Patrick K. O'Brien " __cvsid__ = "$Id: shell.py,v 1.2 2003/06/13 17:59:34 dmorrill Exp $" __revision__ = "$Revision: 1.2 $"[11:-2] @@ -30,8 +31,8 @@ from wx.py.version import VERSION # local imports -from drag_and_drop import PythonObject -from drag_and_drop import clipboard as enClipboard +from .drag_and_drop import PythonObject +from .drag_and_drop import clipboard as enClipboard sys.ps3 = '<-- ' # Input prompt. @@ -123,15 +124,15 @@ if hasattr(self.other, name): return getattr(self.other, name) else: - raise AttributeError, name + raise AttributeError(name) def __setattr__(self, name, value): - if self.__dict__.has_key(name): + if name in self.__dict__: self.__dict__[name] = value elif hasattr(self.other, name): return setattr(self.other, name, value) else: - raise AttributeError, name + raise AttributeError(name) def _getAttributeNames(self): """Return list of magic attributes to extend introspection.""" @@ -276,8 +277,8 @@ This simply sets "close", "exit" and "quit" to a helpful string. """ - import __builtin__ - __builtin__.close = __builtin__.exit = __builtin__.quit = \ + import six.moves.builtins + six.moves.builtins.close = six.moves.builtins.exit = six.moves.builtins.quit = \ 'Click on the close button to leave the application.' def quit(self): @@ -300,7 +301,7 @@ if startupScript and os.path.isfile(startupScript): startupText = 'Startup script executed: ' + startupScript self.push('print %s;execfile(%s)' % \ - (`startupText`, `startupScript`)) + ('startupText', 'startupScript')) else: self.push('') @@ -603,10 +604,10 @@ # to the beginning if we don't find anything. if (self.historyIndex <= -1) \ or (self.historyIndex >= len(self.history)-2): - searchOrder = range(len(self.history)) + searchOrder = list(range(len(self.history))) else: - searchOrder = range(self.historyIndex+1, len(self.history)) + \ - range(self.historyIndex) + searchOrder = list(range(self.historyIndex+1, len(self.history))) + \ + list(range(self.historyIndex)) for i in searchOrder: command = self.history[i] if command[:len(searchText)] == searchText: @@ -623,7 +624,7 @@ # This method will most likely be replaced by the enclosing app # to do something more interesting, like write to a status bar. - print text + print(text) def insertLineBreak(self): """Insert a new line break.""" @@ -1363,4 +1364,3 @@ event.Check(self.crust.filling.fillingTree.showDoc) elif id == ID_FILLING_SHOW_MODULE: event.Check(self.crust.filling.fillingTree.showModule) - diff -Nru python-pyface-4.5.2/pyface/wx/spreadsheet/default_renderer.py python-pyface-6.1.2/pyface/wx/spreadsheet/default_renderer.py --- python-pyface-4.5.2/pyface/wx/spreadsheet/default_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/spreadsheet/default_renderer.py 2019-05-03 08:18:50.000000000 +0000 @@ -15,10 +15,13 @@ # #------------------------------------------------------------------------------- +from __future__ import print_function + import types from string import atof import wx from wx.grid import PyGridCellRenderer +import six #------------------------------------------------------------------------------- @@ -97,9 +100,9 @@ """ Adds three dots "..." to indicate the cell is truncated. """ text = grid.model.GetValue(row, col) - if not isinstance(text, basestring): + if not isinstance(text, six.string_types): msg = 'Problem appending "..." to cell: %d %d' % (row, col) - raise TypeError, msg + raise TypeError(msg) width, height = dc.GetTextExtent(text) if width > rect.width-2: @@ -112,6 +115,6 @@ def GetBestSize88(self, grid, attr, dc, row, col): """ This crashes the app - hmmmm. """ size = PyGridCellRenderer.GetBestSize(self, grid, attr, dc, row, col) - print '-----------------------------', size + print('-----------------------------', size) return size #------------------------------------------------------------------------------- diff -Nru python-pyface-4.5.2/pyface/wx/spreadsheet/font_renderer.py python-pyface-6.1.2/pyface/wx/spreadsheet/font_renderer.py --- python-pyface-4.5.2/pyface/wx/spreadsheet/font_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/spreadsheet/font_renderer.py 2019-05-03 08:18:50.000000000 +0000 @@ -13,7 +13,7 @@ #------------------------------------------------------------------------------ import wx -from default_renderer import DefaultRenderer +from .default_renderer import DefaultRenderer class FontRenderer(DefaultRenderer): """Render data in the specified color and font and fontsize. @@ -91,4 +91,3 @@ def __call__(self, table): return FontRenderer(table, self.color, self.font, self.fontsize) - diff -Nru python-pyface-4.5.2/pyface/wx/spreadsheet/unit_renderer.py python-pyface-6.1.2/pyface/wx/spreadsheet/unit_renderer.py --- python-pyface-4.5.2/pyface/wx/spreadsheet/unit_renderer.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/spreadsheet/unit_renderer.py 2019-05-03 08:18:50.000000000 +0000 @@ -18,7 +18,7 @@ except ImportError: unit_parser = None -from default_renderer import DefaultRenderer +from .default_renderer import DefaultRenderer class UnitRenderer(DefaultRenderer): diff -Nru python-pyface-4.5.2/pyface/wx/spreadsheet/virtual_model.py python-pyface-6.1.2/pyface/wx/spreadsheet/virtual_model.py --- python-pyface-4.5.2/pyface/wx/spreadsheet/virtual_model.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/spreadsheet/virtual_model.py 2019-05-03 08:18:50.000000000 +0000 @@ -11,6 +11,7 @@ # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ +from __future__ import print_function from wx.grid import Grid, PyGridTableBase, GridCellAttr, GridTableMessage, GridCellFloatRenderer from wx.grid import GRIDTABLE_NOTIFY_ROWS_DELETED, GRIDTABLE_NOTIFY_ROWS_APPENDED from wx.grid import GRIDTABLE_NOTIFY_COLS_DELETED, GRIDTABLE_NOTIFY_COLS_APPENDED @@ -18,7 +19,7 @@ from wx.grid import GRID_VALUE_BOOL from wx import ALIGN_LEFT, ALIGN_CENTRE, Colour -from default_renderer import DefaultRenderer +from .default_renderer import DefaultRenderer class VirtualModel(PyGridTableBase): """ @@ -64,10 +65,10 @@ return self._data[row][1].get(self.GetColLabelValue(col), "") def SetValue(self, row, col, value): - print 'Setting value %d %d %s' % (row, col, value) - print 'Before ', self.GetValue(row, col) + print('Setting value %d %d %s' % (row, col, value)) + print('Before ', self.GetValue(row, col)) self._data[row][1][self.GetColLabelValue(col)] = value - print 'After ', self.GetValue(row, col) + print('After ', self.GetValue(row, col)) ''' def GetTypeName(self, row, col): if col == 2 or col == 6: @@ -134,7 +135,7 @@ grid.ProcessTableMessage(msg) def GetAttr88(self, row, col, someExtraParameter ): - print 'Overridden GetAttr ', row, col + print('Overridden GetAttr ', row, col) """Part of a workaround to avoid use of attributes, queried by _PropertyGrid's IsCurrentCellReadOnly""" #property = self.GetPropertyForCoordinate( row, col ) #object = self.GetObjectForCoordinate( row, col ) @@ -187,7 +188,7 @@ """ Append a tupe containing (name, data) """ name, data = row - print 'Appending ', name + print('Appending ', name) self._data.append(row) '''entry = {} for name in self.colnames: @@ -215,7 +216,7 @@ def DeleteRow(self, row): name, data = row - print 'Deleting ', name + print('Deleting ', name) self._data.remove(row) def DeleteRows88(self, rows): diff -Nru python-pyface-4.5.2/pyface/wx/switcher.py python-pyface-6.1.2/pyface/wx/switcher.py --- python-pyface-4.5.2/pyface/wx/switcher.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/switcher.py 2019-05-03 08:18:50.000000000 +0000 @@ -19,7 +19,7 @@ # Major package imports. import wx -from wx.lib.scrolledpanel import wxScrolledPanel +from wx.lib.scrolledpanel import ScrolledPanel as wxScrolledPanel # Enthought library imports. from traits.api import HasTraits diff -Nru python-pyface-4.5.2/pyface/wx/util/font_helper.py python-pyface-6.1.2/pyface/wx/util/font_helper.py --- python-pyface-4.5.2/pyface/wx/util/font_helper.py 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface/wx/util/font_helper.py 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,33 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: Enthought, Inc. +# Description: +#------------------------------------------------------------------------------ +""" Utility functions for working with wx Fonts. """ + + +# Major package imports. +import wx + + +def new_font_like(font, **kw): + """ Creates a new font, like another one, only different. Maybe. """ + + point_size = kw.get('point_size', font.GetPointSize()) + family = kw.get('family', font.GetFamily()) + style = kw.get('style', font.GetStyle()) + weight = kw.get('weight', font.GetWeight()) + underline = kw.get('underline', font.GetUnderlined()) + face_name = kw.get('face_name', font.GetFaceName()) + + return wx.Font(point_size, family, style, weight, underline, face_name) + +### EOF ####################################################################### diff -Nru python-pyface-4.5.2/pyface/xrc_dialog.py python-pyface-6.1.2/pyface/xrc_dialog.py --- python-pyface-4.5.2/pyface/xrc_dialog.py 2015-03-16 11:11:10.000000000 +0000 +++ python-pyface-6.1.2/pyface/xrc_dialog.py 2019-05-03 08:18:50.000000000 +0000 @@ -1,122 +1,17 @@ -#----------------------------------------------------------------------------- +# Copyright (c) 2017, Enthought, Inc. +# All rights reserved. # -# Copyright (c) 2005, Enthought, Inc. -# All rights reserved. -# -# Author: Scott Swarts -# -#----------------------------------------------------------------------------- - -"""A dialog that is loaded from an XRC resource file. -""" -from __future__ import absolute_import - -# Standard library imports. -import os.path - -# Major packages. -import wx -import wx.xrc - -# Enthought library imports -from traits.api import Instance, Str -import traits.util.resource - -# Local imports. -from .dialog import Dialog - - -############################################################################## -# class 'XrcDialog' -############################################################################## - -class XrcDialog(Dialog): - """A dialog that is loaded from an XRC resource file. - """ - - ########################################################################## - # Traits - ########################################################################## - - ### 'XrcDialog' interface ############################################ - - # Path to the xrc file relative to the class's module - xrc_file = Str - - # The ID of the dialog in the file - id = Str("dialog") - - # The resource object - resource = Instance(wx.xrc.XmlResource) - - ########################################################################## - # 'Dialog' interface - ########################################################################## - - def _create_control(self, parent): - """ - Creates the dialog and loads it in from the resource file. - """ - classpath = traits.util.resource.get_path( self ) - path = os.path.join( classpath, self.xrc_file ) - - self.resource = wx.xrc.XmlResource( path ) - return self.resource.LoadDialog(parent, self.id) - - def _create_contents(self, dialog): - """ - Calls add_handlers. The actual content is created - in _create_control by loading a resource file. - """ - # Wire up the standard buttons - # We change the ID on OK and CANCEL to the standard ids - # so we get the default behavior - okbutton = self.XRCCTRL("OK") - if okbutton is not None: - # Change the ID and set the handler - okbutton.SetId(wx.ID_OK) - wx.EVT_BUTTON(self.control, okbutton.GetId(), self._on_ok) - cancelbutton = self.XRCCTRL("CANCEL") - if cancelbutton is not None: - # Change the ID and set the handler - cancelbutton.SetId(wx.ID_CANCEL) - wx.EVT_BUTTON(self.control, cancelbutton.GetId(), self._on_cancel) - helpbutton = self.XRCCTRL("HELP") - if helpbutton is not None: - wx.EVT_BUTTON(self.control, helpbutton.GetId(), self._on_help) - - self._add_handlers() - - ########################################################################## - # 'XrcDialog' interface - ########################################################################## - - def XRCID(self, name): - """ - Returns the numeric widget id for the given name. - """ - return wx.xrc.XRCID(name) - - def XRCCTRL(self, name): - """ - Returns the control with the given name. - """ - return self.control.FindWindowById(self.XRCID(name)) - - def set_validator(self, name, validator): - """ - Sets the validator on the named control. - """ - self.XRCCTRL(name).SetValidator(validator) - - ########################################################################## - # 'XrcDialog' protected interface - ########################################################################## - - def _add_handlers(self): - """ - Override to add event handlers. - """ - return +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! + +import logging + +logger = logging.getLogger(__name__) +logger.warning( + 'DEPRECATED: pyface.xrc_dialog, use pyface.ui.wx.xrc_dialog instead. ' + 'Will be removed in Pyface 7.') -#### EOF ###################################################################### +from pyface.ui.wx.xrc_dialog import * diff -Nru python-pyface-4.5.2/pyface.egg-info/entry_points.txt python-pyface-6.1.2/pyface.egg-info/entry_points.txt --- python-pyface-4.5.2/pyface.egg-info/entry_points.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/pyface.egg-info/entry_points.txt 2019-07-22 09:15:04.000000000 +0000 @@ -0,0 +1,6 @@ +[pyface.toolkits] +null = pyface.ui.null.init:toolkit_object +qt = pyface.ui.qt4.init:toolkit_object +qt4 = pyface.ui.qt4.init:toolkit_object +wx = pyface.ui.wx.init:toolkit_object + diff -Nru python-pyface-4.5.2/pyface.egg-info/PKG-INFO python-pyface-6.1.2/pyface.egg-info/PKG-INFO --- python-pyface-4.5.2/pyface.egg-info/PKG-INFO 2015-08-14 15:55:52.000000000 +0000 +++ python-pyface-6.1.2/pyface.egg-info/PKG-INFO 2019-07-22 09:15:04.000000000 +0000 @@ -1,16 +1,27 @@ Metadata-Version: 1.1 Name: pyface -Version: 4.5.2 +Version: 6.1.2 Summary: traits-capable windowing framework -Home-page: https://docs.enthought.com/pyface +Home-page: http://docs.enthought.com/pyface Author: ETS Developers Author-email: enthought-dev@enthought.com License: BSD Download-URL: https://github.com/enthought/pyface +Description-Content-Type: UNKNOWN Description: ========================================== pyface: traits-capable windowing framework ========================================== + .. image:: https://travis-ci.org/enthought/pyface.svg?branch=master + :target: https://travis-ci.org/enthought/pyface + + .. image:: https://ci.appveyor.com/api/projects/status/68nfb049cdq9wqd1/branch/master?svg=true + :target: https://ci.appveyor.com/project/EnthoughtOSS/pyface/branch/master + + .. image:: https://codecov.io/github/enthought/pyface/coverage.svg?branch=master + :target: https://codecov.io/github/enthought/pyface?branch=master + + The pyface project contains a toolkit-independent GUI abstraction layer, which is used to support the "visualization" features of the Traits package. Thus, you can write code in terms of the Traits API (views, items, editors, @@ -23,8 +34,8 @@ - PyQt - PySide - **Warning:** In Pyface version 5.0 the default GUI backend will change from - ``wx`` to ``qt4``. + **Warning:** The default toolkit if none is supplied is ``qt4``. + This changed from ``wx`` in Pyface 5.0.. Documentation ------------- @@ -44,8 +55,7 @@ * Pygments for syntax highlighting in the Qt code editor widget. - * some widgets may have additional optional dependencies. For example, the - IPython shell widgets require IPython to be installed. + * some widgets may have additional optional dependencies. Platform: Windows Platform: Linux @@ -62,6 +72,10 @@ Classifier: Operating System :: POSIX Classifier: Operating System :: Unix Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 Classifier: Topic :: Scientific/Engineering Classifier: Topic :: Software Development Classifier: Topic :: Software Development :: Libraries diff -Nru python-pyface-4.5.2/pyface.egg-info/requires.txt python-pyface-6.1.2/pyface.egg-info/requires.txt --- python-pyface-4.5.2/pyface.egg-info/requires.txt 2015-08-14 15:55:52.000000000 +0000 +++ python-pyface-6.1.2/pyface.egg-info/requires.txt 2019-07-22 09:15:04.000000000 +0000 @@ -1,2 +1,17 @@ -pygments traits + +[pyqt] +pyqt>=4.10 +pygments + +[pyqt5] +pyqt>=5 +pygments + +[pyside] +pyside>=1.2 +pygments + +[wx] +wxpython>=2.8.10 +numpy diff -Nru python-pyface-4.5.2/pyface.egg-info/SOURCES.txt python-pyface-6.1.2/pyface.egg-info/SOURCES.txt --- python-pyface-4.5.2/pyface.egg-info/SOURCES.txt 2015-08-14 15:55:52.000000000 +0000 +++ python-pyface-6.1.2/pyface.egg-info/SOURCES.txt 2019-07-22 09:15:04.000000000 +0000 @@ -3,65 +3,368 @@ MANIFEST.in README.rst TODO.txt +appveyor-clean-cache.txt +ci-src-requirements.txt dev_requirements.txt +doc-src-requirements.txt image_LICENSE.txt image_LICENSE_Eclipse.txt image_LICENSE_Nuvola.txt image_LICENSE_OOo.txt setup.py +tox-requirements.txt docs/CHANGES.txt docs/DockWindow.ppt docs/DockWindowFeature.doc docs/DockWindowFeature.pdf docs/Makefile +docs/source/applications.rst +docs/source/changelog.rst docs/source/conf.py +docs/source/fields.rst docs/source/index.rst +docs/source/overview.rst +docs/source/submodules.rst +docs/source/timer.rst +docs/source/toolkits.rst docs/source/_static/default.css -docs/source/_static/e-logo-rev.png -docs/source/_static/et.ico +docs/source/_static/e-logo-rev.jpg +docs/source/_static/et.png docs/source/api/modules.rst +docs/source/api/pyface.about_dialog.rst +docs/source/api/pyface.action.action.rst +docs/source/api/pyface.action.action_controller.rst +docs/source/api/pyface.action.action_event.rst +docs/source/api/pyface.action.action_item.rst +docs/source/api/pyface.action.action_manager.rst +docs/source/api/pyface.action.action_manager_item.rst +docs/source/api/pyface.action.api.rst +docs/source/api/pyface.action.field_action.rst +docs/source/api/pyface.action.group.rst +docs/source/api/pyface.action.gui_application_action.rst +docs/source/api/pyface.action.listening_action.rst +docs/source/api/pyface.action.menu_bar_manager.rst +docs/source/api/pyface.action.menu_manager.rst docs/source/api/pyface.action.rst -docs/source/api/pyface.dock.rst -docs/source/api/pyface.grid.rst +docs/source/api/pyface.action.status_bar_manager.rst +docs/source/api/pyface.action.tests.rst +docs/source/api/pyface.action.tests.test_action.rst +docs/source/api/pyface.action.tests.test_action_controller.rst +docs/source/api/pyface.action.tests.test_action_event.rst +docs/source/api/pyface.action.tests.test_action_item.rst +docs/source/api/pyface.action.tests.test_action_manager.rst +docs/source/api/pyface.action.tests.test_field_action.rst +docs/source/api/pyface.action.tests.test_group.rst +docs/source/api/pyface.action.tests.test_gui_application_action.rst +docs/source/api/pyface.action.tests.test_listening_action.rst +docs/source/api/pyface.action.tests.test_traitsui_widget_action.rst +docs/source/api/pyface.action.tool_bar_manager.rst +docs/source/api/pyface.action.tool_palette_manager.rst +docs/source/api/pyface.action.traitsui_widget_action.rst +docs/source/api/pyface.action.window_action.rst +docs/source/api/pyface.api.rst +docs/source/api/pyface.application.rst +docs/source/api/pyface.application_window.rst +docs/source/api/pyface.base_toolkit.rst +docs/source/api/pyface.beep.rst +docs/source/api/pyface.clipboard.rst +docs/source/api/pyface.confirmation_dialog.rst +docs/source/api/pyface.constant.rst +docs/source/api/pyface.dialog.rst +docs/source/api/pyface.directory_dialog.rst +docs/source/api/pyface.drop_handler.rst +docs/source/api/pyface.expandable_header.rst +docs/source/api/pyface.expandable_panel.rst +docs/source/api/pyface.fields.api.rst +docs/source/api/pyface.fields.combo_field.rst +docs/source/api/pyface.fields.i_combo_field.rst +docs/source/api/pyface.fields.i_field.rst +docs/source/api/pyface.fields.i_spin_field.rst +docs/source/api/pyface.fields.i_text_field.rst +docs/source/api/pyface.fields.rst +docs/source/api/pyface.fields.spin_field.rst +docs/source/api/pyface.fields.tests.field_mixin.rst +docs/source/api/pyface.fields.tests.rst +docs/source/api/pyface.fields.tests.test_combo_field.rst +docs/source/api/pyface.fields.tests.test_spin_field.rst +docs/source/api/pyface.fields.tests.test_text_field.rst +docs/source/api/pyface.fields.text_field.rst +docs/source/api/pyface.file_dialog.rst +docs/source/api/pyface.filter.rst +docs/source/api/pyface.gui.rst +docs/source/api/pyface.gui_application.rst +docs/source/api/pyface.heading_text.rst +docs/source/api/pyface.i_about_dialog.rst +docs/source/api/pyface.i_application_window.rst +docs/source/api/pyface.i_clipboard.rst +docs/source/api/pyface.i_confirmation_dialog.rst +docs/source/api/pyface.i_dialog.rst +docs/source/api/pyface.i_directory_dialog.rst +docs/source/api/pyface.i_drop_handler.rst +docs/source/api/pyface.i_file_dialog.rst +docs/source/api/pyface.i_gui.rst +docs/source/api/pyface.i_heading_text.rst +docs/source/api/pyface.i_image_cache.rst +docs/source/api/pyface.i_image_resource.rst +docs/source/api/pyface.i_message_dialog.rst +docs/source/api/pyface.i_progress_dialog.rst +docs/source/api/pyface.i_python_editor.rst +docs/source/api/pyface.i_python_shell.rst +docs/source/api/pyface.i_single_choice_dialog.rst +docs/source/api/pyface.i_splash_screen.rst +docs/source/api/pyface.i_split_widget.rst +docs/source/api/pyface.i_system_metrics.rst +docs/source/api/pyface.i_widget.rst +docs/source/api/pyface.i_window.rst +docs/source/api/pyface.image.image.rst +docs/source/api/pyface.image.rst +docs/source/api/pyface.image_button.rst +docs/source/api/pyface.image_cache.rst +docs/source/api/pyface.image_list.rst +docs/source/api/pyface.image_resource.rst +docs/source/api/pyface.image_widget.rst +docs/source/api/pyface.ipython_widget.rst +docs/source/api/pyface.key_pressed_event.rst +docs/source/api/pyface.layered_panel.rst +docs/source/api/pyface.list_box.rst +docs/source/api/pyface.list_box_model.rst +docs/source/api/pyface.mdi_application_window.rst +docs/source/api/pyface.mdi_window_menu.rst +docs/source/api/pyface.message_dialog.rst +docs/source/api/pyface.mimedata.rst +docs/source/api/pyface.multi_toolbar_window.rst +docs/source/api/pyface.preference.api.rst +docs/source/api/pyface.preference.preference_dialog.rst +docs/source/api/pyface.preference.preference_node.rst +docs/source/api/pyface.preference.preference_page.rst docs/source/api/pyface.preference.rst -docs/source/api/pyface.qt.rst +docs/source/api/pyface.progress_dialog.rst +docs/source/api/pyface.python_editor.rst +docs/source/api/pyface.python_shell.rst +docs/source/api/pyface.resource.api.rst +docs/source/api/pyface.resource.resource_factory.rst +docs/source/api/pyface.resource.resource_manager.rst +docs/source/api/pyface.resource.resource_path.rst +docs/source/api/pyface.resource.resource_reference.rst docs/source/api/pyface.resource.rst +docs/source/api/pyface.resource_manager.rst docs/source/api/pyface.rst +docs/source/api/pyface.single_choice_dialog.rst +docs/source/api/pyface.sizers.flow.rst docs/source/api/pyface.sizers.rst +docs/source/api/pyface.sorter.rst +docs/source/api/pyface.splash_screen.rst +docs/source/api/pyface.splash_screen_log_handler.rst +docs/source/api/pyface.split_application_window.rst +docs/source/api/pyface.split_dialog.rst +docs/source/api/pyface.split_panel.rst +docs/source/api/pyface.split_widget.rst +docs/source/api/pyface.system_metrics.rst +docs/source/api/pyface.tasks.action.api.rst +docs/source/api/pyface.tasks.action.dock_pane_toggle_group.rst +docs/source/api/pyface.tasks.action.listening_action.rst docs/source/api/pyface.tasks.action.rst +docs/source/api/pyface.tasks.action.schema.rst +docs/source/api/pyface.tasks.action.schema_addition.rst +docs/source/api/pyface.tasks.action.task_action.rst +docs/source/api/pyface.tasks.action.task_action_controller.rst +docs/source/api/pyface.tasks.action.task_action_manager_builder.rst +docs/source/api/pyface.tasks.action.task_toggle_group.rst +docs/source/api/pyface.tasks.action.task_window_toggle_group.rst +docs/source/api/pyface.tasks.action.tasks_application_action.rst +docs/source/api/pyface.tasks.advanced_editor_area_pane.rst +docs/source/api/pyface.tasks.api.rst +docs/source/api/pyface.tasks.contrib.python_shell.rst docs/source/api/pyface.tasks.contrib.rst +docs/source/api/pyface.tasks.dock_pane.rst +docs/source/api/pyface.tasks.editor.rst +docs/source/api/pyface.tasks.editor_area_pane.rst +docs/source/api/pyface.tasks.enaml_dock_pane.rst +docs/source/api/pyface.tasks.enaml_editor.rst +docs/source/api/pyface.tasks.enaml_pane.rst +docs/source/api/pyface.tasks.enaml_task_pane.rst +docs/source/api/pyface.tasks.i_advanced_editor_area_pane.rst +docs/source/api/pyface.tasks.i_dock_pane.rst +docs/source/api/pyface.tasks.i_editor.rst +docs/source/api/pyface.tasks.i_editor_area_pane.rst +docs/source/api/pyface.tasks.i_task_pane.rst +docs/source/api/pyface.tasks.i_task_window_backend.rst docs/source/api/pyface.tasks.rst +docs/source/api/pyface.tasks.split_editor_area_pane.rst +docs/source/api/pyface.tasks.task.rst +docs/source/api/pyface.tasks.task_layout.rst +docs/source/api/pyface.tasks.task_pane.rst +docs/source/api/pyface.tasks.task_window.rst +docs/source/api/pyface.tasks.task_window_backend.rst +docs/source/api/pyface.tasks.task_window_layout.rst +docs/source/api/pyface.tasks.tasks_application.rst +docs/source/api/pyface.tasks.tests.rst +docs/source/api/pyface.tasks.tests.test_action_manager_builder.rst +docs/source/api/pyface.tasks.tests.test_dock_pane_toggle_group.rst +docs/source/api/pyface.tasks.tests.test_editor_area_pane.rst +docs/source/api/pyface.tasks.tests.test_enaml_dock_pane.rst +docs/source/api/pyface.tasks.tests.test_enaml_editor.rst +docs/source/api/pyface.tasks.tests.test_enaml_task_pane.rst +docs/source/api/pyface.tasks.tests.test_task_layout.rst +docs/source/api/pyface.tasks.tests.test_task_window.rst +docs/source/api/pyface.tasks.tests.test_tasks_application.rst +docs/source/api/pyface.tasks.tests.test_topological_sort.rst +docs/source/api/pyface.tasks.topological_sort.rst +docs/source/api/pyface.tasks.traits_dock_pane.rst +docs/source/api/pyface.tasks.traits_editor.rst +docs/source/api/pyface.tasks.traits_task_pane.rst +docs/source/api/pyface.tests.python_shell_script.rst docs/source/api/pyface.tests.rst +docs/source/api/pyface.tests.test_about_dialog.rst +docs/source/api/pyface.tests.test_application.rst +docs/source/api/pyface.tests.test_application_window.rst +docs/source/api/pyface.tests.test_base_toolkit.rst +docs/source/api/pyface.tests.test_beep.rst +docs/source/api/pyface.tests.test_clipboard.rst +docs/source/api/pyface.tests.test_confirmation_dialog.rst +docs/source/api/pyface.tests.test_dialog.rst +docs/source/api/pyface.tests.test_directory_dialog.rst +docs/source/api/pyface.tests.test_file_dialog.rst +docs/source/api/pyface.tests.test_gui_application.rst +docs/source/api/pyface.tests.test_heading_text.rst +docs/source/api/pyface.tests.test_image_cache.rst +docs/source/api/pyface.tests.test_image_resource.rst +docs/source/api/pyface.tests.test_message_dialog.rst +docs/source/api/pyface.tests.test_new_toolkit.init.rst +docs/source/api/pyface.tests.test_new_toolkit.rst +docs/source/api/pyface.tests.test_new_toolkit.widget.rst +docs/source/api/pyface.tests.test_progress_dialog.rst +docs/source/api/pyface.tests.test_python_editor.rst +docs/source/api/pyface.tests.test_python_shell.rst +docs/source/api/pyface.tests.test_resource_manager.rst +docs/source/api/pyface.tests.test_single_choice_dialog.rst +docs/source/api/pyface.tests.test_splash_screen.rst +docs/source/api/pyface.tests.test_splash_screen_log_handler.rst +docs/source/api/pyface.tests.test_split_application_window.rst +docs/source/api/pyface.tests.test_split_dialog.rst +docs/source/api/pyface.tests.test_split_panel.rst +docs/source/api/pyface.tests.test_system_metrics.rst +docs/source/api/pyface.tests.test_toolkit.rst +docs/source/api/pyface.tests.test_ui_traits.rst +docs/source/api/pyface.tests.test_widget.rst +docs/source/api/pyface.tests.test_window.rst +docs/source/api/pyface.timer.api.rst +docs/source/api/pyface.timer.do_later.rst +docs/source/api/pyface.timer.i_timer.rst docs/source/api/pyface.timer.rst +docs/source/api/pyface.timer.tests.rst +docs/source/api/pyface.timer.tests.test_timer.rst +docs/source/api/pyface.timer.timer.rst +docs/source/api/pyface.toolkit.rst +docs/source/api/pyface.tree.api.rst +docs/source/api/pyface.tree.node_event.rst +docs/source/api/pyface.tree.node_manager.rst +docs/source/api/pyface.tree.node_monitor.rst +docs/source/api/pyface.tree.node_tree.rst +docs/source/api/pyface.tree.node_tree_model.rst +docs/source/api/pyface.tree.node_type.rst docs/source/api/pyface.tree.rst -docs/source/api/pyface.ui.null.action.rst -docs/source/api/pyface.ui.null.rst -docs/source/api/pyface.ui.qt4.action.rst -docs/source/api/pyface.ui.qt4.code_editor.rst -docs/source/api/pyface.ui.qt4.console.rst -docs/source/api/pyface.ui.qt4.rst -docs/source/api/pyface.ui.qt4.tasks.rst -docs/source/api/pyface.ui.qt4.timer.rst -docs/source/api/pyface.ui.qt4.util.rst -docs/source/api/pyface.ui.qt4.wizard.rst -docs/source/api/pyface.ui.qt4.workbench.rst -docs/source/api/pyface.ui.rst -docs/source/api/pyface.ui.wx.action.rst -docs/source/api/pyface.ui.wx.grid.rst -docs/source/api/pyface.ui.wx.rst -docs/source/api/pyface.ui.wx.timer.rst -docs/source/api/pyface.ui.wx.wizard.rst -docs/source/api/pyface.ui.wx.workbench.rst +docs/source/api/pyface.tree.trait_dict_node_type.rst +docs/source/api/pyface.tree.trait_list_node_type.rst +docs/source/api/pyface.tree.tree.rst +docs/source/api/pyface.tree.tree_model.rst +docs/source/api/pyface.ui_traits.rst +docs/source/api/pyface.util.font_helper.rst +docs/source/api/pyface.util.grid.api.rst +docs/source/api/pyface.util.grid.grid.rst +docs/source/api/pyface.util.grid.grid_column.rst +docs/source/api/pyface.util.grid.grid_model.rst +docs/source/api/pyface.util.grid.grid_row.rst docs/source/api/pyface.util.grid.rst +docs/source/api/pyface.util.guisupport.rst +docs/source/api/pyface.util.id_helper.rst +docs/source/api/pyface.util.python_stc.rst docs/source/api/pyface.util.rst +docs/source/api/pyface.util.testing.rst docs/source/api/pyface.util.tests.rst +docs/source/api/pyface.util.tests.test_id_helper.rst +docs/source/api/pyface.viewer.api.rst +docs/source/api/pyface.viewer.column_provider.rst +docs/source/api/pyface.viewer.content_provider.rst +docs/source/api/pyface.viewer.content_viewer.rst +docs/source/api/pyface.viewer.default_tree_content_provider.rst +docs/source/api/pyface.viewer.label_provider.rst docs/source/api/pyface.viewer.rst +docs/source/api/pyface.viewer.table_column_provider.rst +docs/source/api/pyface.viewer.table_content_provider.rst +docs/source/api/pyface.viewer.table_label_provider.rst +docs/source/api/pyface.viewer.table_viewer.rst +docs/source/api/pyface.viewer.tree_content_provider.rst +docs/source/api/pyface.viewer.tree_item.rst +docs/source/api/pyface.viewer.tree_label_provider.rst +docs/source/api/pyface.viewer.tree_viewer.rst +docs/source/api/pyface.viewer.viewer.rst +docs/source/api/pyface.viewer.viewer_filter.rst +docs/source/api/pyface.viewer.viewer_sorter.rst +docs/source/api/pyface.widget.rst +docs/source/api/pyface.window.rst +docs/source/api/pyface.wizard.api.rst +docs/source/api/pyface.wizard.chained_wizard.rst +docs/source/api/pyface.wizard.chained_wizard_controller.rst +docs/source/api/pyface.wizard.i_wizard.rst +docs/source/api/pyface.wizard.i_wizard_controller.rst +docs/source/api/pyface.wizard.i_wizard_page.rst docs/source/api/pyface.wizard.rst +docs/source/api/pyface.wizard.simple_wizard.rst +docs/source/api/pyface.wizard.simple_wizard_controller.rst +docs/source/api/pyface.wizard.wizard.rst +docs/source/api/pyface.wizard.wizard_controller.rst +docs/source/api/pyface.wizard.wizard_page.rst +docs/source/api/pyface.workbench.action.action_controller.rst +docs/source/api/pyface.workbench.action.api.rst +docs/source/api/pyface.workbench.action.delete_user_perspective_action.rst +docs/source/api/pyface.workbench.action.menu_bar_manager.rst +docs/source/api/pyface.workbench.action.new_user_perspective_action.rst +docs/source/api/pyface.workbench.action.perspective_menu_manager.rst +docs/source/api/pyface.workbench.action.rename_user_perspective_action.rst +docs/source/api/pyface.workbench.action.reset_active_perspective_action.rst +docs/source/api/pyface.workbench.action.reset_all_perspectives_action.rst docs/source/api/pyface.workbench.action.rst +docs/source/api/pyface.workbench.action.save_as_user_perspective_action.rst +docs/source/api/pyface.workbench.action.set_active_perspective_action.rst +docs/source/api/pyface.workbench.action.setattr_action.rst +docs/source/api/pyface.workbench.action.show_view_action.rst +docs/source/api/pyface.workbench.action.toggle_view_visibility_action.rst +docs/source/api/pyface.workbench.action.tool_bar_manager.rst +docs/source/api/pyface.workbench.action.user_perspective_action.rst +docs/source/api/pyface.workbench.action.user_perspective_name.rst +docs/source/api/pyface.workbench.action.view_chooser.rst +docs/source/api/pyface.workbench.action.view_menu_manager.rst +docs/source/api/pyface.workbench.action.workbench_action.rst +docs/source/api/pyface.workbench.api.rst +docs/source/api/pyface.workbench.debug.api.rst +docs/source/api/pyface.workbench.debug.debug_view.rst docs/source/api/pyface.workbench.debug.rst +docs/source/api/pyface.workbench.editor.rst +docs/source/api/pyface.workbench.editor_manager.rst +docs/source/api/pyface.workbench.i_editor.rst +docs/source/api/pyface.workbench.i_editor_manager.rst +docs/source/api/pyface.workbench.i_perspective.rst +docs/source/api/pyface.workbench.i_perspective_item.rst +docs/source/api/pyface.workbench.i_view.rst +docs/source/api/pyface.workbench.i_workbench.rst +docs/source/api/pyface.workbench.i_workbench_part.rst +docs/source/api/pyface.workbench.i_workbench_window_layout.rst +docs/source/api/pyface.workbench.perspective.rst +docs/source/api/pyface.workbench.perspective_item.rst docs/source/api/pyface.workbench.rst -docs/source/api/pyface.wx.rst -docs/source/api/pyface.wx.spreadsheet.rst +docs/source/api/pyface.workbench.tests.rst +docs/source/api/pyface.workbench.tests.test_workbench_window.rst +docs/source/api/pyface.workbench.traits_ui_editor.rst +docs/source/api/pyface.workbench.traits_ui_view.rst +docs/source/api/pyface.workbench.user_perspective_manager.rst +docs/source/api/pyface.workbench.view.rst +docs/source/api/pyface.workbench.window_event.rst +docs/source/api/pyface.workbench.workbench.rst +docs/source/api/pyface.workbench.workbench_window.rst +docs/source/api/pyface.workbench.workbench_window_layout.rst +docs/source/api/pyface.workbench.workbench_window_memento.rst +docs/source/api/pyface.xrc_dialog.rst docs/source/sphinxext/__init__.py docs/source/sphinxext/refactordoc/AUTHORS.txt docs/source/sphinxext/refactordoc/CHANGELOG.txt @@ -87,6 +390,7 @@ examples/file_tree.py examples/file_tree_viewer.py examples/grid.py +examples/hello_world.py examples/image_widget.py examples/ipython_shell.py examples/mdi_application_window.py @@ -99,9 +403,26 @@ examples/splash_screen.py examples/timer.py examples/tool_palette.py +examples/traitsui_window.py examples/tree.py examples/tree_viewer.py examples/wizard.py +examples/application/hello_world/hello_application.py +examples/application/python_editor/python_browser_pane.py +examples/application/python_editor/python_editor.py +examples/application/python_editor/python_editor_application.py +examples/application/python_editor/python_editor_task.py +examples/application/python_editor/images/document_new.png +examples/application/python_editor/images/document_open.png +examples/application/python_editor/images/document_save.png +examples/application/python_editor/images/image_LICENSE.txt +examples/application/python_editor/images/python_icon.png +examples/application/python_editor/images/python_logo.png +examples/application/python_shell/python_shell_application.py +examples/application/python_shell/python_shell_window.py +examples/application/python_shell/images/image_LICENSE.txt +examples/application/python_shell/images/python_icon.png +examples/application/python_shell/images/python_logo.png examples/dock/dock_test.py examples/dock/dock_test2.py examples/dock/dock_test3.py @@ -120,6 +441,8 @@ examples/tasks/advanced/example_task.py examples/tasks/advanced/i_python_editor.py examples/tasks/advanced/python_editor.py +examples/tasks/advanced/python_editor_qt4.py +examples/tasks/advanced/python_editor_wx.py examples/tasks/advanced/run.py examples/tasks/advanced/images/document_new.png examples/tasks/advanced/images/document_open.png @@ -137,6 +460,17 @@ examples/tasks/enaml/enaml_panes.py examples/tasks/enaml/enaml_task.py examples/tasks/enaml/run.py +examples/tasks/steps/README.txt +examples/tasks/steps/mac-menubar-switching.py +examples/tasks/steps/step1.py +examples/tasks/steps/step2.py +examples/tasks/steps/step3.py +examples/tasks/steps/step4.py +examples/tasks/steps/step5.py +examples/tasks/steps/step6.py +examples/tasks/steps/step6a.py +examples/tasks/steps/step7.py +examples/tasks/steps/step8.py examples/workbench/black_view.py examples/workbench/blue_view.py examples/workbench/color_view.py @@ -153,7 +487,9 @@ pyface/_version.py pyface/about_dialog.py pyface/api.py +pyface/application.py pyface/application_window.py +pyface/base_toolkit.py pyface/beep.py pyface/clipboard.py pyface/confirmation_dialog.py @@ -166,6 +502,7 @@ pyface/file_dialog.py pyface/filter.py pyface/gui.py +pyface/gui_application.py pyface/heading_text.py pyface/i_about_dialog.py pyface/i_application_window.py @@ -183,6 +520,7 @@ pyface/i_progress_dialog.py pyface/i_python_editor.py pyface/i_python_shell.py +pyface/i_single_choice_dialog.py pyface/i_splash_screen.py pyface/i_split_widget.py pyface/i_system_metrics.py @@ -201,6 +539,7 @@ pyface/mdi_application_window.py pyface/mdi_window_menu.py pyface/message_dialog.py +pyface/mimedata.py pyface/multi_toolbar_window.py pyface/progress_dialog.py pyface/python_editor.py @@ -216,12 +555,14 @@ pyface/split_widget.py pyface/system_metrics.py pyface/toolkit.py +pyface/ui_traits.py pyface/widget.py pyface/window.py pyface/xrc_dialog.py pyface.egg-info/PKG-INFO pyface.egg-info/SOURCES.txt pyface.egg-info/dependency_links.txt +pyface.egg-info/entry_points.txt pyface.egg-info/not-zip-safe pyface.egg-info/requires.txt pyface.egg-info/top_level.txt @@ -233,12 +574,16 @@ pyface/action/action_manager.py pyface/action/action_manager_item.py pyface/action/api.py +pyface/action/field_action.py pyface/action/group.py +pyface/action/gui_application_action.py +pyface/action/listening_action.py pyface/action/menu_bar_manager.py pyface/action/menu_manager.py pyface/action/status_bar_manager.py pyface/action/tool_bar_manager.py pyface/action/tool_palette_manager.py +pyface/action/traitsui_widget_action.py pyface/action/window_action.py pyface/action/images/action.png pyface/action/images/image_LICENSE.txt @@ -248,7 +593,11 @@ pyface/action/tests/test_action_event.py pyface/action/tests/test_action_item.py pyface/action/tests/test_action_manager.py +pyface/action/tests/test_field_action.py pyface/action/tests/test_group.py +pyface/action/tests/test_gui_application_action.py +pyface/action/tests/test_listening_action.py +pyface/action/tests/test_traitsui_widget_action.py pyface/dock/__init__.py pyface/dock/api.py pyface/dock/dock_sizer.py @@ -285,6 +634,20 @@ pyface/dock/images/tab_scroll_lr.png pyface/dock/images/tab_scroll_r.png pyface/dock/images/window.png +pyface/fields/__init__.py +pyface/fields/api.py +pyface/fields/combo_field.py +pyface/fields/i_combo_field.py +pyface/fields/i_field.py +pyface/fields/i_spin_field.py +pyface/fields/i_text_field.py +pyface/fields/spin_field.py +pyface/fields/text_field.py +pyface/fields/tests/__init__.py +pyface/fields/tests/field_mixin.py +pyface/fields/tests/test_combo_field.py +pyface/fields/tests/test_spin_field.py +pyface/fields/tests/test_text_field.py pyface/grid/__init__.py pyface/grid/api.py pyface/grid/checkbox_image_renderer.py @@ -302,6 +665,11 @@ pyface/grid/simple_grid_model.py pyface/grid/trait_grid_cell_adapter.py pyface/grid/trait_grid_model.py +pyface/image/__init__.py +pyface/image/image.py +pyface/image/library/icons.zip +pyface/image/library/image_LICENSE.txt +pyface/image/library/std.zip pyface/images/about.jpg pyface/images/background.jpg pyface/images/carat_closed.png @@ -358,6 +726,7 @@ pyface/tasks/task_window.py pyface/tasks/task_window_backend.py pyface/tasks/task_window_layout.py +pyface/tasks/tasks_application.py pyface/tasks/topological_sort.py pyface/tasks/traits_dock_pane.py pyface/tasks/traits_editor.py @@ -372,8 +741,12 @@ pyface/tasks/action/task_action_controller.py pyface/tasks/action/task_action_manager_builder.py pyface/tasks/action/task_toggle_group.py +pyface/tasks/action/task_window_toggle_group.py +pyface/tasks/action/tasks_application_action.py +pyface/tasks/contrib/README.txt pyface/tasks/contrib/__init__.py pyface/tasks/contrib/python_shell.py +pyface/tasks/tests/__init__.py pyface/tasks/tests/test_action_manager_builder.py pyface/tasks/tests/test_dock_pane_toggle_group.py pyface/tasks/tests/test_editor_area_pane.py @@ -381,24 +754,31 @@ pyface/tasks/tests/test_enaml_editor.py pyface/tasks/tests/test_enaml_task_pane.py pyface/tasks/tests/test_task_layout.py +pyface/tasks/tests/test_task_window.py +pyface/tasks/tests/test_tasks_application.py pyface/tasks/tests/test_topological_sort.py pyface/tests/__init__.py pyface/tests/python_shell_script.py pyface/tests/test_about_dialog.py +pyface/tests/test_application.py pyface/tests/test_application_window.py +pyface/tests/test_base_toolkit.py pyface/tests/test_beep.py pyface/tests/test_clipboard.py pyface/tests/test_confirmation_dialog.py pyface/tests/test_dialog.py pyface/tests/test_directory_dialog.py pyface/tests/test_file_dialog.py +pyface/tests/test_gui_application.py pyface/tests/test_heading_text.py pyface/tests/test_image_cache.py +pyface/tests/test_image_resource.py pyface/tests/test_message_dialog.py pyface/tests/test_progress_dialog.py pyface/tests/test_python_editor.py pyface/tests/test_python_shell.py pyface/tests/test_resource_manager.py +pyface/tests/test_single_choice_dialog.py pyface/tests/test_splash_screen.py pyface/tests/test_splash_screen_log_handler.py pyface/tests/test_split_application_window.py @@ -406,14 +786,22 @@ pyface/tests/test_split_panel.py pyface/tests/test_system_metrics.py pyface/tests/test_toolkit.py +pyface/tests/test_ui_traits.py pyface/tests/test_widget.py pyface/tests/test_window.py pyface/tests/images/core.png pyface/tests/images/image_LICENSE.txt +pyface/tests/test_new_toolkit/__init__.py +pyface/tests/test_new_toolkit/init.py +pyface/tests/test_new_toolkit/widget.py pyface/timer/__init__.py pyface/timer/api.py pyface/timer/do_later.py +pyface/timer/i_timer.py pyface/timer/timer.py +pyface/timer/tests/__init__.py +pyface/timer/tests/test_do_later.py +pyface/timer/tests/test_timer.py pyface/tree/__init__.py pyface/tree/api.py pyface/tree/node_event.py @@ -463,10 +851,12 @@ pyface/ui/qt4/image_resource.py pyface/ui/qt4/init.py pyface/ui/qt4/message_dialog.py +pyface/ui/qt4/mimedata.py pyface/ui/qt4/progress_dialog.py pyface/ui/qt4/python_editor.py pyface/ui/qt4/python_shell.py pyface/ui/qt4/resource_manager.py +pyface/ui/qt4/single_choice_dialog.py pyface/ui/qt4/splash_screen.py pyface/ui/qt4/split_widget.py pyface/ui/qt4/system_metrics.py @@ -484,6 +874,8 @@ pyface/ui/qt4/code_editor/gutters.py pyface/ui/qt4/code_editor/pygments_highlighter.py pyface/ui/qt4/code_editor/replace_widget.py +pyface/ui/qt4/code_editor/tests/__init__.py +pyface/ui/qt4/code_editor/tests/test_code_widget.py pyface/ui/qt4/console/__init__.py pyface/ui/qt4/console/api.py pyface/ui/qt4/console/bracket_matcher.py @@ -491,6 +883,11 @@ pyface/ui/qt4/console/completion_lexer.py pyface/ui/qt4/console/console_widget.py pyface/ui/qt4/console/history_console_widget.py +pyface/ui/qt4/fields/__init__.py +pyface/ui/qt4/fields/combo_field.py +pyface/ui/qt4/fields/field.py +pyface/ui/qt4/fields/spin_field.py +pyface/ui/qt4/fields/text_field.py pyface/ui/qt4/images/application.png pyface/ui/qt4/images/heading_level_1.png pyface/ui/qt4/images/image_LICENSE.txt @@ -504,9 +901,14 @@ pyface/ui/qt4/tasks/task_pane.py pyface/ui/qt4/tasks/task_window_backend.py pyface/ui/qt4/tasks/util.py +pyface/ui/qt4/tasks/tests/__init__.py pyface/ui/qt4/tasks/tests/test_split_editor_area_pane.py pyface/ui/qt4/tests/__init__.py pyface/ui/qt4/tests/bad_import.py +pyface/ui/qt4/tests/test_gui.py +pyface/ui/qt4/tests/test_mimedata.py +pyface/ui/qt4/tests/test_progress_dialog.py +pyface/ui/qt4/tests/test_qt_imports.py pyface/ui/qt4/timer/__init__.py pyface/ui/qt4/timer/do_later.py pyface/ui/qt4/timer/timer.py @@ -516,6 +918,7 @@ pyface/ui/qt4/util/modal_dialog_tester.py pyface/ui/qt4/util/testing.py pyface/ui/qt4/util/tests/__init__.py +pyface/ui/qt4/util/tests/test_gui_test_assistant.py pyface/ui/qt4/util/tests/test_modal_dialog_tester.py pyface/ui/qt4/wizard/__init__.py pyface/ui/qt4/wizard/wizard.py @@ -526,6 +929,8 @@ pyface/ui/qt4/workbench/view.py pyface/ui/qt4/workbench/workbench_window_layout.py pyface/ui/qt4/workbench/images/spinner.gif +pyface/ui/qt4/workbench/tests/__init__.py +pyface/ui/qt4/workbench/tests/test_workbench_window_layout.py pyface/ui/wx/__init__.py pyface/ui/wx/about_dialog.py pyface/ui/wx/application_window.py @@ -534,23 +939,34 @@ pyface/ui/wx/confirmation_dialog.py pyface/ui/wx/dialog.py pyface/ui/wx/directory_dialog.py +pyface/ui/wx/expandable_header.py +pyface/ui/wx/expandable_panel.py pyface/ui/wx/file_dialog.py pyface/ui/wx/gui.py pyface/ui/wx/heading_text.py +pyface/ui/wx/image_button.py pyface/ui/wx/image_cache.py +pyface/ui/wx/image_list.py pyface/ui/wx/image_resource.py +pyface/ui/wx/image_widget.py pyface/ui/wx/init.py pyface/ui/wx/ipython_widget.py +pyface/ui/wx/layered_panel.py +pyface/ui/wx/list_box.py +pyface/ui/wx/mdi_application_window.py pyface/ui/wx/message_dialog.py +pyface/ui/wx/multi_toolbar_window.py pyface/ui/wx/progress_dialog.py pyface/ui/wx/python_editor.py pyface/ui/wx/python_shell.py pyface/ui/wx/resource_manager.py +pyface/ui/wx/single_choice_dialog.py pyface/ui/wx/splash_screen.py pyface/ui/wx/split_widget.py pyface/ui/wx/system_metrics.py pyface/ui/wx/widget.py pyface/ui/wx/window.py +pyface/ui/wx/xrc_dialog.py pyface/ui/wx/action/__init__.py pyface/ui/wx/action/action_item.py pyface/ui/wx/action/menu_bar_manager.py @@ -559,6 +975,11 @@ pyface/ui/wx/action/tool_bar_manager.py pyface/ui/wx/action/tool_palette.py pyface/ui/wx/action/tool_palette_manager.py +pyface/ui/wx/fields/__init__.py +pyface/ui/wx/fields/combo_field.py +pyface/ui/wx/fields/field.py +pyface/ui/wx/fields/spin_field.py +pyface/ui/wx/fields/text_field.py pyface/ui/wx/grid/__init__.py pyface/ui/wx/grid/api.py pyface/ui/wx/grid/checkbox_image_renderer.py @@ -581,17 +1002,34 @@ pyface/ui/wx/grid/images/image_not_found.png pyface/ui/wx/grid/images/table_edit.png pyface/ui/wx/grid/images/unchecked.png +pyface/ui/wx/grid/tests/__init__.py pyface/ui/wx/grid/tests/composite_grid_model_test_case.py pyface/ui/wx/grid/tests/simple_grid_model_test_case.py pyface/ui/wx/images/application.ico pyface/ui/wx/images/heading_level_1.png pyface/ui/wx/images/image_LICENSE.txt pyface/ui/wx/images/warning.png +pyface/ui/wx/preference/__init__.py +pyface/ui/wx/preference/preference_dialog.py +pyface/ui/wx/tasks/__init__.py +pyface/ui/wx/tasks/advanced_editor_area_pane.py +pyface/ui/wx/tasks/dock_pane.py +pyface/ui/wx/tasks/editor.py +pyface/ui/wx/tasks/editor_area_pane.py +pyface/ui/wx/tasks/main_window_layout.py +pyface/ui/wx/tasks/split_editor_area_pane.py +pyface/ui/wx/tasks/task_pane.py +pyface/ui/wx/tasks/task_window_backend.py pyface/ui/wx/tests/__init__.py pyface/ui/wx/tests/bad_import.py pyface/ui/wx/timer/__init__.py pyface/ui/wx/timer/do_later.py pyface/ui/wx/timer/timer.py +pyface/ui/wx/tree/__init__.py +pyface/ui/wx/tree/tree.py +pyface/ui/wx/viewer/__init__.py +pyface/ui/wx/viewer/table_viewer.py +pyface/ui/wx/viewer/tree_viewer.py pyface/ui/wx/wizard/__init__.py pyface/ui/wx/wizard/wizard.py pyface/ui/wx/wizard/wizard_page.py @@ -608,6 +1046,7 @@ pyface/util/guisupport.py pyface/util/id_helper.py pyface/util/python_stc.py +pyface/util/testing.py pyface/util/grid/__init__.py pyface/util/grid/api.py pyface/util/grid/grid.py @@ -693,7 +1132,10 @@ pyface/workbench/debug/__init__.py pyface/workbench/debug/api.py pyface/workbench/debug/debug_view.py +pyface/workbench/tests/__init__.py +pyface/workbench/tests/test_workbench_window.py pyface/wx/__init__.py +pyface/wx/aui.py pyface/wx/clipboard.py pyface/wx/color.py pyface/wx/dialog.py @@ -706,14 +1148,23 @@ pyface/wx/lazy_switcher.py pyface/wx/pager.py pyface/wx/progress_meter.py +pyface/wx/python_stc.py pyface/wx/scrolled_message_dialog.py pyface/wx/shell.py pyface/wx/sized_panel.py pyface/wx/spacer.py pyface/wx/switcher.py +pyface/wx/grid/__init__.py +pyface/wx/grid/api.py +pyface/wx/grid/grid.py +pyface/wx/grid/grid_column.py +pyface/wx/grid/grid_model.py +pyface/wx/grid/grid_row.py pyface/wx/spreadsheet/__init__.py pyface/wx/spreadsheet/abstract_grid_view.py pyface/wx/spreadsheet/default_renderer.py pyface/wx/spreadsheet/font_renderer.py pyface/wx/spreadsheet/unit_renderer.py -pyface/wx/spreadsheet/virtual_model.py \ No newline at end of file +pyface/wx/spreadsheet/virtual_model.py +pyface/wx/util/__init__.py +pyface/wx/util/font_helper.py \ No newline at end of file diff -Nru python-pyface-4.5.2/README.rst python-pyface-6.1.2/README.rst --- python-pyface-4.5.2/README.rst 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/README.rst 2019-05-03 08:18:49.000000000 +0000 @@ -2,6 +2,16 @@ pyface: traits-capable windowing framework ========================================== +.. image:: https://travis-ci.org/enthought/pyface.svg?branch=master + :target: https://travis-ci.org/enthought/pyface + +.. image:: https://ci.appveyor.com/api/projects/status/68nfb049cdq9wqd1/branch/master?svg=true + :target: https://ci.appveyor.com/project/EnthoughtOSS/pyface/branch/master + +.. image:: https://codecov.io/github/enthought/pyface/coverage.svg?branch=master + :target: https://codecov.io/github/enthought/pyface?branch=master + + The pyface project contains a toolkit-independent GUI abstraction layer, which is used to support the "visualization" features of the Traits package. Thus, you can write code in terms of the Traits API (views, items, editors, @@ -14,8 +24,8 @@ - PyQt - PySide -**Warning:** In Pyface version 5.0 the default GUI backend will change from -``wx`` to ``qt4``. +**Warning:** The default toolkit if none is supplied is ``qt4``. + This changed from ``wx`` in Pyface 5.0.. Documentation ------------- @@ -35,5 +45,4 @@ * Pygments for syntax highlighting in the Qt code editor widget. -* some widgets may have additional optional dependencies. For example, the - IPython shell widgets require IPython to be installed. +* some widgets may have additional optional dependencies. diff -Nru python-pyface-4.5.2/setup.cfg python-pyface-6.1.2/setup.cfg --- python-pyface-4.5.2/setup.cfg 2015-08-14 15:55:52.000000000 +0000 +++ python-pyface-6.1.2/setup.cfg 2019-07-22 09:15:12.000000000 +0000 @@ -1,5 +1,4 @@ [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -Nru python-pyface-4.5.2/setup.py python-pyface-6.1.2/setup.py --- python-pyface-4.5.2/setup.py 2015-08-14 15:30:01.000000000 +0000 +++ python-pyface-6.1.2/setup.py 2019-07-21 09:29:00.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2008-2014 by Enthought, Inc. +# Copyright (c) 2008-2015 by Enthought, Inc. # All rights reserved. import os @@ -7,8 +7,8 @@ from setuptools import setup, find_packages -MAJOR = 4 -MINOR = 5 +MAJOR = 6 +MINOR = 1 MICRO = 2 IS_RELEASED = True @@ -16,6 +16,25 @@ VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO) +def read_module(module, package='pyface'): + """ Read a simple .py file from pyface in a safe way. + + It would be simpler to import the file, but that can be problematic in an + unknown system, so we exec the file instead and extract the variables. + + This will fail if things get too complex in the file being read, but is + sufficient to get version and requirements information. + """ + base_dir = os.path.dirname(__file__) + module_name = package + '.' + module + path = os.path.join(base_dir, package, module+'.py') + with open(path, 'r') as fp: + code = compile(fp.read(), module_name, 'exec') + context = {} + exec(code, context) + return context + + # Return the git revision as a string def git_version(): def _minimal_ext_cmd(cmd): @@ -70,14 +89,15 @@ elif os.path.exists('pyface/_version.py'): # must be a source distribution, use existing version file try: - from pyface._version import git_revision as git_rev - from pyface._version import full_version as full_v + data = read_module('_version') + git_rev = data['git_revision'] + fullversion_source = data['full_version'] except ImportError: - raise ImportError("Unable to import git_revision. Try removing " + raise ImportError("Unable to read git_revision. Try removing " "pyface/_version.py and the build directory " "before building.") - match = re.match(r'.*?\.dev(?P\d+)', full_v) + match = re.match(r'.*?\.dev(?P\d+)', fullversion_source) if match is None: dev_num = '0' else: @@ -95,13 +115,18 @@ git_revision=git_rev, is_released=IS_RELEASED)) + return fullversion + + if __name__ == "__main__": - write_version_py() - from pyface import __version__, __requires__ + __version__ = write_version_py() + data = read_module('__init__') + __requires__ = data['__requires__'] + __extras_require__ = data['__extras_require__'] setup(name='pyface', version=__version__, - url='https://docs.enthought.com/pyface', + url='http://docs.enthought.com/pyface', author='David C. Morrill, et al.', author_email='dmorrill@enthought.com', classifiers=[c.strip() for c in """\ @@ -115,27 +140,42 @@ Operating System :: POSIX Operating System :: Unix Programming Language :: Python + Programming Language :: Python :: 2.7 + Programming Language :: Python :: 3.4 + Programming Language :: Python :: 3.5 + Programming Language :: Python :: 3.6 Topic :: Scientific/Engineering Topic :: Software Development Topic :: Software Development :: Libraries """.splitlines() if len(c.split()) > 0], description='traits-capable windowing framework', long_description=open('README.rst').read(), - download_url=('https://github.com/enthought/pyface'), + download_url='https://github.com/enthought/pyface', install_requires=__requires__, + extras_require=__extras_require__, license='BSD', maintainer='ETS Developers', maintainer_email='enthought-dev@enthought.com', package_data={'': [ + 'image/library/*.zip', 'images/*', 'action/images/*', 'dock/images/*', 'tree/images/*', + 'tests/images/*', 'ui/qt4/images/*', 'ui/wx/images/*', 'ui/wx/grid/images/*', ]}, packages=find_packages(), + entry_points = { + 'pyface.toolkits': [ + 'qt4 = pyface.ui.qt4.init:toolkit_object', + 'qt = pyface.ui.qt4.init:toolkit_object', + 'wx = pyface.ui.wx.init:toolkit_object', + 'null = pyface.ui.null.init:toolkit_object', + ], + }, platforms=["Windows", "Linux", "Mac OS-X", "Unix", "Solaris"], zip_safe=False, - ) + ) diff -Nru python-pyface-4.5.2/tox-requirements.txt python-pyface-6.1.2/tox-requirements.txt --- python-pyface-4.5.2/tox-requirements.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-pyface-6.1.2/tox-requirements.txt 2019-05-03 08:18:50.000000000 +0000 @@ -0,0 +1,8 @@ +mock +nose +numpy +pygments +traits +git+http://github.com/enthought/traitsui.git#egg=traitsui +traits_enaml ; python_version == '2.7' +enaml ; python_version == '2.7'