/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/classification.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/Model/classification.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 388 by jonathan, Mon Feb 10 15:25:05 2003 UTC revision 2374 by jan, Sun Oct 3 21:01:31 2004 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001 by Intevation GmbH  # Copyright (c) 2001, 2003 by Intevation GmbH
2  # Authors:  # Authors:
3  # Jonathan Coles <[email protected]>  # Jonathan Coles <[email protected]>
4  #  #
# Line 16  an input value falls with a range that d Line 16  an input value falls with a range that d
16  If no mapping can be found then default data will  If no mapping can be found then default data will
17  be returned. Input values must be hashable objects  be returned. Input values must be hashable objects
18    
19  See the description of getProperties() for more information  See the description of FindGroup() for more information
20  on the mapping algorithm.  on the mapping algorithm.
21  """  """
22        
23  from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \  import copy, operator, types
      LAYER_VISIBILITY_CHANGED  
24    
25  from Thuban import _  from Thuban import _
 from Thuban.Model.color import Color  
26    
27  from wxPython.wx import *  from messages import \
28        LAYER_PROJECTION_CHANGED, \
29        LAYER_LEGEND_CHANGED, \
30        LAYER_VISIBILITY_CHANGED,\
31        CLASS_CHANGED
32    
33  # constants  from Thuban.Model.color import Color, Transparent, Black
34  RANGE_MIN  = 0  from Thuban.Model.range import Range
 RANGE_MAX  = 1  
 RANGE_DATA = 2  
35    
36  class Classification:  import Thuban.Model.layer
37    
38      def __init__(self, layer, field = None):  from Thuban.Lib.connector import Publisher
         """Initialize a classification.  
39    
40             layer -- the layer object who owns this classification  class Classification(Publisher):
41        """Encapsulates the classification of layer.
42        
43        The Classification divides some kind of data into Groups which
44        are associated with properties. Later the properties can be
45        retrieved by matching data values to the appropriate group.
46        """
47    
48             field -- the name of the data table field that      def __init__(self):
49                      is to be used to classify layer properties          """Initialize a classification."""
         """  
50    
51          self.layer = layer          self.__groups = []
         self.points = {}  
         self.ranges = []  
         self.DefaultData = ClassData()  
         self.field = field  
         #self.SetField(field)  
