Exemple #1
0
    def create_initial_layout(self, parent):
        """ Create the initial window layout. """

        # The view dock window is where all of the views live. It also contains
        # a nested dock window where all of the editors live.
        self._wx_view_dock_window = WorkbenchDockWindow(parent)

        # The editor dock window (which is nested inside the view dock window)
        # is where all of the editors live.
        self._wx_editor_dock_window = WorkbenchDockWindow(
            self._wx_view_dock_window.control
        )
        editor_dock_window_sizer = DockSizer(contents=DockSection())
        self._wx_editor_dock_window.control.SetSizer(editor_dock_window_sizer)

        # Nest the editor dock window in the view dock window.
        editor_dock_window_control = DockControl(
            id      = self.editor_area_id,
            name    = 'Editors',
            control = self._wx_editor_dock_window.control,
            style   = 'fixed',
            width   = self.window.editor_area_size[0],
            height  = self.window.editor_area_size[1],
        )

        view_dock_window_sizer = DockSizer(
            contents=[editor_dock_window_control]
        )

        self._wx_view_dock_window.control.SetSizer(view_dock_window_sizer)

        return self._wx_view_dock_window.control
    def init(self, parent):
        """ Finishes initializing the editor by creating the underlying toolkit
            widget.
        """
        self._uis = []

        # Create a DockWindow to hold each separate object's view:
        theme = self.factory.dock_theme or self.item.container.dock_theme
        dw = DockWindow(parent, theme=theme)
        self.control = dw.control
        self._sizer = DockSizer(DockSection(dock_window=dw))
        self.control.SetSizer(self._sizer)

        # Set up the additional 'list items changed' event handler needed for
        # a list based trait. Note that we want to fire the update_editor_item
        # only when the items in the list change and not when intermediate
        # traits change. Therefore, replace "." by ":" in the extended_name
        # when setting up the listener.
        extended_name = self.extended_name.replace('.', ':')
        self.context_object.on_trait_change(
            self.update_editor_item,
            extended_name + '_items?',
            dispatch='ui')

        # Set of selection synchronization:
        self.sync_value(self.factory.selected, 'selected')
Exemple #3
0
    def init(self, parent):
        """ Finishes initializing the editor by creating the underlying toolkit
            widget.
        """
        self._uis = []

        # Create a DockWindow to hold each separate object's view:
        theme = self.factory.dock_theme or self.item.container.dock_theme
        dw = DockWindow(parent, theme=theme)
        self.control = dw.control
        self._sizer = DockSizer(DockSection(dock_window=dw))
        self.control.SetSizer(self._sizer)

        # Set up the additional 'list items changed' event handler needed for
        # a list based trait:
        self.context_object.on_trait_change(self.update_editor_item,
                                            self.extended_name + '_items?',
                                            dispatch='ui')

        # Set of selection synchronization:
        self.sync_value(self.factory.selected, 'selected')
