Source code for apptools.preferences.ui.preferences_manager

# (C) Copyright 2005-2024 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
""" The preferences manager. """


# Enthought library imports.
from traits.api import HasTraits, Instance, List, Property, Bool
from traitsui.api import Handler, HSplit, Item, TreeEditor
from traitsui.api import TreeNode, View, HTMLEditor
from traitsui.menu import Action

# Local imports.
from .preferences_node import PreferencesNode
from .preferences_page import PreferencesPage


# A tree editor for preferences nodes.
tree_editor = TreeEditor(
    nodes=[
        TreeNode(
            node_for=[PreferencesNode],
            auto_open=False,
            children="children",
            label="name",
            rename=False,
            copy=False,
            delete=False,
            insert=False,
            menu=None,
        ),
    ],
    editable=False,
    hide_root=True,
    selected="selected_node",
    show_icons=False,
)


[docs]class PreferencesHelpWindow(HasTraits): """ Container class to present a view with string info. """
[docs] def traits_view(self): """ Default view to show for this class. """ args = [] kw_args = { "title": "Preferences Page Help", "buttons": ["OK"], "width": 800, "height": 800, "resizable": True, "id": "apptools.preferences.ui.preferences_manager.help", } to_show = {} for name, trait_obj in self.traits().items(): if name != "trait_added" and name != "trait_modified": to_show[name] = trait_obj.help for name in to_show: args.append(Item(name, style="readonly", editor=HTMLEditor())) view = View(*args, **kw_args) return view
[docs]class PreferencesManagerHandler(Handler): """ The traits UI handler for the preferences manager. """ model = Instance(HasTraits) ########################################################################### # 'Handler' interface. ###########################################################################
[docs] def apply(self, info): """ Handle the **Apply** button being clicked. """ info.object.apply()
[docs] def init(self, info): """ Initialize the controls of a user interface. """ # Select the first node in the tree (if there is one). self._select_first_node(info) return super(PreferencesManagerHandler, self).init(info)
[docs] def close(self, info, is_ok): """ Close a dialog-based user interface. """ if is_ok: info.object.apply() return super(PreferencesManagerHandler, self).close(info, is_ok)
[docs] def preferences_help(self, info): """ Custom preferences help panel. The Traits help doesn't work.""" current_page = self.model.selected_page to_show = {} for trait_name, trait_obj in current_page.traits().items(): if hasattr(trait_obj, "show_help") and trait_obj.show_help: to_show[trait_name] = trait_obj.help help_obj = PreferencesHelpWindow(**to_show) help_obj.edit_traits(kind="livemodal")
########################################################################### # Private interface. ########################################################################### def _select_first_node(self, info): """ Select the first node in the tree (if there is one). """ root = info.object.root if len(root.children) > 0: node = root.children[0] info.object.selected_page = node.page
[docs]class PreferencesManager(HasTraits): """ The preferences manager. """ # All of the preferences pages known to the manager. pages = List(PreferencesPage) # The root of the preferences node tree. root = Property(Instance(PreferencesNode)) # The preferences node currently selected in the tree. selected_node = Instance(PreferencesNode) # The preferences associated with the currently selected preferences node. selected_page = Instance(PreferencesPage) # Should the custom Info button be shown? If this is True, then an # Info button is shown that pops up a trait view with an HTML entry # for each trait of the *selected_page* with the metadata 'show_help' # set to True. show_help = Bool(False) # Should the Apply button be shown? show_apply = Bool(False) #### Traits UI views ######################################################
[docs] def traits_view(self): """ Default traits view for this class. """ help_action = Action(name="Info", action="preferences_help") buttons = ["OK", "Cancel"] if self.show_apply: buttons = ["Apply"] + buttons if self.show_help: buttons = [help_action] + buttons # A tree editor for preferences nodes. tree_editor = TreeEditor( nodes=[ TreeNode( node_for=[PreferencesNode], auto_open=False, children="children", label="name", rename=False, copy=False, delete=False, insert=False, menu=None, ), ], on_select=self._selection_changed, editable=False, hide_root=True, selected="selected_node", show_icons=False, ) view = View( HSplit( Item( name="root", editor=tree_editor, show_label=False, width=250, ), Item( name="selected_page", # editor = WidgetEditor(), show_label=False, width=450, style="custom", ), ), buttons=buttons, handler=PreferencesManagerHandler(model=self), resizable=True, title="Preferences", width=0.3, height=0.3, kind="modal", ) self.selected_page = self.pages[0] return view
########################################################################### # 'PreferencesManager' interface. ########################################################################### #### Trait properties ##################################################### def _get_root(self): """ Property getter. """ # Sort the pages by the length of their category path. This makes it # easy for us to create the preference hierarchy as we know that all of # a node's ancestors will have already been created. def sort_key(a): # We have the guard because if the category is the empty string # then split will still return a list containing one item (and not # the empty list). if len(a.category) == 0: len_a = 0 else: len_a = len(a.category.split("/")) return len_a self.pages.sort(key=sort_key) # Create a corresponding preference node hierarchy (the root of the # hierachy is NOT displayed in the preference dialog). # # fixme: Currently we have to create a dummy page for the root node # event though the root does not get shown in the tree! root_page = PreferencesPage(name="Root", preferences_path="root") root = PreferencesNode(page=root_page) for page in self.pages: # Get the page's parent node. parent = self._get_parent(root, page) # Add a child node representing the page. parent.append(PreferencesNode(page=page)) return root #### Trait change handlers ################################################ def _selection_changed(self, new_selection): self.selected_node = new_selection def _selected_node_changed(self, new): """ Static trait change handler. """ if self.selected_node: self.selected_page = self.selected_node.page #### Methods ##############################################################
[docs] def apply(self): """ Apply all changes made in the manager. """ for page in self.pages: page.apply()
########################################################################### # Private interface. ########################################################################### def _get_parent(self, root, page): """ Return the page's parent preference node. """ parent = root if len(page.category) > 0: components = page.category.split("/") for component in components: parent = parent.lookup(component) return parent