/[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 381 by jonathan, Tue Jan 28 18:37: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 13  to data. This mapping can be specified i Line 13  to data. This mapping can be specified i
13  First, specific values can be associated with data.  First, specific values can be associated with data.
14  Second, ranges can be associated with data such that if  Second, ranges can be associated with data such that if
15  an input value falls with a range that data is returned.  an input value falls with a range that data is returned.
16  If no mapping can be found then a NullData 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    import copy, operator, types
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    from Thuban.Model.color import Color, Transparent, Black
34    from Thuban.Model.range import Range
35    
36    import Thuban.Model.layer
37    
38    from Thuban.Lib.connector import Publisher
39    
40    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        def __init__(self):
49            """Initialize a classification."""
50    
51            self.__groups = []
52    
53            self.SetDefaultGroup(ClassGroupDefault())
54    
55        def __iter__(self):
56            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  # constants      def _compile_classification(self):
80  RANGE_MIN  = 0          """Generate the compiled classification
 RANGE_MAX  = 1  
 RANGE_DATA = 2  
81    
82  class Classification:          The compiled classification is a more compact representation of
83            the classification groups that is also more efficient for
84            performing the classification.
85    
86            The compiled classification is a list of tuples. The first
87            element of the tuple is a string which describes the rest of the
88            tuple. There are two kinds of tuples:
89    
90      def __init__(self, field = None):            'singletons'
         """Initialize a classification.  
91    
92             field -- the name of the data table field that              The second element of the tuple is a dictionary which
93                      is to be used to classify layer properties              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          self.points = {}          for group in self.__groups[1:]:
116          self.ranges = []              if isinstance(group, ClassGroupSingleton):
117          self.setField(field)                  if not compiled or compiled[-1][0] != "singletons":
118          self.setNull(None)                      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            If will be created on demand when self._compiled_classification
139            is accessed again.
140    
141            Call this method whenever self.__groups is modified.
142            """
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):
155            """Set the default fill color.
156    
157            fill -- a Color object.
158            """
159            self.GetDefaultGroup().GetProperties().SetFill(fill)
160            self.__SendNotification()
161            
162        def GetDefaultFill(self):
163            """Return the default fill color."""
164            return self.GetDefaultGroup().GetProperties().GetFill()
165            
166        def SetDefaultLineColor(self, color):
167            """Set the default line color.
168    
169            color -- a Color object.
170            """
171            self.GetDefaultGroup().GetProperties().SetLineColor(color)
172            self.__SendNotification()
173            
174        def GetDefaultLineColor(self):
175            """Return the default line color."""
176            return self.GetDefaultGroup().GetProperties().GetLineColor()
177            
178        def SetDefaultLineWidth(self, lineWidth):
179            """Set the default line width.
180    
181            lineWidth -- an integer > 0.
182            """
183            assert isinstance(lineWidth, types.IntType)
184            self.GetDefaultGroup().GetProperties().SetLineWidth(lineWidth)
185            self.__SendNotification()
186                    
187      def setField(self, field):      def GetDefaultLineWidth(self):
188          """Set the name of the data table field to use.          """Return the default line width."""
189                    return self.GetDefaultGroup().GetProperties().GetLineWidth()
190             field -- if None then all values map to NullData          
191    
192        #
193        # 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        # 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        def SetDefaultGroup(self, group):
201            """Set the group to be used when a value can't be classified.
202    
203            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        def AppendGroup(self, item):
217            """Append a new ClassGroup item to the classification.
218    
219            item -- this must be a valid ClassGroup object
220            """
221    
222            self.InsertGroup(self.GetNumGroups(), item)
223    
224        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        def FindGroup(self, value):
250            """Return the group that matches the value.
251    
252            Groups are effectively checked in the order the were added to
253            the Classification.
254    
255            value -- the value to classify. If there is no mapping or value
256                     is None, return the default properties
257          """          """
258    
259          self.field = field          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            return self.GetDefaultGroup()
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            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):
287            items = []
288    
289            def build_color_item(text, color):
290                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()
305                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            for p in self:
315                items.append(build_item(p, p.GetDisplayText()))
316    
317            return (_("Classification"), items)
318    
319    class ClassIterator:
320        """Allows the Groups in a Classifcation to be interated over.
321    
322        The items are returned in the following order:
323            default data, singletons, ranges, maps
324        """
325    
326        def __init__(self, data): #default, points, ranges, maps):
327            """Constructor.
328    
329            default -- the default group
330    
331            points -- a list of singleton groups
332    
333      def setNull(self, data):          ranges -- a list of range groups
         """Set the data to be used when a value can't be classified.  
