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)