52    
53      def SetField(self, field):          self.SetDefaultGroup(ClassGroupDefault())
54          """Set the name of the data table field to use.  
55                def __iter__(self):
56             field -- if None then all values map to the default data          return ClassIterator(self.__groups)
57          """  
58        def __deepcopy__(self, memo):
59            clazz = Classification()
60    
61            clazz.__groups[0] = copy.deepcopy(self.__groups[0])
62    
63            for i in range(1, len(self.__groups)):
64                clazz.__groups.append(copy.deepcopy(self.__groups[i]))
65    
66            return clazz
67    
68        def __SendNotification(self):
69            """Notify the layer that this class has changed."""
70            self.issue(CLASS_CHANGED)
71    
72        def __getattr__(self, attr):
73            """Generate the compiled classification on demand"""
74            if attr == "_compiled_classification":
75                self._compile_classification()
76                return self._compiled_classification
77            raise AttributeError(attr)
78    
79          self.field = field      def _compile_classification(self):
80          self.layer.changed(LAYER_LEGEND_CHANGED, self.layer)          """Generate the compiled classification
81    
82      def GetField(self):          The compiled classification is a more compact representation of
83          return self.field          the classification groups that is also more efficient for
84            performing the classification.
85    
86      def SetDefaultData(self, data):          The compiled classification is a list of tuples. The first
87          """Set the data to be used when a value can't be classified.          element of the tuple is a string which describes the rest of the
88            tuple. There are two kinds of tuples:
89    
90             data -- data that the value maps to. See class description.            'singletons'
91    
92                The second element of the tuple is a dictionary which
93                combines several consecutive ClassGroupSingleton instances.
94                The dictionary maps the values of the singletons (as
95                returned by the GetValue() method) to the corresponding
96                group.
97    
98              'range'
99    
100                The tuple describes a ClassGroupRange instance. The tuples
101                second element is a tuple fo the form (lfunc, min, max,
102                rfunc, group) where group is the original group object,
103                lfunc and rfuct are comparison functions and min and max are
104                lower and upper bounds of the range. Given a value and such
105                a tuple the group matches if and only if
106    
107                    lfunc(min, value) and rfunc(max, value)
108    
109                is true.
110    
111            The compiled classification is bound to
112            self._compile_classification.
113          """          """
114            compiled = []
115            for group in self.__groups[1:]:
116                if isinstance(group, ClassGroupSingleton):
117                    if not compiled or compiled[-1][0] != "singletons":
118                        compiled.append(("singletons", {}))
119                    compiled[-1][1].setdefault(group.GetValue(), group)
120                elif isinstance(group, ClassGroupRange):
121                    left, min, max, right = group.GetRangeTuple()
122                    if left == "[":
123                        lfunc = operator.le
124                    elif left == "]":
125                        lfunc = operator.lt
126                    if right == "[":
127                        rfunc = operator.gt
128                    elif right == "]":
129                        rfunc = operator.ge
130                    compiled.append(("range", (lfunc, min, max, rfunc, group)))
131                else:
132                    raise TypeError("Unknown group type %s", group)
133            self._compiled_classification = compiled
134    
135        def _clear_compiled_classification(self):
136            """Reset the compiled classification.
137    
138          self.DefaultData = data          If will be created on demand when self._compiled_classification
139            is accessed again.
140    
141      def GetDefaultData(self):          Call this method whenever self.__groups is modified.
142          return self.DefaultData          """
143            try:
144                del self._compiled_classification
145            except:
146                pass
147    
148        #
149        # these SetDefault* methods are really only provided for
150        # some backward compatibility. they should be considered
151        # for removal once all the classification code is finished.
152        #
153    
154      def SetDefaultFill(self, fill):      def SetDefaultFill(self, fill):
155          self.DefaultData.SetFill(fill)          """Set the default fill color.
156          self.layer.changed(LAYER_LEGEND_CHANGED, self.layer)  
157            fill -- a Color object.
158            """
159            self.GetDefaultGroup().GetProperties().SetFill(fill)
160            self.__SendNotification()
161                    
162      def GetDefaultFill(self):      def GetDefaultFill(self):
163          return self.DefaultData.GetFill()          """Return the default fill color."""
164            return self.GetDefaultGroup().GetProperties().GetFill()
165                    
166      def SetDefaultStroke(self, stroke):      def SetDefaultLineColor(self, color):
167          self.DefaultData.SetStroke(stroke)          """Set the default line color.
168          self.layer.changed(LAYER_LEGEND_CHANGED, self.layer)  
169            color -- a Color object.
170            """
171            self.GetDefaultGroup().GetProperties().SetLineColor(color)
172            self.__SendNotification()
173                    
174      def GetDefaultStroke(self):      def GetDefaultLineColor(self):
175          return self.DefaultData.GetStroke()          """Return the default line color."""
176            return self.GetDefaultGroup().GetProperties().GetLineColor()
177                    
178      def SetDefaultStrokeWidth(self, strokeWidth):      def SetDefaultLineWidth(self, lineWidth):
179          self.DefaultData.SetStrokeWidth(strokeWidth)          """Set the default line width.
180          self.layer.changed(LAYER_LEGEND_CHANGED, self.layer)  
181            lineWidth -- an integer > 0.
182            """
183            assert isinstance(lineWidth, types.IntType)
184            self.GetDefaultGroup().GetProperties().SetLineWidth(lineWidth)
185            self.__SendNotification()
186                    
187      def GetDefaultStrokeWidth(self):      def GetDefaultLineWidth(self):
188          return self.DefaultData.GetStrokeWidth()          """Return the default line width."""
189            return self.GetDefaultGroup().GetProperties().GetLineWidth()
190                    
     def AddRange(self, min, max, data):  
         """Add a new range to the classification.  
191    
192             A range allows a value to be classified if it falls between      #
193             min and max. Specifically, min <= value < max      # The methods that manipulate self.__groups have to be kept in
194                # sync. We store the default group in index 0 to make it
195             min -- the lower bound.      # convienent to iterate over the classification's groups, but
196        # from the user's perspective the first (non-default) group is
197        # at index 0 and the DefaultGroup is a special entity.
198        #
199    
200             max -- the upper bound.      def SetDefaultGroup(self, group):
201            """Set the group to be used when a value can't be classified.
202    
203             data -- data that the value maps to. See class description.          group -- group that the value maps to.
204          """          """
205            assert isinstance(group, ClassGroupDefault)
206            if len(self.__groups) > 0:
207                self.__groups[0] = group
208            else:
209                self.__groups.append(group)
210            self.__SendNotification()
211    
212        def GetDefaultGroup(self):
213            """Return the default group."""
214            return self.__groups[0]
215    
216          if min >= max:      def AppendGroup(self, item):
217              raise ValueError(_("Range minimum >= maximum!"))          """Append a new ClassGroup item to the classification.
         self.ranges.append([min, max, data])  
         self.layer.changed(LAYER_LEGEND_CHANGED, self.layer)  
218    
219      def AddPoint(self, value, data):          item -- this must be a valid ClassGroup object
220          """Associate a single value with data.          """
221    
222             When this value is to be classified data will be returned.          self.InsertGroup(self.GetNumGroups(), item)
223    
224             value -- classification value.      def InsertGroup(self, index, group):
225            assert isinstance(group, ClassGroup)
226            self.__groups.insert(index + 1, group)
227            self._clear_compiled_classification()
228            self.__SendNotification()
229    
230        def RemoveGroup(self, index):
231            """Remove the classification group with the given index"""
232            self.__groups.pop(index + 1)
233            self._clear_compiled_classification()
234            self.__SendNotification()
235    
236        def ReplaceGroup(self, index, group):
237            assert isinstance(group, ClassGroup)
238            self.__groups[index + 1] = group
239            self._clear_compiled_classification()
240            self.__SendNotification()
241    
242        def GetGroup(self, index):
243            return self.__groups[index + 1]
244    
245        def GetNumGroups(self):
246            """Return the number of non-default groups in the classification."""
247            return len(self.__groups) - 1
248    
249             data  -- data that the value maps to. See class description.      def FindGroup(self, value):
250          """          """Return the group that matches the value.
251    
252          self.points[value] = data          Groups are effectively checked in the order the were added to
253          self.layer.changed(LAYER_LEGEND_CHANGED, self.layer)          the Classification.
254    
255      def GetProperties(self, value):          value -- the value to classify. If there is no mapping or value
256          """Return the associated data, or the default data.                   is None, return the default properties
257            """
258    
259            if value is not None:
260                for typ, params in self._compiled_classification:
261                    if typ == "singletons":
262                        group = params.get(value)
263                        if group is not None:
264                            return group
265                    elif typ == "range":
266                        lfunc, min, max, rfunc, g = params
267                        if lfunc(min, value) and rfunc(max, value):
268                            return g
269    
270             The following search technique is used:          return self.GetDefaultGroup()
                (1) if the field is None, return the default data  
                (2) check if the value exists as a single value  
                (3) check if the value falls within a range. Ranges  
                    are checked in the order they were added to  
                    the classification.  
   
            value -- the value to classify. If there is no mapping,  
                     or value is None, return the default data  
                     (which may be None)  
         """  
   
         if self.field is not None and value is not None:  
             #  
             # first check the discrete values  
             #  
             if self.points.has_key(value):  
                 return self.points[value]  
   
             #  
             # now check the ranges  
             #  
             for p in self.ranges:  
                 if (p[RANGE_MIN] <= value) and (value < p[RANGE_MAX]):  
                     return p[RANGE_DATA]  
