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

workbench_window.py

00001 """ A top-level workbench window. """


# Major package imports.
import wx

# Enthought library imports.
from enthought.envisage import Plugin
from enthought.pyface.api import MDIApplicationWindow
from enthought.pyface.action.api import Group, MenuBarManager, StatusBarManager
from enthought.pyface.action.api import ToolBarManager
from enthought.traits.api import Dict, Instance, List, Trait, Tuple
from enthought.util.wx.drag_and_drop import PythonDropTarget, clipboard

# Local imports.
from page_layout import PageLayout
from view import View
from workarea_window import WorkareaWindow

# Local imports.
from ui_plugin_definition import UIActions, UIBranding, UIViews


00024 class WorkbenchWindow(MDIApplicationWindow):
    """ A top-level workbench window. """

    #### 'WorkbenchWindow' interface ##########################################

    # The UI plugin that is creating the window.
    plugin = Instance(Plugin)

    ####
    # FIXME: The following traits are misnomers now that we have WorkareaWindow
    ####

    # The open editors.
    editors = List(WorkareaWindow)

    # The active editor, which is defined as the most recent editor to receive
    # focus, or None if no editors are open or the previous active editor was
    # closed in a manner that did not cause focus to change to another editor.
    active_editor = Trait(None, None, WorkareaWindow)

    # Auxillary views for the active editor.
    editor_views = List(View)

    # The current selection within the window.
    selection = List

    # The visible views.
    views = List(View)

    # The layout manager.
    page_layout = Instance(PageLayout)

    # The page layout preferences.
    page_layout_preferences = Dict

    # The toolbar image size.
    tool_bar_image_size = Tuple

00062     def _page_layout_default(self):
        """ Default initializer for page_layout trait. """

        return PageLayout(self)

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

00071     def __init__(self, plugin, **traits):
        """ Creates a new workbench window. """

        # Base class constructor.
        super(WorkbenchWindow, self).__init__(plugin=plugin, **traits)

        # Get all contributed menus,  groups and actions.
        menus, groups, actions = self._get_action_extensions(self)

        # Menu bar.
        self.menu_bar_manager = MenuBarManager(
            Group(id='FileGroup'),
            Group(id='ToolsGroup'),
            Group(id='HelpGroup'),

            id = 'MenuBar',
        )
        self._initialize_menu_bar(self, menus, groups, actions)

        # Tool bar.
        # Note that we have to configure the image_size here because the
        # toolbar's init expects it to be set.
        image_size = (16, 16)
        if self.tool_bar_image_size != ():
            image_size = self.tool_bar_image_size

        self.tool_bar_manager = ToolBarManager(id='ToolBar',
                                               image_size = image_size)
        self._initialize_tool_bar(self, actions)

        # Status bar.
        self.status_bar_manager = StatusBarManager(id='StatusBar')

        return

    #### fixme: Action controller interface!!!!!
    def perform(self, action, event):

        event.application = self.plugin.application
        event.window = self

        return action.perform(event)

    def can_add_to_menu(self, action):
        return True

    def add_to_menu(self, action):
        return

00120     def _create_menu_bar(self, parent):
        """ Creates the menu bar (if required). """

        if self.menu_bar_manager is not None:
            menu_bar = self.menu_bar_manager.create_menu_bar(
                parent, controller=self
            )
            parent.SetMenuBar(menu_bar)

        return

    #### fixme: Action controller interface!!!!!

    ###########################################################################
    # 'Window' interface.
    ###########################################################################

00137     def close(self):
        """ Closes the window. """

        if self.plugin.window_can_close(self):
            for view in self.views:
                view.closing = True
            self.views = []
            super(WorkbenchWindow, self).close()

        return

    ###########################################################################
    # Protected 'Window' interface.
    ###########################################################################

00152     def _create_contents(self, parent):
        """ Creates the window contents. """

        application = self.plugin.application
        
        # Get all contributed views.
        extensions = application.get_extensions(UIViews)

        # Set the default window content.
        self.create_default_content(extensions)

        # Listen for drag over and drops on the client window.
        client_window = self.control.GetClientWindow()
        client_window.SetDropTarget(PythonDropTarget(self))

        return

