Esempio n. 1
0
class IEditor(IWorkbenchPart):
    """ The interface of a workbench editor. """

    # The optional command stack.
    command_stack = Instance("apptools.undo.api.ICommandStack")

    # Is the object that the editor is editing 'dirty' i.e., has it been
    # modified but not saved?
    dirty = Bool(False)

    # The object that the editor is editing.
    #
    # The framework sets this when the editor is created.
    obj = Any()

    # Editor Lifecycle Events ---------------------------------------------#

    # Fired when the editor is closing.
    closing = VetoableEvent()

    # Fired when the editor is closed.
    closed = Event()

    # Methods -------------------------------------------------------------#

    def close(self):
        """ Close the editor.
Esempio n. 2
0
class IApplication(
    IExtensionRegistry, IImportManager, IPluginManager, IServiceRegistry
):
    """ The application interface. """

    #: The application's globally unique identifier.
    id = Str

    #: The name of a directory (created for you) to which the application can
    #: read and write non-user accessible data, i.e. configuration information,
    #: preferences, etc.
    home = Str

    #: The name of a directory (created for you upon access) to which the
    #: application can read and write user-accessible data, e.g. projects
    #: created by the user.
    user_data = Str

    #: The root preferences node.
    preferences = Instance(IPreferences)

    #### Events ####

    #: Fired when the application is starting. This is the first thing that
    #: happens when the 'start' method is called.
    starting = VetoableEvent(ApplicationEvent)

    #: Fired when all plugins have been started.
    started = Event(ApplicationEvent)

    #: Fired when the plugin manager is stopping. This is the first thing that
    #: happens when the 'stop' method is called.
    stopping = VetoableEvent(ApplicationEvent)

    #: Fired when all plugins have been stopped.
    stopped = Event(ApplicationEvent)

    def run(self):
        """ Run the application.