334    
335             data -- data that the value maps to. See class description.          maps -- a list of map groups
336          """          """
337    
338          self.NullData = data          self.data = data
339            self.data_index = 0
340    
341      def addRange(self, min, max, data):      def __iter__(self):
342          """Add a new range to the classification.          return self
343    
344             A range allows a value to be classified if it falls between      def next(self):
345             min and max. Specifically, min <= value < max          """Return the next item."""
           
            min -- the lower bound.  
346    
347             max -- the upper bound.          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             data -- data that the value maps to. See class description.  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 min >= max:          if props is not None:
372              raise ValueError(_("Range minimum >= maximum!"))              self.SetProperties(props)
373          self.ranges.append([min, max, data])          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      def addPoint(self, value, data):          color -- the color of the line. This must be a Color object.
396          """Associate a single value with data.          """
397    
398             When this value is to be classified data will be returned.          self.__stroke = color
399    
400             value -- classification value.      def GetLineWidth(self):
401            """Return the line width."""
402            return self.__strokeWidth
403    
404             data  -- data that the value maps to. See class description.      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.points[value] = data          self.__strokeWidth = lineWidth
414    
415      def getProperties(self, value):      def GetSize(self):
416          """Return the associated data, or the NullData.          """Return the size."""
417            return self.__size
418    
419             The following search technique is used:      def SetSize(self, size):
420                 (1) if the field is None, return NullData          """Set the size.
                (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.  
421    
422             value -- the value to classify. If there is no mapping          size -- the new size. This must be > 0.
                     return the NullData (which may be None)  
423          """          """
424            assert isinstance(size, types.IntType)
425            if (size < 1):
426                raise ValueError(_("size < 1"))
427    
428          if self.field is not None:          self.__size = size
             #  
             # first check the discrete values  
             #  
             if self.points.has_key(value):  
                 return self.points[value]  
429    
430              #      def GetFill(self):
431              # now check the ranges          """Return the fill color as a Color object."""
432              #          return self.__fill
             for p in self.ranges:  
                 if (p[RANGE_MIN] <= value) and (value < p[RANGE_MAX]):  
                     return p[RANGE_DATA]  
433    
434        def SetFill(self, fill):
435            """Set the fill color.
436    
437          return self.NullData          fill -- the color of the fill. This must be a Color object.
438            """
439    
440      def TreeInfo(self):          self.__fill = fill
441          items = []  
442        def __eq__(self, other):
443            """Return true if 'props' has the same attributes as this class"""
444    
445          #          #
446          # shouldn't print anything if there are no classifications          # 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          def color_string(color):      """A base class for all Groups within a Classification"""
             if color is None:  
                 return "None"  
             return "(%.3f, %.3f, %.3f)" % (color.red, color.green, color.blue)  
472    
473          if self.NullData is not None:      def __init__(self, label = "", props = None, group = None):
474              i = []          """Constructor.
             for key, value in self.NullData.items():  
                 if isinstance(value, Color):  
                     i.append((_("%s: %s") % (key, color_string(value)), value))  
                 else:  
                     i.append(_("%s: %s") % (key, value))  
             items.append((_("'NULL'"), i))  
475    
476          for name, data in self.points.items():          label -- A string representing the Group's label
477              i = []          """
             for key, value in data.items():  
                 if isinstance(value, Color):  
                     i.append((_("%s: %s") % (key, color_string(value)), value))  
                 else:  
                     i.append(_("%s: %s") % (key, value))  
             items.append((_("%s") % name, i))  
478    
479          for p in self.ranges:          if group is not None:
480              i = []              self.SetLabel(copy.copy(group.GetLabel()))
481              data = p[RANGE_DATA]              self.SetProperties(copy.copy(group.GetProperties()))
482              for key, value in data.items():              self.SetVisible(group.IsVisible())
483                  if isinstance(value, Color):          else:
484                      i.append((_("%s: %s") % (key, color_string(value)), value))              self.SetLabel(label)
485                  else:              self.SetProperties(props)
486                      i.append(_("%s: %s") % (key, value))              self.SetVisible(True)
487              items.append((_("%s-%s") % (p[RANGE_MIN], p[RANGE_MAX], i)))  
488              def GetLabel(self):
489          return (_("Classifications"), items)          """Return the Group's label."""
490            return self.label
491    
492        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
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.381  
changed lines
  Added in v.2374

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26