00169     def on_drag_over(self, x, y, obj, default_drag_result):
        """ Called when a data object is being dragged over the target. """

        from enthought.envisage.project import CookieManager
        from enthought.envisage.project.action.open_cookie import OpenCookie

        # fixme: The 'clipboard.node' was a quick hack put into the Pyface
        # tree some time ago! The whole drag and drop thang needs revisiting!
        bindings = clipboard.node
        if bindings is None:
            bindings = []

        drag_result = wx.DragNone
        for binding in bindings:
            cookie = CookieManager().get_cookie(OpenCookie, binding.obj)
            if cookie is not None:
                drag_result = default_drag_result

        return drag_result

00189     def on_drop(self, x, y, obj, default_drag_result):
        """ Called when a node is dropped on the work area. """
        from enthought.envisage.project import CookieManager
        from enthought.envisage.project.action.open_cookie import OpenCookie

        # fixme: The 'clipboard.node' was a quick hack put into the Pyface
        # tree some time ago! The whole drag and drop thang needs revisiting!
        bindings = clipboard.node
        if bindings is None:
            bindings = []

        for binding in bindings:
            cookie = CookieManager().get_cookie(OpenCookie, binding.obj)
            if cookie is not None:
                cookie.open(self, binding)
            
        return default_drag_result

    ###########################################################################
    # 'WorkbenchWindow' interface.
    ###########################################################################

00211     def create_editor(self, title, tool_bar_manager=None, is_mdi=True, float=True):
        """ Creates an editor in the workarea. """

        editor = self.create_child_window(title, is_mdi, float=float)

        # Set up the tool bar if necessary.
        if tool_bar_manager is not None:
            tool_bar = tool_bar_manager.create_tool_bar(editor)
            editor.SetToolBar(tool_bar)

        return editor

00223     def create_view(self, name, position):
        """ Creates a named view in the requested position. """

        layout_part = self.page_layout.get_layout_part(position)

        return layout_part.create_part_pane(name)

00230     def create_default_content(self, ui_views):
        """ Creates the default window content. """

        page_layout = PageLayout(self)
        page_layout.add_workarea()

        visibility = self.plugin.preferences.get('view_visibility', {})

        for ui_view in ui_views:
            # We are about to actually import view implementation classes, so
            # make sure that the plugins that contributed them have been
            # started.
            self.plugin.application.start_plugin(ui_view._definition_.id)

            for bundle in ui_view.views:
                # Create the view from the definition bundle.
                view = self._create_view(bundle)
                self.views.append(view)

                # If the view has a visibility preference, use that to decide
                # if the view should be shown.  If no preference has been set,
                # use the visibility setting declared by the bundle.
                # NOTE: The attempt to use the bundle setting is wrapped in a
                # try...except in case someone is using an old definition of
                # bundle class that doesn't have the property defined.
                default_visible = True
                try:
                    default_visible = bundle.visible
                except:
                    pass
                view_visible = visibility.get(view.id, default_visible)
                if view_visible:
                    view.open()

        from enthought.pyface.action.api import Action
        from enthought.traits.api import Any

        # The view menu.
        menu  = self.menu_bar_manager.find_item('ViewMenu')
        group = menu.find_group('Start')


        class ViewAction(Action):

            view = Any

            def perform(self, ingored_event):
                # BOGUS:  The checked state is already changed so we need to
                # BOGUS:  look at not checked to see if we should open or close
                # BOGUS:  the view.
                #
                # As of 12/12/05, the toggle is no longer done first, thus I've
                # removed a "not" in the following logic.  I'm not sure if this
                # was a planned change in the API, so I'm leaving this comment in here
                # in case it changes back. -- LGV
                if self.checked:
                    self.view.close()
                else:
                    self.view.open()

            def __init__(self, **traits):
                super(ViewAction, self).__init__(**traits)
                self.view.on_trait_change(self._on_opened_changed, "opened")

            def _on_opened_changed(self, new):
                self.checked = new

        for view in self.views:
            group.append(ViewAction(name=view.name, style='toggle',
                                    checked=view.opened, view=view))

        menu.changed = menu

        return