Esempio n. 3
0
class IEditor(Interface):
    """ The base interface for all panes (central and dock) in a Task.
    """

    #: The editor's user-visible name.
    name = Str()

    #: The tooltip to show for the editor's tab, if any.
    tooltip = Str()

    #: The toolkit-specific control that represents the editor.
    control = Any()

    #: The object that the editor is editing.
    obj = Any()

    #: Has the editor's object been modified but not saved?
    dirty = Bool()

    #: 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_active = Bool()

    #: Does the editor currently have the focus?
    has_focus = Bool()

    #: Fired when the editor has been requested to close.
    closing = VetoableEvent()

    #: Fired when the editor has been closed.
    closed = Event()

    # ------------------------------------------------------------------------
    # 'IEditor' interface.
    # ------------------------------------------------------------------------

    def close(self):
        """ Close the editor.
        """

    def create(self, parent):
        """ Create and set the toolkit-specific control that represents the
            editor.
        """

    def destroy(self):
        """ Destroy the toolkit-specific control that represents the editor.
Esempio n. 4
0
class MEditor(HasTraits):
    """ Mixin containing common code for toolkit-specific implementations.
    """

    # 'IEditor' interface -------------------------------------------------#

    name = Str()
    tooltip = Str()
    control = Any()
    obj = Any()
    dirty = Bool(False)

    editor_area = Instance("pyface.tasks.i_editor_area_pane.IEditorAreaPane")
    is_active = Property(Bool, observe="editor_area.active_editor")
    has_focus = Bool(False)

    closing = VetoableEvent()
    closed = Event()

    # ------------------------------------------------------------------------
    # 'IEditor' interface.
    # ------------------------------------------------------------------------

    def close(self):
        """ Close the editor.
        """
        if self.control is not None:
            self.closing = event = Vetoable()
            if not event.veto:
                self.editor_area.remove_editor(self)
                self.closed = True

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

    @cached_property
    def _get_is_active(self):
        if self.editor_area is not None:
            return self.editor_area.active_editor == self
        return False
Esempio n. 5
0
class Workbench(HasTraits):
    """ A workbench.

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

    """

    # 'IWorkbench' interface -----------------------------------------------

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

    # The editor manager is used to create/restore editors.
    editor_manager = Instance(IEditorManager)

    # The optional application scripting manager.
    script_manager = Instance("apptools.appscripting.api.IScriptManager")

    # 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 optional undo manager.
    undo_manager = Instance("pyface.undo.api.IUndoManager")

    # The user-defined perspectives manager.
    user_perspective_manager = Instance(UserPerspectiveManager)

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

    # 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)

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

    # The factory that is used to create workbench windows. This is used in
    # the default implementation of 'create_window'. If you override that
    # method then you obviously don't need to set this trait!
    window_factory = Callable

    # Private interface ----------------------------------------------------

    # An 'explicit' exit is when the the 'exit' method is called.
    # An 'implicit' exit is when the user closes the last open window.
    _explicit_exit = Bool(False)

    # ------------------------------------------------------------------------
    # 'IWorkbench' interface.
    # ------------------------------------------------------------------------

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

        window = self.window_factory(workbench=self, **kw)

        # Add on any user-defined perspectives.
        window.perspectives.extend(self.user_perspective_manager.perspectives)

        # Restore the saved window memento (if there is one).
        self._restore_window_layout(window)

        # 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.observe(self._on_window_activated, "activated")
        window.observe(self._on_window_opening, "opening")
        window.observe(self._on_window_opened, "opened")
        window.observe(self._on_window_closing, "closing")
        window.observe(self._on_window_closed, "closed")

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

        return window

    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.

        Returns True if the exit succeeded, False if it was vetoed.

        """

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

        # Event notification.
        self.exiting = event = Vetoable()
        if not event.veto:
            # This flag is checked in '_on_window_closing' to see what kind of
            # exit is being performed.
            self._explicit_exit = True

            if len(self.windows) > 0:
                exited = self._close_all_windows()

            # The degenerate case where no workbench windows have ever been
            # created!
            else:
                # Trait notification.
                self.exited = self

                exited = True

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

        else:
            exited = False

        if not exited:
            logger.debug("**** exit of the workbench vetoed ****")

        return exited

    # Convenience methods on the active window -----------------------------

    def edit(self, obj, kind=None, use_existing=True):
        """ Edit an object in the active workbench window. """

        return self.active_window.edit(obj, kind, use_existing)

    def get_editor(self, obj, kind=None):
        """ Return the editor that is editing an object.

        Returns None if no such editor exists.

        """

        if self.active_window is None:
            return None

        return self.active_window.get_editor(obj, kind)

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

        Returns None if no such editor exists.

        """

        return self.active_window.get_editor_by_id(id)

    # Message dialogs ----

    def confirm(self, message, title=None, cancel=False, default=NO):
        """ Convenience method to show a confirmation dialog. """

        return self.active_window.confirm(message, title, cancel, default)

    def information(self, message, title="Information"):
        """ Convenience method to show an information message dialog. """

        return self.active_window.information(message, title)

    def warning(self, message, title="Warning"):
        """ Convenience method to show a warning message dialog. """

        return self.active_window.warning(message, title)

    def error(self, message, title="Error"):
        """ Convenience method to show an error message dialog. """

        return self.active_window.error(message, title)

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

    # Initializers ---------------------------------------------------------

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

        # It would be preferable to base this on GUI.state_location.
        state_location = os.path.join(
            ETSConfig.application_home,
            "pyface",
            "workbench",
            ETSConfig.toolkit,
        )

        if not os.path.exists(state_location):
            os.makedirs(state_location)

        logger.debug("workbench state location is %s", state_location)

        return state_location

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

        # We make sure the undo package is entirely optional.
        try:
            from pyface.undo.api import UndoManager
        except ImportError:
            return None

        return UndoManager()

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

        return UserPerspectiveManager(state_location=self.state_location)

    # ------------------------------------------------------------------------
    # Protected 'Workbench' interface.
    # ------------------------------------------------------------------------

    def _create_window(self, **kw):
        """ Factory method that creates a new workbench window. """

        raise NotImplementedError()

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

    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

    def _restore_window_layout(self, window):
        """ Restore the window layout. """

        filename = os.path.join(self.state_location, "window_memento")
        if os.path.exists(filename):
            try:
                # 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 = open(filename, "rb")
                memento = pickle.load(f)
                f.close()

                # The memento doesn't actually get used until the window is
                # opened, so there is nothing to go wrong in this step!
                window.set_memento(memento)

            # If *anything* goes wrong then simply log the error and carry on
            # with no memento!
            except:
                logger.exception("restoring window layout from %s", filename)

    def _save_window_layout(self, window):
        """ Save the window layout. """

        # Save the window layout.
        f = open(os.path.join(self.state_location, "window_memento"), "wb")
        pickle.dump(window.get_memento(), f)
        f.close()

        return

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

    def _on_window_activated(self, event):
        """ Dynamic trait change handler. """
        window = event.object
        logger.debug("window %s activated", window)

        self.active_window = window

    def _on_window_opening(self, event):
        """ Dynamic trait change handler. """
        window = event.object
        # Event notification.
        self.window_opening = window_event = VetoableWindowEvent(window=window)
        if window_event.veto:
            event.new.veto = True

    def _on_window_opened(self, event):
        """ Dynamic trait change handler. """
        window = event.object
        # 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)

    def _on_window_closing(self, event):
        """ Dynamic trait change handler. """
        window = event.object
        # Event notification.
        self.window_closing = window_event = VetoableWindowEvent(window=window)

        if window_event.veto:
            event.new.veto = True

        else:
            # Is this the last open window?
            if len(self.windows) == 1:
                # If this is an 'implicit exit' then make sure that we fire the
                # appropriate workbench lifecycle events.
                if not self._explicit_exit:
                    # Event notification.
                    self.exiting = window_event = Vetoable()
                    if window_event.veto:
                        event.new.veto = True

                if not event.new.veto:
                    # Save the window size, position and layout.
                    self._save_window_layout(window)

    def _on_window_closed(self, event):
        """ Dynamic trait change handler. """
        window = event.object
        self.windows.remove(window)

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

        # Was this the last window?
        if len(self.windows) == 0:
            # Event notification.
            self.exited = self

        return
Esempio n. 6
0
class IWorkbench(Interface):
    """ The workbench interface. """

    # 'IWorkbench' interface -----------------------------------------------

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

    # The optional application scripting manager.
    script_manager = Instance("apptools.appscripting.api.IScriptManager")

    # 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 optional undo manager.
    undo_manager = Instance("pyface.undo.api.IUndoManager")

    # The user defined perspectives manager.
    user_perspective_manager = Instance(UserPerspectiveManager)

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

    # 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.
    #
    # This is fired after the last open window has been closed.
    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)

    # ------------------------------------------------------------------------
    # 'IWorkbench' interface.
    # ------------------------------------------------------------------------

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

    def edit(self, obj, kind=None, use_existing=True):
        """ Edit an object in the active workbench window. """

    def exit(self):
        """ Exit 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.

        """

    def get_editor(self, obj, kind=None):
        """ Return the editor that is editing an object.

        Returns None if no such editor exists.

        """

    def get_editor_by_id(self, id):
        """ Return the editor with the specified Id.
