1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
# (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!
#
# Author: Enthought, Inc.
# Description: <Enthought pyface package component>
import logging
from pyface.action.action import Action
from traits.api import Any, Str, observe, Undefined
# Logging.
logger = logging.getLogger(__name__)
class ListeningAction(Action):
""" An Action that listens and makes a callback to an object.
"""
# ListeningAction interface ----------------------------------------------
#: The (extended) name of the method to call. By default, the on_perform
#: function will be called with the event.
method = Str()
#: The (extended) name of the attribute that determines whether the action
#: is enabled. By default, the action is always enabled when an object is
#: set.
enabled_name = Str()
#: The (extended) name of the attribute that determines whether the action
#: is visible. By default, the action is always visible.
visible_name = Str()
#: The object to which the names above apply.
object = Any()
# -------------------------------------------------------------------------
# 'Action' interface.
# -------------------------------------------------------------------------
def destroy(self):
""" Called when the action is no longer required.
Removes all the task listeners.
"""
if self.object:
if self.enabled_name:
self.object.observe(
self._enabled_update, self.enabled_name, remove=True
)
if self.visible_name:
self.object.observe(
self._visible_update, self.visible_name, remove=True
)
def perform(self, event=None):
""" Call the appropriate function.
This looks for a method to call based on the extended method name
stored in the :py:attr:`method` trait. If the method is empty, then
this follows the usual Action method resolution.
"""
if self.method != "":
method = self._get_attr(self.object, self.method)
if method:
method()
else:
super().perform(event)
# -------------------------------------------------------------------------
# Protected interface.
# -------------------------------------------------------------------------
def _get_attr(self, obj, name, default=None):
""" Perform an extended look up of a dotted name. """
try:
for attr in name.split("."):
# Perform the access in the Trait name style: if the object is
# None, assume it simply hasn't been initialized and don't show
# the warning.
if obj is None:
return default
else:
obj = getattr(obj, attr)
except AttributeError:
logger.error("Did not find name %r on %r" % (attr, obj))
return default
return obj
# Trait change handlers --------------------------------------------------
@observe('enabled_name')
def _enabled_name_updated(self, event):
old, new = event.old, event.new
obj = self.object
if obj is not None:
if old:
obj.observe(self._enabled_update, old, remove=True)
if new:
obj.observe(self._enabled_update, new)
self._enabled_update()
@observe('visible_name')
def _visible_name_updated(self, event):
old, new = event.old, event.new
obj = self.object
if obj is not None:
if old:
obj.observe(self._visible_update, old, remove=True)
if new:
obj.observe(self._visible_update, new)
self._visible_update()
@observe('object')
def _object_updated(self, event):
old, new = event.old, event.new
for kind in ("enabled", "visible"):
method = getattr(self, "_%s_update" % kind)
name = getattr(self, "%s_name" % kind)
if name:
if old and old is not Undefined:
old.observe(method, name, remove=True)
if new:
new.observe(method, name)
method()
def _enabled_update(self, event=None):
if self.enabled_name:
if self.object:
self.enabled = bool(
self._get_attr(self.object, self.enabled_name, False)
)
else:
self.enabled = False
else:
self.enabled = bool(self.object)
def _visible_update(self, event=None):
if self.visible_name:
if self.object:
self.visible = bool(
self._get_attr(self.object, self.visible_name, False)
)
else:
self.visible = False
else:
self.visible = True
|