Exemple #4
0
    def __init__(
        self, panel, group, ui, suppress_label, is_dock_window, create_panel
    ):
        """ Initializes the object.
        """
        # Get the contents of the group:
        content = group.get_content()

        # Create a group editor object if one is needed:
        self.control = self.sizer = editor = None
        self.ui = ui
        self.group = group
        self.is_horizontal = group.orientation == "horizontal"
        layout = group.layout
        is_scrolled_panel = group.scrollable
        is_splitter = layout == "split"
        is_tabbed = layout == "tabbed"
        id = group.id

        # Assume our contents are not resizable:
        self.resizable = False

        if is_dock_window and (is_splitter or is_tabbed):
            if is_splitter:
                self.dock_contents = self.add_dock_window_splitter_items(
                    panel, content, group
                )
            else:
                self.resizable = group.springy
                self.dock_contents = create_notebook_for_items(
                    content, ui, panel, group, self.add_notebook_item, True
                )
            return

        if (
            is_dock_window
            or create_panel
            or is_scrolled_panel
            or (id != "")
            or (group.visible_when != "")
            or (group.enabled_when != "")
        ):
            if is_scrolled_panel:
                new_panel = TraitsUIScrolledPanel(panel)
                new_panel.SetMinSize(panel.GetMinSize())
                self.resizable = True
            else:
                new_panel = TraitsUIPanel(panel, -1)

            sizer = panel.GetSizer()
            if sizer is None:
                sizer = wx.BoxSizer(wx.VERTICAL)
                panel.SetSizer(sizer)
            self.control = panel = new_panel
            if is_splitter or is_tabbed:
                editor = DockWindowGroupEditor(control=panel, ui=ui)
            else:
                editor = GroupEditor(control=panel)
            if id != "":
                ui.info.bind(group.id, editor)
            if group.visible_when != "":
                ui.add_visible(group.visible_when, editor)
            if group.enabled_when != "":
                ui.add_enabled(group.enabled_when, editor)

        self.panel = panel
        self.dock_contents = None

        # Determine the horizontal/vertical orientation of the group:
        if self.is_horizontal:
            orientation = wx.HORIZONTAL
        else:
            orientation = wx.VERTICAL

        # Set up a group with or without a border around its contents:
        label = ""
        if not suppress_label:
            label = group.label

        if group.show_border:
            box = wx.StaticBox(panel, -1, label)
            self._set_owner(box, group)
            self.sizer = wx.StaticBoxSizer(box, orientation)
        else:
            if layout == "flow":
                self.sizer = FlowSizer(orientation)
            else:
                self.sizer = wx.BoxSizer(orientation)
            if label != "":
                self.sizer.Add(
                    heading_text(panel, text=label).control,
                    0,
                    wx.EXPAND | wx.LEFT | wx.TOP | wx.RIGHT,
                    4,
                )

        # If no sizer has been specified for the panel yet, make the new sizer
        # the layout sizer for the panel:
        if panel.GetSizer() is None:
            panel.SetSizer(self.sizer)

        # Set up scrolling now that the sizer has been set:
        if is_scrolled_panel:
            if self.is_horizontal:
                panel.SetupScrolling(scroll_y=False)
            else:
                panel.SetupScrolling(scroll_x=False)

        if is_splitter:
            dw = DockWindow(
                panel,
                handler=ui.handler,
                handler_args=(ui.info,),
                id=ui.id,
                theme=group.dock_theme,
            ).control
            if editor is not None:
                editor.dock_window = dw

            dw.SetSizer(
                DockSizer(
                    contents=self.add_dock_window_splitter_items(
                        dw, content, group
                    )
                )
            )
            self.sizer.Add(dw, 1, wx.EXPAND)
        elif len(content) > 0:
            if is_tabbed:
                self.resizable = group.springy
                dw = create_notebook_for_items(
                    content, ui, panel, group, self.add_notebook_item
                )
                if editor is not None:
                    editor.dock_window = dw

                self.sizer.Add(dw, self.resizable, wx.EXPAND)
            # Check if content is all Group objects:
            elif layout == "fold":
                self.resizable = True
                self.sizer.Add(
                    self.create_fold_for_items(panel, content), 1, wx.EXPAND
                )
            elif isinstance(content[0], Group):
                # If so, add them to the panel and exit:
                self.add_groups(content, panel)
            else:
                self.add_items(content, panel, self.sizer)

        # If the caller is a DockWindow, we need to define the content we are
        # adding to it:
        if is_dock_window:
            self.dock_contents = DockRegion(
                contents=[
                    DockControl(
                        name=group.get_label(self.ui),
                        image=group.image,
                        id=group.get_id(),
                        style=group.dock,
                        dockable=DockableViewElement(ui=ui, element=group),
                        export=group.export,
                        control=panel,
                    )
                ]
            )
Exemple #5
0
def create_notebook_for_items(
    content, ui, parent, group, item_handler=None, is_dock_window=False
):
    """ Creates a notebook and adds a list of groups or items to it as separate
        pages.
    """
    if is_dock_window:
        nb = parent
    else:
        dw = DockWindow(
            parent, handler=ui.handler, handler_args=(ui.info,), id=ui.id
        )
        if group is not None:
            dw.theme = group.dock_theme
        nb = dw.control
    pages = []
    count = 0

    # Create a notebook page for each group or item in the content:
    active = 0
    for index, item in enumerate(content):
        if isinstance(item, Group):
            # Create the group as a nested DockWindow item:
            if item.selected:
                active = index
            sg_sizer, resizable, contents = fill_panel_for_group(
                nb, item, ui, suppress_label=True, is_dock_window=True
            )

            # If the result is a region (i.e. notebook) with only one page,
            # collapse it down into just the contents of the region:
            if isinstance(contents, DockRegion) and (
                len(contents.contents) == 1
            ):
                contents = contents.contents[0]

            # Add the content to the notebook as a new page:
            pages.append(contents)
        else:
            # Create the new page as a simple DockControl containing the
            # specified set of controls:
            page_name = item.get_label(ui)
            count += 1
            if page_name == "":
                page_name = "Page %d" % count

            sizer = wx.BoxSizer(wx.VERTICAL)

            panel = TraitsUIPanel(nb, -1)
            panel.SetSizer(sizer)

            pages.append(
                DockControl(
                    name=page_name,
                    image=item.image,
                    id=item.get_id(),
                    style=item.dock,
                    dockable=DockableViewElement(ui=ui, element=item),
                    export=item.export,
                    control=panel,
                )
            )
            item_handler(item, panel, sizer)
            panel.GetSizer().Fit(panel)

    region = DockRegion(contents=pages, active=active)

    # If the caller is a DockWindow, return the region as the result:
    if is_dock_window:
        return region

    nb.SetSizer(DockSizer(contents=DockSection(contents=[region])))

    # Return the notebook as the result:
    return nb