Esempio n. 7
0
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 = Str("Pyface Application")

    #: Human-readable company name
    company = Str()

    #: Human-readable description of the application
    description = Str()

    # Infrastructure ---------------------------------------------------------

    #: The application's globally unique identifier.
    id = Str()

    #: 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
Esempio n. 8
0
class Application(HasTraits):
    """ An extensible, pluggable, application.

    This class handles the common case for non-GUI applications, and it is
    intended to be subclassed to change start/stop behaviour etc.

    """

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

    #: The application's globally unique identifier.
    id = Str

    #: The name of a directory (created for you) to which the application can
    #: read and write non-user accessible data, i.e. configuration information,
    #: preferences, etc.
    home = Str

    #: The name of a directory (created for you upon access) to which the
    #: application can read and write user-accessible data, e.g. projects
    #: created by the user.
    user_data = Str

    #: The root preferences node.
    preferences = Instance(IPreferences)

    #### Events ####

    #: Fired when the application is starting.
    starting = VetoableEvent(ApplicationEvent)

    #: Fired when all plugins have been started.
    started = Event(ApplicationEvent)

    #: Fired when the application is stopping.
    stopping = VetoableEvent(ApplicationEvent)

    #: Fired when all plugins have been stopped.
    stopped = Event(ApplicationEvent)

    #### 'IPluginManager' interface ###########################################

    #### Events ####

    #: Fired when a plugin has been added.
    plugin_added = Delegate("plugin_manager", modify=True)

    #: Fired when a plugin has been removed.
    plugin_removed = Delegate("plugin_manager", modify=True)

    #### 'Application' interface ##############################################

    # These traits allow application developers to build completely different
    # styles of extensible application. It allows Envisage to be used as a
    # framework for frameworks ;^)

    #: The extension registry.
    extension_registry = Instance(IExtensionRegistry)

    #: The plugin manager (starts and stops plugins etc).
    plugin_manager = Instance(IPluginManager)

    #: The service registry.
    service_registry = Instance(IServiceRegistry)

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

    # The import manager.
    _import_manager = Instance(IImportManager, factory=ImportManager)

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

    def __init__(self, plugins=None, **traits):
        """ Constructor.

        We allow the caller to specify an initial list of plugins, but the list
        itself is not part of the public API. To add and remove plugins after
        after construction, use the 'add_plugin' and 'remove_plugin' methods
        respectively. The application is also iterable, so to iterate over the
        plugins use 'for plugin in application: ...'.

        """

        super().__init__(**traits)

        # fixme: We have to initialize the application home here (i.e. we can't
        # wait until the 'home' trait is accessed) because the scoped
        # preferences uses 'ETSConfig.application' home as the name of the
        # default preferences file.
        self._initialize_application_home()

        # Set the default preferences node used by the preferences package.
        # This allows 'PreferencesHelper' and 'PreferenceBinding' instances to
        # be used as more convenient ways to access preferences.
        #
        # fixme: This is another sneaky global!
        set_default_preferences(self.preferences)

        # We allow the caller to specify an initial list of plugins, but the
        # list itself is not part of the public API. To add and remove plugins
        # after construction, use the 'add_plugin' and 'remove_plugin' methods
        # respectively. The application is also iterable, so to iterate over
        # the plugins use 'for plugin in application: ...'.
        if plugins is not None:
            for plugin in plugins:
                self.add_plugin(plugin)

        return

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

    #### Trait initializers ###################################################

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

        return ETSConfig.application_home

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

        user_data = os.path.join(ETSConfig.user_data, self.id)

        # Make sure it exists!
        if not os.path.exists(user_data):
            os.makedirs(user_data)

        return user_data

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

        return ScopedPreferences()

    #### Methods ##############################################################

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

        if self.start():
            self.stop()

        return

    ###########################################################################
    # 'IExtensionRegistry' interface.
    ###########################################################################

    def add_extension_point_listener(self, listener, extension_point_id=None):
        """ Add a listener for extensions being added/removed. """

        self.extension_registry.add_extension_point_listener(
            listener, extension_point_id)

        return

    def add_extension_point(self, extension_point):
        """ Add an extension point. """

        self.extension_registry.add_extension_point(extension_point)

        return

    def get_extensions(self, extension_point_id):
        """ Return a list containing all contributions to an extension point.

        """

        return self.extension_registry.get_extensions(extension_point_id)

    def get_extension_point(self, extension_point_id):
        """ Return the extension point with the specified Id. """

        return self.extension_registry.get_extension_point(extension_point_id)

    def get_extension_points(self):
        """ Return all extension points that have been added to the registry.

        """

        return self.extension_registry.get_extension_points()

    def remove_extension_point_listener(self,
                                        listener,
                                        extension_point_id=None):
        """ Remove a listener for extensions being added/removed. """

        self.extension_registry.remove_extension_point_listener(
            listener, extension_point_id)

        return

    def remove_extension_point(self, extension_point_id):
        """ Remove an extension point. """

        self.extension_registry.remove_extension_point(extension_point_id)

        return

    def set_extensions(self, extension_point_id, extensions):
        """ Set the extensions contributed to an extension point. """

        self.extension_registry.set_extensions(extension_point_id, extensions)

        return

    ###########################################################################
    # 'IImportManager' interface.
    ###########################################################################

    def import_symbol(self, symbol_path):
        """ Import the symbol defined by the specified symbol path. """

        return self._import_manager.import_symbol(symbol_path)

    ###########################################################################
    # 'IPluginManager' interface.
    ###########################################################################

    def __iter__(self):
        """ Return an iterator over the manager's plugins. """

        return iter(self.plugin_manager)

    def add_plugin(self, plugin):
        """ Add a plugin to the manager. """

        self.plugin_manager.add_plugin(plugin)

        return

    def get_plugin(self, plugin_id):
        """ Return the plugin with the specified Id. """

        return self.plugin_manager.get_plugin(plugin_id)

    def remove_plugin(self, plugin):
        """ Remove a plugin from the manager. """

        self.plugin_manager.remove_plugin(plugin)

        return

    def start(self):
        """ Start the plugin manager.

        Returns True unless the start was vetoed.

        """

        # fixme: This method is notionally on the 'IPluginManager' interface
        # but that interface knows nothing about the vetoable events etc and
        # hence doesn't have a return value.
        logger.debug("---------- application starting ----------")

        # Lifecycle event.
        self.starting = event = self._create_application_event()
        if not event.veto:
            # Start the plugin manager (this starts all of the manager's
            # plugins).
            self.plugin_manager.start()

            # Lifecycle event.
            self.started = self._create_application_event()

            logger.debug("---------- application started ----------")

        else:
            logger.debug("---------- application start vetoed ----------")

        return not event.veto

    def start_plugin(self, plugin=None, plugin_id=None):
        """ Start the specified plugin. """

        return self.plugin_manager.start_plugin(plugin, plugin_id)

    def stop(self):
        """ Stop the plugin manager.

        Returns True unless the stop was vetoed.

        """

        # fixme: This method is notionally on the 'IPluginManager' interface
        # but that interface knows nothing about the vetoable events etc and
        # hence doesn't have a return value.
        logger.debug("---------- application stopping ----------")

        # Lifecycle event.
        self.stopping = event = self._create_application_event()
        if not event.veto:
            # Stop the plugin manager (this stops all of the manager's
            # plugins).
            self.plugin_manager.stop()

            # Save all preferences.
            self.preferences.save()

            # Lifecycle event.
            self.stopped = self._create_application_event()

            logger.debug("---------- application stopped ----------")

        else:
            logger.debug("---------- application stop vetoed ----------")

        return not event.veto

    def stop_plugin(self, plugin=None, plugin_id=None):
        """ Stop the specified plugin. """

        return self.plugin_manager.stop_plugin(plugin, plugin_id)

    ###########################################################################
    # 'IServiceRegistry' interface.
    ###########################################################################

    def get_required_service(self,
                             protocol,
                             query="",
                             minimize="",
                             maximize=""):
        """ Return the service that matches the specified query.

        Raise a 'NoSuchServiceError' exception if no such service exists.

        """

        service = self.service_registry.get_required_service(
            protocol, query, minimize, maximize)

        return service

    def get_service(self, protocol, query="", minimize="", maximize=""):
        """ Return at most one service that matches the specified query. """

        service = self.service_registry.get_service(protocol, query, minimize,
                                                    maximize)

        return service

    def get_service_from_id(self, service_id):
        """ Return the service with the specified id. """

        return self.service_registry.get_service_from_id(service_id)

    def get_service_properties(self, service_id):
        """ Return the dictionary of properties associated with a service. """

        return self.service_registry.get_service_properties(service_id)

    def get_services(self, protocol, query="", minimize="", maximize=""):
        """ Return all services that match the specified query. """

        services = self.service_registry.get_services(protocol, query,
                                                      minimize, maximize)

        return services

    def register_service(self, protocol, obj, properties=None):
        """ Register a service. """

        service_id = self.service_registry.register_service(
            protocol, obj, properties)

        return service_id

    def set_service_properties(self, service_id, properties):
        """ Set the dictionary of properties associated with a service. """

        self.service_registry.set_service_properties(service_id, properties)

        return

    def unregister_service(self, service_id):
        """ Unregister a service. """

        self.service_registry.unregister_service(service_id)

        return

    ###########################################################################
    # 'Application' interface.
    ###########################################################################

    #### Trait initializers ###################################################

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

        # Do the import here to emphasize the fact that this is just the
        # default implementation and that the application developer is free
        # to override it!
        from .plugin_extension_registry import PluginExtensionRegistry

        return PluginExtensionRegistry(plugin_manager=self)

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

        # Do the import here to emphasize the fact that this is just the
        # default implementation and that the application developer is free
        # to override it!
        from .plugin_manager import PluginManager

        return PluginManager(application=self)

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

        # Do the import here to emphasize the fact that this is just the
        # default implementation and that the application developer is free
        # to override it!
        from .service_registry import ServiceRegistry

        return ServiceRegistry()

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

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

    # fixme: We have this to make it easier to assign a new plugin manager
    # at construction time due to the fact that the plugin manager needs a
    # reference to the application and vice-versa, e.g. we can do
    #
    #    application = Application(plugin_manager=EggPluginManager())
    #
    # If we didn't have this then we would have to do this:-
    #
    #    application = Application()
    #    application.plugin_manager = EggPluginManager(application=application)
    #
    # Of course, it would be better if the plugin manager didn't require a
    # reference to the application at all (it currently uses it to set the
    # 'application' trait of plugin instances - but that is only done for the
    # same reason as this (i.e. it is nice to be able to pass plugins into the
    # application constructor).
    def _plugin_manager_changed(self, trait_name, old, new):
        """ Static trait change handler. """

        if old is not None:
            old.application = None

        if new is not None:
            new.application = self

        return

    #### Methods ##############################################################

    def _create_application_event(self):
        """ Create an application event. """

        return ApplicationEvent(application=self)

    def _initialize_application_home(self):
        """ Initialize the application home directory. """

        ETSConfig.application_home = os.path.join(ETSConfig.application_data,
                                                  self.id)

        # Make sure it exists!
        if not os.path.exists(ETSConfig.application_home):
            os.makedirs(ETSConfig.application_home)

        return
