Source code for pyface.action.action_manager

# (C) Copyright 2005-2023 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!

""" Abstract base class for all action managers. """


from traits.api import (
    Bool, Constant, Event, HasTraits, Instance, List, observe, Property, Str
)

from pyface.action.action_controller import ActionController
from pyface.action.group import Group


[docs]class ActionManager(HasTraits): """ Abstract base class for all action managers. An action manager contains a list of groups, with each group containing a list of items. There are currently three concrete sub-classes: 1) 'MenuBarManager' 2) 'MenuManager' 3) 'ToolBarManager' """ # 'ActionManager' interface -------------------------------------------- #: The Id of the default group. DEFAULT_GROUP = Constant("additions") #: The action controller (if any) used to control how actions are performed. controller = Instance(ActionController) #: Is the action manager enabled? enabled = Bool(True) #: All of the contribution groups in the manager. groups = Property(List(Instance(Group)), observe='_groups.items') #: The manager's unique identifier (if it has one). id = Str() #: Is the action manager visible? visible = Bool(True) # Events ---- #: fixme: We probably need more granular events than this! changed = Event() # Private interface ---------------------------------------------------- #: All of the contribution groups in the manager. _groups = List(Instance(Group)) # ------------------------------------------------------------------------ # 'object' interface. # ------------------------------------------------------------------------ def __init__(self, *args, **traits): """ Creates a new action manager. Parameters ---------- args : collection of strings, Group instances, or ActionManagerItem s Positional arguments are interpreted as Items or Groups managed by the action manager. Notes ----- If a Group is passed as a positional agrument then it is added to the manager and any subsequent Items arguments are appended to the Group until another Group is encountered. If a string is passed, a Group is created with id set to the string. """ # Base class constructor. super().__init__(**traits) # The last group in every manager is the group with Id 'additions'. # # fixme: The side-effect of this is to ensure that the 'additions' # group has been created. Is the 'additions' group even a good idea? group = self._get_default_group() # Add all items to the manager. for arg in args: # We allow a group to be defined by simply specifying a string (its # Id). if isinstance(arg, str): # Create a group with the specified Id. arg = Group(id=arg) # If the item is a group then add it just before the default group # (ie. we always keep the default group as the last group in the # manager). if isinstance(arg, Group): self.insert(-1, arg) group = arg # Otherwise, the item is an action manager item so add it to the # current group. else: group.append(arg) # ------------------------------------------------------------------------ # 'ActionManager' interface. # ------------------------------------------------------------------------ # Trait properties ----------------------------------------------------- def _get_groups(self): return self._groups[:] # Trait change handlers ------------------------------------------------ @observe('enabled') def _enabled_updated(self, event): for group in self._groups: group.enabled = event.new @observe('visible') def _visible_updated(self, event): for group in self._groups: group.visible = event.new # Methods -------------------------------------------------------------#
[docs] def append(self, item): """ Append an item to the manager. Parameters ---------- item : string, Group instance or ActionManagerItem The item to append. Notes ----- If the item is a group, the Group is appended to the manager's list of groups. It the item is a string, then a group is created with the string as the ``id`` and the new group is appended to the list of groups. If the item is an ActionManagerItem then the item is appended to the manager's default group. """ item = self._prepare_item(item) if isinstance(item, Group): group = self._groups else: group = self._get_default_group() group.append(item) return group
[docs] def destroy(self): """ Called when the manager is no longer required. By default this method simply calls 'destroy' on all of the manager's groups. """ for group in self.groups: group.destroy()
[docs] def insert(self, index, item): """ Insert an item into the manager at the specified index. Parameters ---------- index : int The position at which to insert the object item : string, Group instance or ActionManagerItem The item to insert. Notes ----- If the item is a group, the Group is inserted into the manager's list of groups. It the item is a string, then a group is created with the string as the ``id`` and the new group is inserted into the list of groups. If the item is an ActionManagerItem then the item is inserted into the manager's defualt group. """ item = self._prepare_item(item) if isinstance(item, Group): group = self._groups else: group = self._get_default_group() group.insert(index, item) return group
[docs] def find_group(self, id): """ Find a group with a specified Id. Parameters ---------- id : str The id of the group to find. Returns ------- group : Group The group which matches the id, or None if no such group exists. """ for group in self._groups: if group.id == id: return group else: return None
[docs] def find_item(self, path): """ Find an item using a path. Parameters ---------- path : str A '/' separated list of contribution Ids. Returns ------- item : ActionManagerItem or None Returns the matching ActionManagerItem, or None if any component of the path is not found. """ components = path.split("/") # If there is only one component, then the path is just an Id so look # it up in this manager. if len(components) > 0: item = self._find_item(components[0]) if len(components) > 1 and item is not None: item = item.find_item("/".join(components[1:])) else: item = None return item
[docs] def walk(self, fn): """ Walk the manager applying a function at every item. The components are walked in pre-order. Parameters ---------- fn : Callable A callable to apply to the tree of groups and items, starting with the manager. """ fn(self) for group in self._groups: self.walk_group(group, fn)
[docs] def walk_group(self, group, fn): """ Walk a group applying a function at every item. The components are walked in pre-order. Parameters ---------- group : Group The group to walk. fn : Callable A callable to apply to the tree of groups and items. """ fn(group) for item in group.items: if isinstance(item, Group): self.walk_group(item, fn) else: self.walk_item(item, fn)
[docs] def walk_item(self, item, fn): """ Walk an item (may be a sub-menu manager remember!). The components are walked in pre-order. Parameters ---------- item : item The item to walk. This may be a submenu or similar in addition to simple Action items. fn : Callable A callable to apply to the tree of items and subgroups. """ if hasattr(item, "groups"): item.walk(fn) else: fn(item)
# ------------------------------------------------------------------------ # Private interface. # ------------------------------------------------------------------------ def _get_default_group(self): """ Returns the manager's default group. This will create this group if it doesn't already exist. Returns ------- group : Group The manager's default group. """ group = self.find_group(self.DEFAULT_GROUP) if group is None: group = self._prepare_item(self.DEFAULT_GROUP) self._groups.append(group) return group def _prepare_item(self, item): """ Prepare an item to be added to this ActionManager. Parameters ---------- item : string, Group instance or ActionManagerItem The item to be added to this ActionManager Returns ------- item : Group or ActionManagerItem Modified item """ # 1) The item is a 'Group' instance. if isinstance(item, Group): item.parent = self # 2) The item is a string. elif isinstance(item, str): # Create a group with that Id. item = Group(id=item) item.parent = self return item def _find_item(self, id): """ Find an item with a spcified Id. Parameters ---------- id : str The id of the item to be found. Returns ------- item : ActionManagerItem or None Returns the item with the specified Id, or None if no such item exists. """ for group in self.groups: item = group.find(id) if item is not None: return item else: return None # ------------------------------------------------------------------------ # Debugging interface. # ------------------------------------------------------------------------
[docs] def dump(self, indent=""): """ Render a manager! """ print(indent, "Manager", self.id) indent += " " for group in self._groups: self.render_group(group, indent)
[docs] def render_group(self, group, indent=""): """ Render a group! """ print(indent, "Group", group.id) indent += " " for item in group.items: if isinstance(item, Group): print("Surely, a group cannot contain another group!!!!") self.render_group(item, indent) else: self.render_item(item, indent)
[docs] def render_item(self, item, indent=""): """ Render an item! """ if hasattr(item, "groups"): item.dump(indent) else: print(indent, "Item", item.id)