Exemple #6
0
class NotebookEditor(Editor):
    """ An editor for lists that displays the list as a "notebook" of tabbed
        pages.
    """

    #---------------------------------------------------------------------------
    #  Trait definitions:
    #---------------------------------------------------------------------------

    # Is the notebook editor scrollable? This values overrides the default:
    scrollable = True

    # The currently selected notebook page object:
    selected = Any

    #---------------------------------------------------------------------------
    #  Finishes initializing the editor by creating the underlying toolkit
    #  widget:
    #---------------------------------------------------------------------------

    def init(self, parent):
        """ Finishes initializing the editor by creating the underlying toolkit
            widget.
        """
        self._uis = []

        # Create a DockWindow to hold each separate object's view:
        theme = self.factory.dock_theme or self.item.container.dock_theme
        dw = DockWindow(parent, theme=theme)
        self.control = dw.control
        self._sizer = DockSizer(DockSection(dock_window=dw))
        self.control.SetSizer(self._sizer)

        # Set up the additional 'list items changed' event handler needed for
        # a list based trait:
        self.context_object.on_trait_change(self.update_editor_item,
                                            self.extended_name + '_items?',
                                            dispatch='ui')

        # Set of selection synchronization:
        self.sync_value(self.factory.selected, 'selected')

    #---------------------------------------------------------------------------
    #  Updates the editor when the object trait changes external to the editor:
    #---------------------------------------------------------------------------

    def update_editor(self):
        """ Updates the editor when the object trait changes externally to the
            editor.
        """
        # Make sure the DockWindow is in a correct state:
        self._sizer.Reset(self.control)

        # Destroy the views on each current notebook page:
        self.close_all()

        # Create a DockControl for each object in the trait's value:
        uis = self._uis
        dock_controls = []
        for object in self.value:
            dock_control, view_object, monitoring = self._create_page(object)
            # Remember the DockControl for later deletion processing:
            uis.append([dock_control, object, view_object, monitoring])
            dock_controls.append(dock_control)

        # Add the new items to the DockWindow:
        self.add_controls(dock_controls)

        if self.ui.info.initialized:
            self.update_layout()

    #---------------------------------------------------------------------------
    #  Handles some subset of the trait's list being updated:
    #---------------------------------------------------------------------------

    def update_editor_item(self, event):
        """ Handles an update to some subset of the trait's list.
        """
        # Make sure the DockWindow is in a correct state:
        self._sizer.Reset(self.control)

        index = event.index

        # Delete the page corresponding to each removed item:
        layout = ((len(event.removed) + len(event.added)) <= 1)
        for i in range(len(event.removed)):
            dock_control, object, view_object, monitoring = self._uis[index]
            if monitoring:
                view_object.on_trait_change(self.update_page_name,
                                            self.factory.page_name[1:],
                                            remove=True)
            dock_control.close(layout=layout, force=True)
            del self._uis[index]

        # Add a page for each added object:
        dock_controls = []
        for object in event.added:
            dock_control, view_object, monitoring = self._create_page(object)
            self._uis[index:index] = [[
                dock_control, object, view_object, monitoring
            ]]
            dock_controls.append(dock_control)
            index += 1

        # Add the new items to the DockWindow:
        self.add_controls(dock_controls)

        self.update_layout()

    #---------------------------------------------------------------------------
    #  Closes all currently open notebook pages:
    #---------------------------------------------------------------------------

    def close_all(self):
        """ Closes all currently open notebook pages.
        """
        page_name = self.factory.page_name[1:]
        for dock_control, object, view_object, monitoring in self._uis:
            if monitoring:
                view_object.on_trait_change(self.update_page_name,
                                            page_name,
                                            remove=True)
            dock_control.close(layout=False, force=True)

        # Reset the list of ui's and dictionary of page name counts:
        self._uis = []
        self._pages = {}

    #---------------------------------------------------------------------------
    #  Disposes of the contents of an editor:
    #---------------------------------------------------------------------------

    def dispose(self):
        """ Disposes of the contents of an editor.
        """
        self.context_object.on_trait_change(self.update_editor_item,
                                            self.name + '_items?',
                                            remove=True)
        self.close_all()

        super(NotebookEditor, self).dispose()

    #---------------------------------------------------------------------------
    #  Adds a group of new DockControls to the view:
    #---------------------------------------------------------------------------

    def add_controls(self, controls):
        """ Adds a group of new DockControls to the view.
        """
        if len(controls) > 0:
            section = self.control.GetSizer().GetContents()
            if ((len(section.contents) == 0)
                    or (not isinstance(section.contents[-1], DockRegion))):
                section.contents.append(DockRegion(contents=controls))
            else:
                for control in controls:
                    section.contents[-1].add(control, activate=False)
            # Fire this event to activate the dock control corresponding
            # to the selected object, if any.
            self._selected_changed(None, self.selected)

    #---------------------------------------------------------------------------
    #  Updates the layout of the DockWindow:
    #---------------------------------------------------------------------------

    def update_layout(self):
        """ Updates the layout of the DockWindow.
        """
        self.control.Layout()
        self.control.Refresh()

    #---------------------------------------------------------------------------
    #  Handles the trait defining a particular page's name being changed:
    #---------------------------------------------------------------------------

    def update_page_name(self):
        """ Handles the trait defining a particular page's name being changed.
        """
        changed = False
        for i, value in enumerate(self._uis):
            dock_control, user_object, view_object, monitoring = value
            if dock_control.control is not None:
                name = None
                handler = getattr(
                    self.ui.handler,
                    '%s_%s_page_name' % (self.object_name, self.name), None)
                if handler is not None:
                    name = handler(self.ui.info, user_object)

                if name is None:
                    name = unicode(
                        xgetattr(view_object, self.factory.page_name[1:],
                                 u'???'))

                changed |= (dock_control.name != name)
                dock_control.name = name

        if changed:
            self.update_layout()

    #---------------------------------------------------------------------------
    #  Creates a DockControl for a specified object:
    #---------------------------------------------------------------------------

    def _create_page(self, object):
        """ Creates a DockControl for a specified object.
        """
        # Create the view for the object:
        view_object = object
        factory = self.factory
        if factory.factory is not None:
            view_object = factory.factory(object)

        ui = view_object.edit_traits(parent=self.control,
                                     view=factory.view,
                                     kind=factory.ui_kind).set(parent=self.ui)

        # Get the name of the page being added to the notebook:
        name = ''
        monitoring = False
        prefix = '%s_%s_page_' % (self.object_name, self.name)
        page_name = self.factory.page_name
        if page_name[0:1] == '.':
            name = xgetattr(view_object, page_name[1:], None)
            monitoring = (name is not None)
            if monitoring:
                handler_name = None
                method = getattr(self.ui.handler, prefix + 'name', None)
                if method is not None:
                    handler_name = method(self.ui.info, object)
                if handler_name is not None:
                    name = handler_name
                else:
                    name = unicode(name) or u'???'
                view_object.on_trait_change(self.update_page_name,
                                            page_name[1:],
                                            dispatch='ui')
            else:
                name = ''
        elif page_name != '':
            name = page_name

        if name == '':
            name = user_name_for(view_object.__class__.__name__)

        # Make sure the name is not a duplicate:
        if not monitoring:
            self._pages[name] = count = self._pages.get(name, 0) + 1
            if count > 1:
                name += (' %d' % count)

        # Return a new DockControl for the ui, and whether or not its name is
        # being monitored:
        image = None
        method = getattr(self.ui.handler, prefix + 'image', None)
        if method is not None:
            image = method(self.ui.info, object)
        dock_control = DockControl(control=ui.control,
                                   id=str(id(ui.control)),
                                   name=name,
                                   style=factory.dock_style,
                                   image=image,
                                   export=factory.export,
                                   closeable=factory.deletable,
                                   dockable=DockableListElement(ui=ui,
                                                                editor=self))
        return (dock_control, view_object, monitoring)

    #---------------------------------------------------------------------------
    #  Activates the corresponding dock window when the 'selected' trait of
    #  the editor is changed.
    #---------------------------------------------------------------------------
    def _selected_changed(self, old, new):
        """ Activates the corresponding dock window when the 'selected' trait
        of the editor is changed.
        """
        for i, value in enumerate(self._uis):
            if new == value[1]:
                value[0].activate()
                break
        return