File: workbench_application.py

package info (click to toggle)
python-envisageplugins 3.1.2-1
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 1,616 kB
  • ctags: 1,970
  • sloc: python: 7,047; makefile: 11; sh: 11; lisp: 1
file content (190 lines) | stat: -rw-r--r-- 6,313 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
""" The entry point for an Envisage Workbench application. """


# Standard library imports.
import logging

# Enthought library imports.
#
# fixme: The ordering of these imports is critical. We don't use traits UI in
# this module, but it must be imported *before* any 'HasTraits' class whose
# instances might want to have 'edit_traits' called on them.
#
# fixme: Just importing the package is enought (see above).
import enthought.traits.ui

# Enthought library imports.
from enthought.envisage.api import Application
from enthought.pyface.api import AboutDialog, Dialog, GUI, ImageResource
from enthought.pyface.api import SplashScreen
from enthought.pyface.workbench.api import IWorkbench
from enthought.traits.api import Callable, Instance, Str, Tuple

# Local imports.
from workbench import Workbench


# Logging.
logger = logging.getLogger(__name__)


class WorkbenchApplication(Application):
    """ The entry point for an Envisage Workbench application.

    i.e. a GUI application whose user interface is provided by the workbench
    plugin.

    This class handles the common case for Workbench applications, and it is
    intended to be subclassed to change start/stop behaviour etc. In fact, I
    generally create a subclass for every Workbench application I write since
    it is a good place to put branding information etc.

    """

    #### 'WorkbenchApplication' interface #####################################

    # The PyFace GUI for the application (this is here to make it easy for
    # parts of the application to get a reference to the GUI so they can get
    # system metrics, etc.
    gui = Instance(GUI)
    
    # The workbench.
    workbench = Instance(IWorkbench)

    # The factory for creating the workbench (used *instead* of providing a
    # workbench explicitly).
    workbench_factory = Callable(Workbench)

    # Branding information.
    #
    # The 'About' dialog.
    about_dialog = Instance(Dialog)
    
    # The icon used on window title bars etc.
    icon = Instance(ImageResource, ImageResource('application.ico'))
    
    # The name of the application (also used on window title bars etc).
    name = Str('Workbench')
    
    # The splash screen (None, the default, if no splash screen is required).
    splash_screen = Instance(SplashScreen)

    # The default position of the main window.
    window_position = Tuple((200, 200))
    
    # The default size of the main window.
    window_size = Tuple((800, 600))

    ###########################################################################
    # 'IApplication' interface.
    ###########################################################################

    def run(self):
        """ Run the application.

        This does the following (so you don't have to ;^):-

        1) Starts the application
        2) Creates and opens a workbench window
        3) Starts the GUI event loop
        4) When the event loop terminates, stops the application

        """

        logger.debug('---------- workbench application ----------')

        # Make sure the GUI has been created (so that, if required, the splash
        # screen is shown).
        gui = self.gui
        
        # Start the application.
        if self.start():
            # Create and open the first workbench window.
            window = self.workbench.create_window(
                position=self.window_position, size=self.window_size
            )
            window.open()

            # We stop the application when the workbench has exited.
            self.workbench.on_trait_change(self._on_workbench_exited, 'exited')
            
            # Start the GUI event loop.
            #
            # THIS CALL DOES NOT RETURN UNTIL THE GUI IS CLOSED.
            gui.start_event_loop()
        
        return
        
    ###########################################################################
    # 'WorkbenchApplication' interface.
    ###########################################################################

    #### Initializers #########################################################

    def _about_dialog_default(self):
        """ Trait initializer. """

        return AboutDialog(image=ImageResource('about'))
    
    def _gui_default(self):
        """ Trait initializer. """

        return GUI(splash_screen=self.splash_screen)

    def _workbench_default(self):
        """ Trait initializer. """

        return self.create_workbench()
    
    #### Methods ##############################################################

    def about(self):
        """ Display the about dialog. """

        # fixme: We really need to create a new 'about dialog' every time so
        # that it can have the active window as its parent.
        self.about_dialog.open()

        return

    # fixme: Is this needed on the public API? Why can't we just do this in
    # the default initializer (_workbench_default)?
    def create_workbench(self):
        """ Create the workbench. """

        logger.debug('workbench factory %s', self.workbench_factory)

        return self.workbench_factory(application=self)

    def exit(self):
        """ Exit the application.

        This closes all open windows and hence exits the GUI event loop.

        """

        self.workbench.exit()

        return

    ###########################################################################
    # Private interface.
    ###########################################################################

    def _on_workbench_exited(self):
        """ Dynamic trait change handler. """

        # We don't invoke 'stop' directly because:-
        #
        # The workbench is often exited via a user action (either by closing
        # the last open window, or by choosing 'File/Exit'). If this happens
        # then the workbench 'exit' method is called from within an event
        # handler which would cause the 'stop' method to get called *before*
        # the handling of the window 'closed' event is complete. Hance, this
        # might mean that somebody listening for the window being closed would
        # get the event *after* the application had already stopped!
        self.gui.invoke_later(self.stop)

        return
        
#### EOF ######################################################################