Logo Search packages:      
Sourcecode: mayavi2 version File versions  Download package

workbench.py

00001 """ The Envisage workbench. """


# Standard library imports.
import logging
import os

# Enthought library imports.
from enthought.envisage.api import Application, Preferences
from enthought.envisage.resource.api import ResourceManager
from enthought.pyface.api import ImageResource
from enthought.pyface.api import confirm, YES
from enthought.traits.api import Bool, Event, HasTraits, Instance, List
from enthought.traits.api import Property, Str, Tuple, Vetoable, VetoableEvent

# Local imports.
from branding import Branding
from perspective import Perspective
from user_perspective import UserPerspective
from view import View
from window import Window
from window_factory import WindowFactory


# Setup a logger for this module.
logger=logging.getLogger(__name__)


00029 class WindowEvent(HasTraits):
    """ A window lifecycle event. """

    #### 'WindowEvent' interface ##############################################

    # The window that the event occurred on.
    window = Instance(Window)


00038 class VetoableWindowEvent(WindowEvent, Vetoable):
    """ A vetoable window lifecycle event. """

    pass


00044 class Workbench(HasTraits):
    """ The Envisage workbench.

    There is exactly *one* workbench per application. The workbench can create
    any number of workbench windows.

    """

    #### 'Workbench' interface ################################################

    # Application branding information.
    branding = Instance(Branding)

    # The active workbench window (the last one to get focus).
    active_window = Instance(Window)

    # The Envisage application that the workbench is part of.
    application = Instance(Application)

    # The Id of the default perspective.
    default_perspective_id = Str

    # The perspectives available in the workbench.
    perspectives = List(Perspective)

    # The user defined perspectives manager:
    user_perspective = Instance(UserPerspective)

    # User preferences.
    #
    # fixme: We don't really want a preference object on the workbench itself,
    # but how else could preference pages etc. find them?!?
    preferences = Instance(Preferences)

    # Should we prompt the user when they attempt to close the last open window
    # (and hence exit the application!). This helps prevent the user from
    # exiting the application accidentally. However, we *never* prompt if the
    # user exits the workbench by choosing the 'Exit' action on the 'File'
    # menu.
    #
    # fixme: Shouldn't this be on the workbench UI?
    prompt_on_exit = Bool(True)

    # The resource manager used by the workbench. The resource manager is used
    # to find editors, etc.
    resource_manager = Instance(ResourceManager, ())

    # Should tool names be shown on tool bar tools?
    show_tool_names = Bool(False)

    # A directory on the local file system that we can read and write to at
    # will. This is used to persist window layout information, etc.
    state_location = Str

    # The views available in the workbench (note that this is *all* of the
    # views, not just those currently visible).
    views = List(View)

    # All of the workbench windows created by the workbench.
    windows = List(Window)

    # The initial position of each workbench window.
    window_position = Tuple((100, 100))

    # The initial size of each workbench window.
    window_size = Tuple((800, 600))

    #### Workbench lifecycle events ####

    # Fired when the workbench is about to exit.
    #
    # This can be caused by either:-
    #
    # a) The 'exit' method being called.
    # b) The last open window being closed.
    #
    exiting = VetoableEvent

    # Fired when the workbench has exited.
    exited = Event

    #### Window lifecycle events ####

    # Fired when a workbench window has been created.
    window_created = Event(WindowEvent)

    # Fired when a workbench window is opening.
    window_opening = Event(VetoableWindowEvent)

    # Fired when a workbench window has been opened.
    window_opened = Event(WindowEvent)

    # Fired when a workbench window is closing.
    window_closing = Event(VetoableWindowEvent)

    # Fired when a workbench window has been closed.
    window_closed = Event(WindowEvent)

    #### Private interface ####################################################

    # Is the workbench in the process of exiting?
    _exiting = Bool(False)

    ###########################################################################
    # 'object' interface.
    ###########################################################################

00151     def __init__(self, application, **traits):
        """ Creates a new workbench. """

        # Super class constructor.
        super(Workbench, self).__init__(application=application, **traits)

        return

    ###########################################################################
    # 'Workbench' interface.
    ###########################################################################

00163     def create_window(self):
        """ Factory method that creates a new workbench window.

        This does *not* open the window. To do that, call its 'open' method.

        """

        window = WindowFactory().create_window(self)

        # Listen for the window being activated/opened/closed etc. Activated in
        # this context means 'gets the focus'.
        #
        # NOTE: 'activated' is not fired on a window when the window first
        # opens and gets focus. It is only fired when the window comes from
        # lower in the stack to be the active window.
        window.on_trait_change(self._on_window_activated, 'activated')
        window.on_trait_change(self._on_window_opening, 'opening')
        window.on_trait_change(self._on_window_opened, 'opened')
        window.on_trait_change(self._on_window_closing, 'closing')
        window.on_trait_change(self._on_window_closed, 'closed')

        # Event notification.
        self.window_created = WindowEvent(window=window)

        return window

