Source code for envisage.ui.workbench.workbench_application
# (C) Copyright 2007-2024 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in 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!
""" The entry point for an Envisage Workbench application. """
# Standard library imports.
import logging
from pyface.api import AboutDialog, Dialog, GUI, ImageResource, SplashScreen
from pyface.workbench.api import IWorkbench
from traits.api import Callable, Instance, Str, Tuple
# Enthought library imports.
from envisage.api import Application
# Local imports.
from .workbench import Workbench
# Logging.
logger = logging.getLogger(__name__)
[docs]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.
###########################################################################
[docs] 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()
###########################################################################
# '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 ##############################################################
[docs] 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()
# fixme: Is this needed on the public API? Why can't we just do this in
# the default initializer (_workbench_default)?
[docs] def create_workbench(self):
"""Create the workbench."""
logger.debug("workbench factory %s", self.workbench_factory)
return self.workbench_factory(application=self)
[docs] def exit(self):
"""Exit the application.
This closes all open windows and hence exits the GUI event loop.
"""
self.workbench.exit()
###########################################################################
# 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)