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.
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.
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.
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
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
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.
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
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
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)
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)
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)
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()