Esempio n. 9
0
class MEditor(MWorkbenchPart):
    """ Mixin containing common code for toolkit-specific implementations. """

    # 'IEditor' interface -------------------------------------------------#

    # The optional command stack.
    command_stack = Instance("apptools.undo.api.ICommandStack")

    # Is the object that the editor is editing 'dirty' i.e., has it been
    # modified but not saved?
    dirty = Bool(False)

    # The object that the editor is editing.
    #
    # The framework sets this when the editor is created.
    obj = Any()

    # Editor Lifecycle Events ---------------------------------------------#

    # Fired when the editor is opening.
    opening = VetoableEvent()

    # Fired when the editor has been opened.
    open = Event()

    # Fired when the editor is closing.
    closing = Event(VetoableEvent)

    # Fired when the editor is closed.
    closed = Event()

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

    def __str__(self):
        """ Return an informal string representation of the object. """

        return "Editor(%s)" % self.id

    # ------------------------------------------------------------------------
    # 'IWorkbenchPart' interface.
    # ------------------------------------------------------------------------

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

        # If no Id is specified then use a random uuid
        # this gaurantees (barring *really* unusual cases) that there are no
        # collisions between the ids of editors.
        return uuid.uuid4().hex

    # ------------------------------------------------------------------------
    # 'IEditor' interface.
    # ------------------------------------------------------------------------

    def close(self):
        """ Close the editor. """

        if self.control is not None:
            self.closing = event = Vetoable()
            if not event.veto:
                self.window.close_editor(self)

                self.closed = True

        return

    # Initializers ---------------------------------------------------------

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

        # We make sure the undo package is entirely optional.
        try:
            from apptools.undo.api import CommandStack
        except ImportError:
            return None

        return CommandStack(undo_manager=self.window.workbench.undo_manager)