271    
272        def GetProperties(self, value):
273            """Return the properties associated with the given value.
274          
275            Use this function rather than Classification.FindGroup().GetProperties()
276            since the returned group may be a ClassGroupMap which doesn't support
277            a call to GetProperties().
278            """
279    
280          return self.DefaultData          group = self.FindGroup(value)
281            if isinstance(group, ClassGroupMap):
282                return group.GetPropertiesFromValue(value)
283            else:
284                return group.GetProperties()
285    
286      def TreeInfo(self):      def TreeInfo(self):
287          items = []          items = []
288    
289          #          def build_color_item(text, color):
290          # XXX: shouldn't print anything if there are no classifications              if color is Transparent:
291          #                  return ("%s: %s" % (text, _("None")), None)
292    
293                return ("%s: (%.3f, %.3f, %.3f)" %
294                        (text, color.red, color.green, color.blue),
295                        color)
296    
297            def build_item(group, string):
298                label = group.GetLabel()
299                if label == "":
300                    label = string
301                else:
302                    label += " (%s)" % string
303    
304                        props = group.GetProperties()
         def color_string(color):  
             if color is None:  
                 return "None"  
             return "(%.3f, %.3f, %.3f)" % (color.red, color.green, color.blue)  
   
         def build_item(data):  
305              i = []              i = []
306                v = props.GetLineColor()
307                i.append(build_color_item(_("Line Color"), v))
308                v = props.GetLineWidth()
309                i.append(_("Line Width: %s") % v)
310                v = props.GetFill()
311                i.append(build_color_item(_("Fill"), v))
312                return (label, i)
313    
314              v = data.GetStroke()          for p in self:
315              i.append((_("Stroke: %s") % color_string(v), v))              items.append(build_item(p, p.GetDisplayText()))
             v = data.GetStrokeWidth()  
             i.append((_("Stroke Width: %s") % v))  
             v = data.GetFill()  
             i.append((_("Fill: %s") % color_string(v), v))  
             return i  
   
         items.append((_("'DEFAULT'"), build_item(self.DefaultData)))  
   
         for name, data in self.points.items():  
             items.append((_("%s") % name, build_item(data)))  
   
         for p in self.ranges:  
             data = p[RANGE_DATA]  
             items.append((_("%s-%s") % (p[RANGE_MIN], p[RANGE_MAX])),  
                          build_item(data))  