00189     def exit(self):
        """ Exits the workbench.

        This closes all open workbench windows.

        This method is not called when the user clicks the close icon. Nor when
        they do an Alt+F4 in Windows. It is only called when the application
        menu File->Exit item is selected.

        """

        logger.debug('**** exiting the workbench ****')

        # Event notification.
        self.exiting = event = Vetoable()
        if not event.veto:
            # The active window (i.e., the window that had the focus at the
            # time of of the exit).
            active_window = self.active_window

            # This flag is checked in '_on_window_closing' to see if the window
            # is being closed either programmatically (by this method), or
            # manually (by the user).
            self._exiting = True

            # Close all windows.
            if self._close_all_windows():
                # Save the window size, position and layout.
                self._save_window_layout(active_window)

                # Event notification.
                self.exited = self

            # Whether the exit succeeded or not, we are no longer in the
            # process of exiting.
            self._exiting = False

        else:
            logger.debug('workbench exit vetoed')

        return

    # Convenience methods on the active window.
00232     def edit(self, resource, use_existing=True):
        """ Edits a resource.

        If 'use_existing' is True and the resource is already being edited in
        the active workbench window then the existing editor will be activated
        (i.e., given focus, brought to the front, etc.).

        If 'use_existing' is False, then a new editor will be created even if
        one already exists.

        """

        return self.active_window.edit(resource, use_existing)

00246     def get_editor_by_id(self, id):
        """ Returns the editor with the specified Id.

        Returns None if no such editor exists.

        """

        return self.active_window.get_editor_by_id(id)

00255     def get_editor_by_resource(self, resource):
        """ Returns the editor that is editing a resource.

        Returns None if no such editor exists.

        """

        return self.active_window.get_editor_by_resource(resource)

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

00268     def _can_exit(self, window):
        """ Is an 'implicit exit' allowed?

        An 'implicit exit' is performed when the user attempts to close the
        last open window.

        Returns True if the exit is allowed (i.e., nobody vetoed it).

        """

        logger.debug('firing exiting event')

        self.exiting = event = Vetoable()
        if event.veto:
            can_exit = False

        else:
            can_exit = self._confirm_exit(window)

        return can_exit

00289     def _confirm_exit(self, window):
        """ Returns True if it is OK to exit the application. """

        if self.prompt_on_exit:
            answer = confirm(
                window.control, "Exit %s?" % window.title, "Confirm Exit"
            )
            can_exit = answer == YES

        else:
            can_exit = True

        return can_exit

00303     def _close_all_windows(self):
        """ Closes all open windows.

        Returns True if all windows were closed, False if the user changed
        their mind ;^)

        """

        # We take a copy of the windows list because as windows are closed
        # they are removed from it!
        windows = self.windows[:]
        windows.reverse()

        for window in windows:
            # We give the user chance to cancel the exit as each window is
            # closed.
            if not window.close():
                all_closed = False
                break

        else:
            all_closed = True

        return all_closed

00328     def _save_window_layout(self, window):
        """ Saves the window size, position and layout. """

        # Note the size and the position of the window (these values get
        # saved as user preferences).
        self.window_size = window.size
        self.window_position = window.position

        # Save the window layout.
        window.save_layout()

        return

    #### Trait change handlers ################################################

00343     def _on_window_activated(self, window, trait_name, event):
        """ Dynamic trait change handler. """

        logger.debug('window [%s] activated', window)

        self.active_window = window

        return

00352     def _on_window_opening(self, window, trait_name, event):
        """ Dynamic trait change handler. """

        logger.debug('window [%s] opening', window)

        # Event notification.
        self.window_opening = window_event = VetoableWindowEvent(window=window)
        if window_event.veto:
            event.veto = True

        return

00364     def _on_window_opened(self, window, trait_name, event):
        """ Dynamic trait change handler. """

        logger.debug('window [%s] opened', window)

        # We maintain a list of all open windows so that (amongst other things)
        # we can detect when the user is attempting to close the last one.
        self.windows.append(window)

        # This is necessary because the activated event is not fired when a
        # window is first opened and gets focus.  It is only fired when the
        # window comes from lower in the stack to be the active window.
        self.active_window = window

        # Event notification.
        self.window_opened = WindowEvent(window=window)

        return

00383     def _on_window_closing(self, window, trait_name, event):
        """ Dynamic trait change handler. """

        logger.debug('window [%s] closing', window)

        # Is the user performing an 'implicit exit' by attempting to close the
        # last open window?
        if not self._exiting and len(self.windows) == 1:
            can_close = self._can_exit(window)
            if can_close:
                # Save the window size, position and layout.
                self._save_window_layout(window)

        else:
            can_close = True

        if can_close:
            # Event notification.
            window_event        = VetoableWindowEvent(window=window)
            self.window_closing = window_event

            if window_event.veto:
                event.veto = True

        else:
            event.veto = True

        return

00412     def _on_window_closed(self, window, trait_name, event):
        """ Dynamic trait change handler. """

        logger.debug('window [%s] closed', window)

        self.windows.remove(window)

        # Event notification.
        self.window_closed = WindowEvent(window=window)

        return

#### EOF ######################################################################

Generated by  Doxygen 1.6.0   Back to index