~ubuntu-branches/ubuntu/utopic/python-traitsui/utopic

« back to all changes in this revision

Viewing changes to traitsui/view_elements.py

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath
  • Date: 2011-07-09 13:57:39 UTC
  • Revision ID: james.westby@ubuntu.com-20110709135739-x5u20q86huissmn1
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#------------------------------------------------------------------------------
 
2
#
 
3
#  Copyright (c) 2005, Enthought, Inc.
 
4
#  All rights reserved.
 
5
#
 
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
 
10
#
 
11
#  Thanks for using Enthought open source!
 
12
#
 
13
#  Author: David C. Morrill
 
14
#  Date:   10/18/2004
 
15
#
 
16
#------------------------------------------------------------------------------
 
17
 
 
18
""" Define the ViewElements class, which is used to define a (typically
 
19
    class-based) hierarchical name space of related ViewElement objects.
 
20
 
 
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.
 
25
"""
 
26
 
 
27
#-------------------------------------------------------------------------------
 
28
#  Imports:
 
29
#-------------------------------------------------------------------------------
 
30
 
 
31
from __future__ import absolute_import
 
32
 
 
33
from traits.api import HasStrictTraits, List, Dict, Str, Int, Any, TraitError
 
34
 
 
35
from traits.trait_base import enumerate
 
36
 
 
37
from .view_element import ViewElement
 
38
 
 
39
#-------------------------------------------------------------------------------
 
40
#  Trait definitions:
 
41
#-------------------------------------------------------------------------------
 
42
 
 
43
# Trait for contents of a ViewElements object
 
44
content_trait = Dict( str, ViewElement )
 
45
 
 
46
#-------------------------------------------------------------------------------
 
47
#  'ViewElements' class:
 
48
#-------------------------------------------------------------------------------
 
49
 
 
50
class ViewElements ( HasStrictTraits ):
 
51
    """ Defines a hierarchical name space of related ViewElement objects.
 
52
    """
 
53
    #---------------------------------------------------------------------------
 
54
    #  Trait definitions:
 
55
    #---------------------------------------------------------------------------
 
56
 
 
57
    # Dictionary containing the named ViewElement items
 
58
    content = content_trait
 
59
 
 
60
    #---------------------------------------------------------------------------
 
61
    #  Finds a specified ViewElement within the specified (optional) search
 
62
    #  context:
 
63
    #---------------------------------------------------------------------------
 
64
 
 
65
    def find ( self, name, stack = None ):
 
66
        """ Finds a specified ViewElement within the specified (optional) search
 
67
            context.
 
68
        """
 
69
        # Assume search starts from the beginning the of the search order:
 
70
        i = 0
 
71
 
 
72
        # If a stack was specified, see if there is a matching entry in the
 
73
        # stack already:
 
74
        if stack is not None:
 
75
            for ssi in stack:
 
76
                if name == ssi.id:
 
77
                    # Match found, resume search at next ViewElements object
 
78
                    # in the search order:
 
79
                    i = ssi.context + 1
 
80
                    break
 
81
 
 
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:
 
89
                if stack is not None:
 
90
                    stack[0:0] = [ SearchStackItem( id      = name,
 
91
                                                    context = i + j ) ]
 
92
 
 
93
                # Return the ViewElement object that matched the name:
 
94
                return result
 
95
 
 
96
        # Indicate no match was found:
 
97
        return None
 
98
 
 
99
    #---------------------------------------------------------------------------
 
100
    #  Returns a sorted list of all names accessible from the ViewElements
 
101
    #  object that are of a specified (ViewElement) type:
 
102
    #---------------------------------------------------------------------------
 
103
 
 
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.
 
107
        """
 
108
        if klass is None:
 
109
            from . import view
 
110
            klass = view.View
 
111
        result = []
 
112
 
 
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 )
 
119
 
 
120
        # Sort the resulting list of names:
 
121
        result.sort()
 
122
 
 
123
        # Return the result:
 
124
        return result
 
125
 
 
126
    #---------------------------------------------------------------------------
 
127
    #  Handles the 'parents' list being updated:
 
128
    #---------------------------------------------------------------------------
 
129
 
 
130
    def _parents__changed ( self ):
 
131
        self._search_order = None
 
132
 
 
133
    def _parents_items_changed ( self ):
 
134
        self._search_order = None
 
135
 
 
136
    #---------------------------------------------------------------------------
 
137
    #  Returns the current search order (computing it if necessary):
 
138
    #---------------------------------------------------------------------------
 
139
 
 
140
    def _get_search_order ( self ):
 
141
        if self._search_order is None:
 
142
            self._search_order = self._mro()
 
143
        return self._search_order
 
144
 
 
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
    #---------------------------------------------------------------------------
 
150
 
 
151
    def _mro ( self ):
 
152
        return self._merge(
 
153
                  [ [ self ] ] +
 
154
                  [ parent._get_search_order()[:] for parent in self.parents ] +
 
155
                  [ self.parents[:] ] )
 
156
 
 
157
    def _merge ( self, seqs ):
 
158
        result = []
 
159
        while True:
 
160
            # Remove any empty sequences from the list:
 
161
            seqs = [ seq for seq in seqs if len( seq ) > 0 ]
 
162
            if len( seqs ) == 0:
 
163
                return result
 
164
 
 
165
            # Find merge candidates among the sequence heads:
 
166
            for seq in seqs:
 
167
                candidate = seq[0]
 
168
                if len( [ s for s in seqs if candidate in s[1:] ] ) == 0:
 
169
                    break
 
170
            else:
 
171
                raise TraitError, "Inconsistent ViewElements hierarchy"
 
172
 
 
173
            # Add the candidate to the result:
 
174
            result.append( candidate )
 
175
 
 
176
            # Then remove the candidate:
 
177
            for seq in seqs:
 
178
                if seq[0] == candidate:
 
179
                    del seq[0]
 
180
 
 
181
    #---------------------------------------------------------------------------
 
182
    #  Returns a 'pretty print' version of the ViewElements object:
 
183
    #---------------------------------------------------------------------------
 
184
 
 
185
    def __repr__ ( self ):
 
186
        """ Returns a "pretty print" version of the ViewElements object.
 
187
        """
 
188
        return self.content.__repr__()
 
189
 
 
190
#-------------------------------------------------------------------------------
 
191
#  Define forward reference traits:
 
192
#-------------------------------------------------------------------------------
 
193
 
 
194
ViewElements.add_class_trait( 'parents',       List( ViewElements ) )
 
195
ViewElements.add_class_trait( '_search_order', Any )
 
196
 
 
197
#-------------------------------------------------------------------------------
 
198
#  'SearchStackItem' class:
 
199
#-------------------------------------------------------------------------------
 
200
 
 
201
class SearchStackItem ( HasStrictTraits ):
 
202
 
 
203
    #---------------------------------------------------------------------------
 
204
    #  Trait definitions:
 
205
    #---------------------------------------------------------------------------
 
206
 
 
207
    # Name that was looked up
 
208
    id = Str
 
209
 
 
210
    # Index into the 'mro' list of ViewElements that the ID was found in
 
211
    context = Int
 
212