Esempio n. 10
0
class Window(MWindow, Widget):
    """ The toolkit specific implementation of a Window.  See the IWindow
    interface for the API documentation.
    """

    # 'IWindow' interface -----------------------------------------------------

    position = Property(Tuple)

    size = Property(Tuple)

    size_state = Enum("normal", "maximized")

    title = Str()

    # Window Events ----------------------------------------------------------

    #: The window has been opened.
    opened = Event()

    #: The window is about to open.
    opening = VetoableEvent()

    #: The window has been activated.
    activated = Event()

    #: The window has been closed.
    closed = Event()

    #: The window is about to be closed.
    closing = VetoableEvent()

    #: The window has been deactivated.
    deactivated = Event()

    # Private interface ------------------------------------------------------

    #: Shadow trait for position.
    _position = Tuple((-1, -1))

    #: 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

    # -------------------------------------------------------------------------
    # Protected 'IWindow' interface.
    # -------------------------------------------------------------------------

    def _create_control(self, parent):
        """ Create a default QMainWindow. """
        control = QtGui.QMainWindow(parent)

        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)

        # XXX starting with visible true is not recommended
        control.setVisible(self.visible)

        return control

    # -------------------------------------------------------------------------
    # 'IWidget' interface.
    # -------------------------------------------------------------------------

    def destroy(self):

        if self.control is not None:
            # Avoid problems with recursive calls.
            # Widget.destroy() sets self.control to None,
            # so we need a reference to control
            control = self.control

            # Widget.destroy() sets self.control to None and deletes it later,
            # so we call it before control.close()
            # This is not strictly necessary (closing the window in fact
            # hides it), but the close may trigger an application shutdown,
            # which can take a long time and may also attempt to recursively
            # destroy the window again.
            super().destroy()
            control.close()
            control.hide()

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

    def _get_position(self):
        """ Property getter for position. """

        return self._position

    def _set_position(self, position):
        """ Property setter for position. """

        if self.control is not None:
            self.control.move(*position)

        old = self._position
        self._position = position

        self.trait_property_changed("position", old, position)

    def _get_size(self):
        """ Property getter for size. """

        return self._size

    def _set_size(self, size):
        """ Property setter for size. """

        if self.control is not None:
            self.control.resize(*size)

        old = self._size
        self._size = size

        self.trait_property_changed("size", old, size)

    def _size_state_changed(self, state):
        control = self.control
        if control is None:
            return  # Nothing to do here

        if state == "maximized":
            control.setWindowState(control.windowState()
                                   | QtCore.Qt.WindowState.WindowMaximized)
        elif state == "normal":
            control.setWindowState(control.windowState()
                                   & ~QtCore.Qt.WindowState.WindowMaximized)

    def _title_changed(self, title):
        """ Static trait change handler. """

        if self.control is not None:
            self.control.setWindowTitle(title)

    def __event_filter_default(self):
        return WindowEventFilter(self)