00305     def editor_opened(self, editor):
        """ Handle an editor being opened. """

        self.editors.append(editor)
        self.active_editor = editor

        # Connect trait event handlers.
        editor.on_trait_change(self._on_editor_activated, 'activated')
        editor.on_trait_change(self._on_editor_closed, 'closed')

        return

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

00321     def _initialize_menu_bar(self, window, menus, groups, actions):
        """ Initializes a window's menu bar with all contributions. """

        from enthought.envisage.project.menu_builder import MenuBuilder

        menu_builder = MenuBuilder(action_path='menu_bar_path', window=window)
        menu_builder.build_menu(
            self.plugin.application, window.menu_bar_manager, menus, groups, actions
        )

        # Add the 'Window' menu that mimics the standard wx menu for
        # tiling/cascading etc.
        from enthought.pyface.api import MDIWindowMenu
        group = window.menu_bar_manager.groups[-2]#('HelpGroup')
        group.insert(1, MDIWindowMenu(window))

        return

00339     def _initialize_tool_bar(self, window, actions):
        """ Initializes a window's tool bar with all contributions. """

        tool_bar_manager = window.tool_bar_manager
        tool_bar_manager.show_tool_names = self.plugin.preferences.get(
            'show_tool_names'
        )

        for action, defined_in in actions:
            path = action.bundle.tool_bar_path
            if len(path) > 0:
                group = tool_bar_manager.find_group(path)
                if group is None:
                    group = tool_bar_manager.append(Group(id=path))

                group.append(action)

        return

00358     def _create_view(self, bundle):
        """ Creates a view implementation. """

        application = self.plugin.application
        
        # Import the class that implements the view.
        class_name = bundle.class_name
        klass = application.import_symbol(class_name)

        # Create the view implementation.
        view = klass(window=self)
        view.copy_traits(bundle)

        # Listen for selection changes.
        view.on_trait_change(self._on_view_selection_changed, 'selection')

        return view

00376     def _get_action_extensions(self, window):
        """ Returns all contributions to the 'UIActions' extension point. """

        application = self.plugin.application

        from workbench_action_proxy import WorkbenchActionProxyFactory
        factory = WorkbenchActionProxyFactory()

        extensions = application.get_extensions(UIActions)

        menus   = []
        groups  = []
        actions = []
        for extension in extensions:
            for menu in extension.menus:
                menus.append((menu, extension._definition_.id))

            for group in extension.groups:
                groups.append((group, extension._definition_.id))

            for action in extension.actions:
                proxy = factory.create_instance(
                    action, window, extension._definition_.id
                )
                proxy.menu_bar_path = action.menu_bar_path
                actions.append((proxy, extension._definition_.id))

        # fixme: Hack to sort menus by path length.
        def sort((a, x), (b, y)):
            ca = a.path.split('/')
            cb = b.path.split('/')

            return cmp(len(ca), len(cb))

        menus.sort(sort)

        return menus, groups, actions

00414     def _update_auxillary_parts(self, active_editor):
        """ Update all the auxillary editor parts to match the active editor.
        """

        # Close down any existing editor views.
        for view in self.editor_views:
            # fixme : err... should this be a destroy?  maybe only on close?
            view.close()
            self.editor_views = []

        if active_editor is not None:
            self.editor_views = active_editor.get_auxillary_views()
            for view in self.editor_views:
                view.open()

        return

    #### Trait event handlers #################################################

    #### Static ####

00435     def _active_editor_changed(self, old, new):
        """ Called when the active editor is changed. """

        self._update_auxillary_parts(new)

        return

    #### Dynamic ####

00444     def _on_editor_activated(self, editor):
        """ Called when an editor is activated. """

        self.active_editor = editor

        return

00451     def _on_editor_closed(self, editor):
        """ Called when an editor is closed. """

        if self.active_editor == editor:
            self.active_editor = None

        del self.editors[self.editors.index(editor)]

        return

00461     def _on_view_selection_changed(self, obj, trait_name, old, new):
        """ Called when a view's selection is changed. """

        self.selection = new

        return

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

Generated by  Doxygen 1.6.0   Back to index