316    
317          return (_("Classifications"), items)          return (_("Classification"), items)
   
318    
319  class ClassData:  class ClassIterator:
320        """Allows the Groups in a Classifcation to be interated over.
321    
322      def __init__(self):      The items are returned in the following order:
323          self.stroke = None          default data, singletons, ranges, maps
324          self.stroke_width = 0      """
325          self.fill = None  
326          self.label = ""      def __init__(self, data): #default, points, ranges, maps):
327                """Constructor.
328      def GetStroke(self):  
329          return self.stroke          default -- the default group
330    
331            points -- a list of singleton groups
332    
333      def SetStroke(self, stroke):          ranges -- a list of range groups
         self.stroke = stroke  
334    
335      def GetStrokeWidth(self):          maps -- a list of map groups
336          return self.stroke_width          """
337    
338            self.data = data
339            self.data_index = 0
340    
341        def __iter__(self):
342            return self
343    
344        def next(self):
345            """Return the next item."""
346    
347            if self.data_index >= len(self.data):
348                raise StopIteration
349            else:
350                d = self.data[self.data_index]
351                self.data_index += 1
352                return d
353    
354    class ClassGroupProperties:
355        """Represents the properties of a single Classification Group.
356    
357        These are used when rendering a layer."""
358    
359        # TODO: Actually, size is only relevant for point objects.
360        # Eventually it should be spearated, e.g. when introducing symbols.
361    
362        def __init__(self, props = None):
363            """Constructor.
364    
365            props -- a ClassGroupProperties object. The class is copied if
366                     prop is not None. Otherwise, a default set of properties
367                     is created such that: line color = Black, line width = 1,
368                     size = 5 and fill color = Transparent
369            """
370    
371            if props is not None:
372                self.SetProperties(props)
373            else:
374                self.SetLineColor(Black)
375                self.SetLineWidth(1)
376                self.SetSize(5)
377                self.SetFill(Transparent)
378    
379        def SetProperties(self, props):
380            """Set this class's properties to those in class props."""
381    
382            assert isinstance(props, ClassGroupProperties)
383            self.SetLineColor(props.GetLineColor())
384            self.SetLineWidth(props.GetLineWidth())
385            self.SetSize(props.GetSize())
386            self.SetFill(props.GetFill())
387    
388        def GetLineColor(self):
389            """Return the line color as a Color object."""
390            return self.__stroke
391    
392        def SetLineColor(self, color):
393            """Set the line color.
394    
395            color -- the color of the line. This must be a Color object.
396            """
397    
398            self.__stroke = color
399    
400        def GetLineWidth(self):
401            """Return the line width."""
402            return self.__strokeWidth
403    
404        def SetLineWidth(self, lineWidth):
405            """Set the line width.
406    
407            lineWidth -- the new line width. This must be > 0.
408            """
409            assert isinstance(lineWidth, types.IntType)
410            if (lineWidth < 1):
411                raise ValueError(_("lineWidth < 1"))
412    
413            self.__strokeWidth = lineWidth
414    
415      def SetStrokeWidth(self, stroke_width):      def GetSize(self):
416          self.stroke_width = stroke_width          """Return the size."""
417            return self.__size
418    
419        def SetSize(self, size):
420            """Set the size.
421    
422            size -- the new size. This must be > 0.
423            """
424            assert isinstance(size, types.IntType)
425            if (size < 1):
426                raise ValueError(_("size < 1"))
427    
428            self.__size = size
429    
430      def GetFill(self):      def GetFill(self):
431          return self.fill          """Return the fill color as a Color object."""
432            return self.__fill
433    
434      def SetFill(self, fill):      def SetFill(self, fill):
435          self.fill = fill          """Set the fill color.
436    
437            fill -- the color of the fill. This must be a Color object.
438            """
439    
440            self.__fill = fill
441    
442        def __eq__(self, other):
443            """Return true if 'props' has the same attributes as this class"""
444    
445            #
446            # using 'is' over '==' results in a huge performance gain
447            # in the renderer
448            #
449            return isinstance(other, ClassGroupProperties)   \
450                and (self.__stroke is other.__stroke or      \
451                     self.__stroke == other.__stroke)        \
452                and (self.__fill is other.__fill or          \
453                     self.__fill == other.__fill)            \
454                and self.__strokeWidth == other.__strokeWidth\
455                and self.__size == other.__size
456    
457        def __ne__(self, other):
458            return not self.__eq__(other)
459    
460        def __copy__(self):
461            return ClassGroupProperties(self)
462    
463        def __deepcopy__(self):
464            return ClassGroupProperties(self)
465    
466        def __repr__(self):
467            return repr((self.__stroke, self.__strokeWidth, self.__size,
468                        self.__fill))
469    
470    class ClassGroup:
471        """A base class for all Groups within a Classification"""
472    
473        def __init__(self, label = "", props = None, group = None):
474            """Constructor.
475    
476            label -- A string representing the Group's label
477            """
478    
479            if group is not None:
480                self.SetLabel(copy.copy(group.GetLabel()))
481                self.SetProperties(copy.copy(group.GetProperties()))
482                self.SetVisible(group.IsVisible())
483            else:
484                self.SetLabel(label)
485                self.SetProperties(props)
486                self.SetVisible(True)
487    
488      def GetLabel(self):      def GetLabel(self):
489            """Return the Group's label."""
490          return self.label          return self.label
491    
492      def SetLabel(self, label):      def SetLabel(self, label):
493            """Set the Group's label.
494    
495            label -- a string representing the Group's label. This must
496                     not be None.
497            """
498            assert isinstance(label, types.StringTypes)
499          self.label = label          self.label = label
500    
501        def GetDisplayText(self):
502            assert False, "GetDisplay must be overridden by subclass!"
503            return ""
504    
505        def Matches(self, value):
506            """Determines if this Group is associated with the given value.
507    
508            Returns False. This needs to be overridden by all subclasses.
509            """
510            assert False, "GetMatches must be overridden by subclass!"
511            return False
512    
513        def GetProperties(self):
514            """Return the properties associated with the given value."""
515    
516            return self.prop
517    
518        def SetProperties(self, prop):
519            """Set the properties associated with this Group.
520    
521            prop -- a ClassGroupProperties object. if prop is None,
522                    a default set of properties is created.
523            """
524    
525            if prop is None: prop = ClassGroupProperties()
526            assert isinstance(prop, ClassGroupProperties)
527            self.prop = prop
528    
529        def IsVisible(self):
530            return self.visible
531    
532        def SetVisible(self, visible):
533            self.visible = visible
534    
535        def __eq__(self, other):
536            return isinstance(other, ClassGroup) \
537                and self.label == other.label \
538                and self.GetProperties() == other.GetProperties()
539    
540        def __ne__(self, other):
541            return not self.__eq__(other)
542    
543        def __repr__(self):
544            return repr(self.label) + ", " + repr(self.GetProperties())
545        
546    class ClassGroupSingleton(ClassGroup):
547        """A Group that is associated with a single value."""
548    
549        def __init__(self, value = 0, props = None, label = "", group = None):
550            """Constructor.
551    
552            value -- the associated value.
553    
554            prop -- a ClassGroupProperites object. If prop is None a default
555                     set of properties is created.
556    
557            label -- a label for this group.
558            """
559            ClassGroup.__init__(self, label, props, group)
560    
561            self.SetValue(value)
562    
563        def __copy__(self):
564            return ClassGroupSingleton(self.GetValue(),
565                                       self.GetProperties(),
566                                       self.GetLabel())
567    
568        def __deepcopy__(self, memo):
569            return ClassGroupSingleton(self.GetValue(), group = self)
570    
571        def GetValue(self):
572            """Return the associated value."""
573            return self.__value
574    
575        def SetValue(self, value):
576            """Associate this Group with the given value."""
577            self.__value = value
578    
579        def Matches(self, value):
580            """Determine if the given value matches the associated Group value."""
581    
582            """Returns True if the value matches, False otherwise."""
583    
584            return self.__value == value
585    
586        def GetDisplayText(self):
587            label = self.GetLabel()
588    
589            if label != "": return label
590    
591            return str(self.GetValue())
592    
593        def __eq__(self, other):
594            return ClassGroup.__eq__(self, other) \
595                and isinstance(other, ClassGroupSingleton) \
596                and self.__value == other.__value
597    
598        def __repr__(self):
599            return "(" + repr(self.__value) + ", " + ClassGroup.__repr__(self) + ")"
600    
601    class ClassGroupDefault(ClassGroup):
602        """The default Group. When values do not match any other
603           Group within a Classification, the properties from this
604           class are used."""
605    
606        def __init__(self, props = None, label = "", group = None):
607            """Constructor.
608    
609            prop -- a ClassGroupProperites object. If prop is None a default
610                     set of properties is created.
611    
612            label -- a label for this group.
613            """
614    
615            ClassGroup.__init__(self, label, props, group)
616    
617        def __copy__(self):
618            return ClassGroupDefault(self.GetProperties(), self.GetLabel())
619    
620        def __deepcopy__(self, memo):
621            return ClassGroupDefault(label = self.GetLabel(), group = self)
622    
623        def Matches(self, value):
624            return True
625    
626        def GetDisplayText(self):
627            label = self.GetLabel()
628    
629            if label != "": return label
630    
631            return _("DEFAULT")
632    
633        def __eq__(self, other):
634            return ClassGroup.__eq__(self, other) \
635                and isinstance(other, ClassGroupDefault) \
636                and self.GetProperties() == other.GetProperties()
637    
638        def __repr__(self):
639            return "(" + ClassGroup.__repr__(self) + ")"
640    
641    class ClassGroupRange(ClassGroup):
642        """A Group that represents a range of values that map to the same
643           set of properties."""
644    
645        def __init__(self, _range = (0,1), props = None, label = "", group=None):
646            """Constructor.
647    
648            The minumum value must be strictly less than the maximum.
649    
650            _range -- either a tuple (min, max) where min < max or
651                      a Range object
652    
653            prop -- a ClassGroupProperites object. If prop is None a default
654                     set of properties is created.
655    
656            label -- a label for this group.
657            """
658    
659            ClassGroup.__init__(self, label, props, group)
660            self.SetRange(_range)
661    
662        def __copy__(self):
663            return ClassGroupRange(self.__range,
664                                   props = self.GetProperties(),
665                                   label = self.GetLabel())
666    
667        def __deepcopy__(self, memo):
668            return ClassGroupRange(copy.copy(self.__range),
669                                   group = self)
670    
671        def GetMin(self):
672            """Return the range's minimum value."""
673            return self.__range.GetRange()[1]
674    
675        def SetMin(self, min):
676            """Set the range's minimum value.
677        
678            min -- the new minimum. Note that this must be less than the current
679                   maximum value. Use SetRange() to change both min and max values.
680            """
681        
682            self.SetRange((min, self.__range.GetRange()[2]))
683    
684        def GetMax(self):
685            """Return the range's maximum value."""
686            return self.__range.GetRange()[2]
687    
688        def SetMax(self, max):
689            """Set the range's maximum value.
690        
691            max -- the new maximum. Note that this must be greater than the current
692                   minimum value. Use SetRange() to change both min and max values.
693            """
694            self.SetRange((self.__range.GetRange()[1], max))
695    
696        def SetRange(self, _range):
697            """Set a new range.
698    
699            _range -- Either a tuple (min, max) where min < max or
700                      a Range object.
701    
702            Raises ValueError on error.
703            """
704    
705            if isinstance(_range, Range):
706                self.__range = _range
707            elif isinstance(_range, types.TupleType) and len(_range) == 2:
708                self.__range = Range(("[", _range[0], _range[1], "["))
709            else:
710                raise ValueError()
711    
712        def GetRange(self):
713            """Return the range as a string"""
714            return self.__range.string(self.__range.GetRange())
715    
716        def GetRangeTuple(self):
717            return self.__range.GetRange()
718    
719        def Matches(self, value):
720            """Determine if the given value lies with the current range.
721    
722            The following check is used: min <= value < max.
723            """
724    
725            return operator.contains(self.__range, value)
726    
727        def GetDisplayText(self):
728            label = self.GetLabel()
729    
730            if label != "": return label
731    
732            return self.__range.string(self.__range.GetRange())
733    
734        def __eq__(self, other):
735            return ClassGroup.__eq__(self, other) \
736                and isinstance(other, ClassGroupRange) \
737                and self.__range == other.__range
738    
739        def __repr__(self):
740            return "(" + str(self.__range) + ClassGroup.__repr__(self) + ")"
741    
742    class ClassGroupMap(ClassGroup):
743        """Currently, this class is not used."""
744    
745        FUNC_ID = "id"
746    
747        def __init__(self, map_type = FUNC_ID, func = None, prop = None, label=""):
748            ClassGroup.__init__(self, label)
749    
750            self.map_type = map_type
751            self.func = func
752    
753            if self.func is None:
754                self.func = func_id
755    
756        def Map(self, value):
757            return self.func(value)
758    
759        def GetProperties(self):
760            return None
761    
762        def GetPropertiesFromValue(self, value):
763            pass
764    
765        def GetDisplayText(self):
766            return "Map: " + self.map_type
767    
768        #
769        # built-in mappings
770        #
771        def func_id(value):
772            return value
773    

Legend:
Removed from v.388  
changed lines
  Added in v.2374

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26