Esempio n. 11
0
class IWindow(IWidget):
    """ The abstract interface for all pyface top-level windows.

    A pyface top-level window has no visual representation until it is opened
    (ie. its 'control' trait will be None until it is opened).
    """

    # 'IWindow' interface -----------------------------------------------------

    #: The position of the window.
    position = Tuple()

    #: The size of the window.
    size = Tuple()

    #: The window title.
    title = Str()

    # Window Events ----------------------------------------------------------

    #: The window has been opened.
    opened = Event()

    #: The window is about to open.
    opening = VetoableEvent()

    #: The window has been activated.
    activated = Event()

    #: The window has been closed.
    closed = 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: Str
    key_pressed = Event(KeyPressedEvent)

    # -------------------------------------------------------------------------
    # 'IWindow' interface.
    # -------------------------------------------------------------------------

    def open(self):
        """ Opens the window.

        This fires the :py:attr:`closing` vetoable event, giving listeners the
        opportunity to veto the opening of 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.
        """

    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.
        """

    def confirm(self, message, title=None, cancel=False, default=NO):
        """ Convenience method to show a confirmation dialog.

        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",
                    detail="",
                    informative=""):
        """ Convenience method to show an information 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.

        """

    def warning(self, message, title="Warning", detail="", informative=""):
        """ Convenience method to show a warning 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.

        """

    def error(self, message, title="Error", detail="", informative=""):
        """ Convenience method to show an error message dialog.
#
# (C) Copyright 2013 Enthought, Inc., Austin, TX
# All right reserved.
#
# This file is open source software distributed according to the terms in
# LICENSE.txt
#

from traits.api import Str, List, Vetoable, VetoableEvent, Any


class ItemsModified(Vetoable):
    """ Type of event fired when a DataContext has values added or removed.
    """

    context = Any  #Instance('codetools.contexts.i_context.IContext')
    added = List(Str)
    removed = List(Str)
    modified = List(Str)

    def __repr__(self):
        return ('%s(context=%r, added=%r, removed=%r, modified=%r)' %
                (type(self).__name__, self.context, self.added, self.removed,
                 self.modified))


# Define an Event trait which accepts an ItemsModified object:
ItemsModifiedEvent = VetoableEvent(ItemsModified)
Esempio n. 13
0
class Window(MWindow, Widget):
    """ The toolkit specific implementation of a Window.  See the IWindow
    interface for the API documentation.
    """

    # 'IWindow' interface -----------------------------------------------------

    position = Property(Tuple)

    size = Property(Tuple)

    title = Str()

    # Window Events ----------------------------------------------------------

    #: The window has been opened.
    opened = Event()

    #: The window is about to open.
    opening = VetoableEvent()

    #: The window has been activated.
    activated = Event()

    #: The window has been closed.
    closed = 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: Str
    key_pressed = Event(KeyPressedEvent)

    size = Property(Tuple)

    # Private interface ------------------------------------------------------

    # Shadow trait for position.
    _position = Tuple((-1, -1))

    # Shadow trait for size.
    _size = Tuple((-1, -1))

    # -------------------------------------------------------------------------
    # 'IWindow' interface.
    # -------------------------------------------------------------------------

    def activate(self):
        self.control.Iconize(False)
        self.control.Raise()

    def show(self, visible):
        self.control.Show(visible)

    # -------------------------------------------------------------------------
    # Protected 'IWindow' interface.
    # -------------------------------------------------------------------------

    def _add_event_listeners(self):
        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

        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,
            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. """

        return self._position

    def _set_position(self, position):
        """ Property setter for position. """

        if self.control is not None:
            self.control.SetPosition(position)

        old = self._position
        self._position = position

        self.trait_property_changed("position", old, position)

    def _get_size(self):
        """ Property getter for size. """

        return self._size

    def _set_size(self, size):
        """ Property setter for size. """

        if self.control is not None:
            self.control.SetSize(size)

        old = self._size
        self._size = size

        self.trait_property_changed("size", old, size)

    def _title_changed(self, title):
        """ Static trait change handler. """

        if self.control is not None:
            self.control.SetTitle(title)

    # wx event handlers ------------------------------------------------------

    def _wx_on_activate(self, event):
        """ Called when the frame is being activated or deactivated. """

        if event.GetActive():
            self.activated = self
        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. """

        self.close()

    def _wx_on_control_move(self, event):
        """ Called when the window is resized. """

        # Get the real position and set the trait without performing
        # notification.

        # WXBUG - From the API documentation you would think that you could
        # call event.GetPosition directly, but that would be wrong.  The pixel
        # reported by that call is the pixel just below the window menu and
        # just right of the Windows-drawn border.

        try:
            self._position = (event.GetEventObject().GetPosition().Get()
                              )  # Sizer.GetPosition().Get()
        except:
            pass
        event.Skip()

    def _wx_on_control_size(self, event):
        """ Called when the window is resized. """

        # Get the new size and set the shadow trait without performing
        # notification.
        wxsize = event.GetSize()

        self._size = (wxsize.GetWidth(), wxsize.GetHeight())

        event.Skip()

    def _wx_on_char(self, event):
        """ Called when a key is pressed when the tree has focus. """

        self.key_pressed = KeyPressedEvent(
            alt_down=event.altDown,
            control_down=event.controlDown,
            shift_down=event.shiftDown,
            key_code=event.KeyCode,
            event=event,
        )

        event.Skip()