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
|
# (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__)
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?
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)
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
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
|