Source code for pyface.tree.node_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!

""" The node manager looks after a collection of node types. """


import logging


from traits.api import HasPrivateTraits, List, observe


from .node_type import NodeType


# Create a logger for this module.
logger = logging.getLogger(__name__)


[docs]class NodeManager(HasPrivateTraits): """ The node manager looks after a collection of node types. """ # 'NodeManager' interface -----------------------------------------# # All registered node types. node_types = List(NodeType) # fixme: Where should the system actions go? The node tree, the node # tree model, here?!? system_actions = List() # ------------------------------------------------------------------------ # 'object' interface. # ------------------------------------------------------------------------ def __init__(self, **traits): """ Creates a new tree model. """ # Base class constructor. super().__init__(**traits) # This saves looking up a node's type every time. If we ever have # nodes that change type dynamically then we will obviously have to # re-think this (although we should probably re-think dynamic type # changes first ;^). self._node_to_type_map = {} # { Any node : NodeType node_type } return # ------------------------------------------------------------------------ # 'NodeManager' interface. # ------------------------------------------------------------------------ # fixme: This is the only API call that we currently have that manipulates # the manager's node types. Should we make the 'node_types' list # available via the public API?
[docs] def add_node_type(self, node_type): """ Adds a new node type to the manager. """ node_type.node_manager = self self.node_types.append(node_type)
[docs] def get_node_type(self, node): """ Returns the node's type. Returns None if none of the manager's node types recognize the node. """ # Generate the key for the node to type map. key = self.get_key(node) # Check the cache first. node_type = self._node_to_type_map.get(key, None) if node_type is None: # If we haven't seen this node before then attempt to find a node # type that 'recognizes' it. # # fixme: We currently take the first node type that recognizes the # node. This obviously means that ordering of node types is # important, but we don't have an interface for controlling the # order. Maybe sort on some 'precedence' trait on the node type? for node_type in self.node_types: if node_type.is_type_for(node): self._node_to_type_map[key] = node_type break else: node_type = None if node_type is None: logger.warning("no node type for %s" % str(node)) return node_type
[docs] def get_key(self, node): """ Generates a unique key for a node. In this case, 'unique' means unqiue within the node manager. """ # We do it like this 'cos, for example, using id() on a string doesn't # give us what we want, but things like lists aren't hashable, so we # can't always use hash()). try: key = hash(node) except: key = id(node) return key
# ------------------------------------------------------------------------ # Private interface. # ------------------------------------------------------------------------ @observe("node_types") def _update_node_manager_on_new_node_types(self, event): """ Called when the entire list of node types has been changed. """ new = event.new for node_type in new: node_type.node_manager = self return