1
#------------------------------------------------------------------------------
3
# Copyright (c) 2005, Enthought, Inc.
6
# This software is provided without warranty under the terms of the BSD
7
# license included in enthought/LICENSE.txt and may be redistributed only
8
# under the conditions described in the aforementioned license. The license
9
# is also available online at http://www.enthought.com/licenses/BSD.txt
11
# Thanks for using Enthought open source!
13
# Author: David C. Morrill
16
#------------------------------------------------------------------------------
18
""" Define the ViewElements class, which is used to define a (typically
19
class-based) hierarchical name space of related ViewElement objects.
21
Normally there is a ViewElements object associated with each Traits-based
22
class, which contains all of the ViewElement objects associated with the
23
class. The ViewElements object is also linked to the ViewElements objects
24
of its associated class's parent classes.
27
#-------------------------------------------------------------------------------
29
#-------------------------------------------------------------------------------
31
from __future__ import absolute_import
33
from traits.api import HasStrictTraits, List, Dict, Str, Int, Any, TraitError
35
from traits.trait_base import enumerate
37
from .view_element import ViewElement
39
#-------------------------------------------------------------------------------
41
#-------------------------------------------------------------------------------
43
# Trait for contents of a ViewElements object
44
content_trait = Dict( str, ViewElement )
46
#-------------------------------------------------------------------------------
47
# 'ViewElements' class:
48
#-------------------------------------------------------------------------------
50
class ViewElements ( HasStrictTraits ):
51
""" Defines a hierarchical name space of related ViewElement objects.
53
#---------------------------------------------------------------------------
55
#---------------------------------------------------------------------------
57
# Dictionary containing the named ViewElement items
58
content = content_trait
60
#---------------------------------------------------------------------------
61
# Finds a specified ViewElement within the specified (optional) search
63
#---------------------------------------------------------------------------
65
def find ( self, name, stack = None ):
66
""" Finds a specified ViewElement within the specified (optional) search
69
# Assume search starts from the beginning the of the search order:
72
# If a stack was specified, see if there is a matching entry in the
77
# Match found, resume search at next ViewElements object
78
# in the search order:
82
# Search for a matching name starting at the specified ViewElements
83
# object in the search order:
84
for j, ves in enumerate( self._get_search_order()[i:] ):
85
result = ves.content.get( name )
86
if result is not None:
87
# Match found. If there is a stack, push matching name and
88
# ViewElements context onto it:
90
stack[0:0] = [ SearchStackItem( id = name,
93
# Return the ViewElement object that matched the name:
96
# Indicate no match was found:
99
#---------------------------------------------------------------------------
100
# Returns a sorted list of all names accessible from the ViewElements
101
# object that are of a specified (ViewElement) type:
102
#---------------------------------------------------------------------------
104
def filter_by ( self, klass = None ):
105
""" Returns a sorted list of all names accessible from the ViewElements
106
object that are of a specified (ViewElement) type.
113
# Add each item in the search order which is of the right class and
114
# which is not already in the result list:
115
for ves in self._get_search_order():
116
for name, ve in ves.content.items():
117
if isinstance( ve, klass ) and (name not in result):
118
result.append( name )
120
# Sort the resulting list of names:
126
#---------------------------------------------------------------------------
127
# Handles the 'parents' list being updated:
128
#---------------------------------------------------------------------------
130
def _parents__changed ( self ):
131
self._search_order = None
133
def _parents_items_changed ( self ):
134
self._search_order = None
136
#---------------------------------------------------------------------------
137
# Returns the current search order (computing it if necessary):
138
#---------------------------------------------------------------------------
140
def _get_search_order ( self ):
141
if self._search_order is None:
142
self._search_order = self._mro()
143
return self._search_order
145
#---------------------------------------------------------------------------
146
# Compute the Python 'C3' algorithm used to determine a class's 'mro'
147
# and apply it to the 'parents' of the ViewElements to determine the
148
# correct search order:
149
#---------------------------------------------------------------------------
154
[ parent._get_search_order()[:] for parent in self.parents ] +
155
[ self.parents[:] ] )
157
def _merge ( self, seqs ):
160
# Remove any empty sequences from the list:
161
seqs = [ seq for seq in seqs if len( seq ) > 0 ]
165
# Find merge candidates among the sequence heads:
168
if len( [ s for s in seqs if candidate in s[1:] ] ) == 0:
171
raise TraitError, "Inconsistent ViewElements hierarchy"
173
# Add the candidate to the result:
174
result.append( candidate )
176
# Then remove the candidate:
178
if seq[0] == candidate:
181
#---------------------------------------------------------------------------
182
# Returns a 'pretty print' version of the ViewElements object:
183
#---------------------------------------------------------------------------
185
def __repr__ ( self ):
186
""" Returns a "pretty print" version of the ViewElements object.
188
return self.content.__repr__()
190
#-------------------------------------------------------------------------------
191
# Define forward reference traits:
192
#-------------------------------------------------------------------------------
194
ViewElements.add_class_trait( 'parents', List( ViewElements ) )
195
ViewElements.add_class_trait( '_search_order', Any )
197
#-------------------------------------------------------------------------------
198
# 'SearchStackItem' class:
199
#-------------------------------------------------------------------------------
201
class SearchStackItem ( HasStrictTraits ):
203
#---------------------------------------------------------------------------
205
#---------------------------------------------------------------------------
207
# Name that was looked up
210
# Index into the 'mro' list of ViewElements that the ID was found in