/[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 436 by jonathan, Thu Feb 27 15:53:03 2003 UTC revision 1912 by bh, Mon Nov 3 13:55:41 2003 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 GetClassData() for more information  See the description of FindGroup() for more information
20  on the mapping algorithm.  on the mapping algorithm.
21  """  """
22        
23  # fix for people using python2.1  import copy, operator, types
 from __future__ import nested_scopes  
24    
25  from types import *  from Thuban import _
26    
27  from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \  from messages import \
28       LAYER_VISIBILITY_CHANGED      LAYER_PROJECTION_CHANGED, \
29        LAYER_LEGEND_CHANGED, \
30        LAYER_VISIBILITY_CHANGED,\
31        CLASS_CHANGED
32    
33  from Thuban import _  from Thuban.Model.color import Color, Transparent, Black
34  from Thuban.Model.color import Color  from Thuban.Model.range import Range
35    
36  import Thuban.Model.layer  import Thuban.Model.layer
37    
38  from wxPython.wx import *  from Thuban.Lib.connector import Publisher
39    
40  # constants  class Classification(Publisher):
41  RANGE_MIN  = 0      """Encapsulates the classification of layer.
42  RANGE_MAX  = 1      
43  RANGE_DATA = 2      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  class Classification:      def __init__(self):
49            """Initialize a classification."""
50    
51            self.__groups = []
52    
53      def __init__(self, layer = None, field = None):          self.SetDefaultGroup(ClassGroupDefault())
         """Initialize a classification.  
54    
55             layer -- the layer object who owns this classification      def __iter__(self):
56            return ClassIterator(self.__groups)
57    
58             field -- the name of the data table field that      def __deepcopy__(self, memo):
59                      is to be used to classify layer properties          clazz = Classification()
         """  
   
         self.layer = None # stop message sending  
60    
61          self.SetDefaultGroup(ClassGroupDefault())          clazz.__groups[0] = copy.deepcopy(self.__groups[0])
         self.SetField(field)  
62    
63          self.layer = layer          for i in range(1, len(self.__groups)):
64          self.points = []              clazz.__groups.append(copy.deepcopy(self.__groups[i]))
         self.ranges = []  
         self.maps   = []  
65    
66      def __iter__(self):          return clazz
         return ClassIterator(self.DefaultGroup,  
                              self.points,  
                              self.ranges,  
                              self.maps)  
   
     def __SendMessage(self, message):  
         if self.layer is not None:  
             self.layer.changed(message, self.layer)  
       
     def SetField(self, field):  
         """Set the name of the data table field to use.  
           
            field -- if None then all values map to the default data  
         """  
67    
68          if field == "":      def __SendNotification(self):
69              field = None          """Notify the layer that this class has changed."""
70            self.issue(CLASS_CHANGED)
71    
72          self.field = field      def __getattr__(self, attr):
73          self.__SendMessage(LAYER_LEGEND_CHANGED)          """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      def GetField(self):      def _compile_classification(self):
80          return self.field          """Generate the compiled classification
81    
82      def SetLayer(self, layer):          The compiled classification is a more compact representation of
83          assert(isinstance(layer, Thuban.Model.layer.Layer))          the classification groups that is also more efficient for
84          self.layer = layer          performing the classification.
         self.__SendMessage(LAYER_LEGEND_CHANGED)  
85    
86      def GetLayer(self):          The compiled classification is a list of tuples. The first
87          return layer.self          element of the tuple is a string which describes the rest of the
88            tuple. There are two kinds of tuples:
89    
90      def SetDefaultGroup(self, group):            'singletons'
91          """Set the group to be used when a value can't be classified.  
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             group -- group that the value maps to. See class description.              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          assert(isinstance(group, ClassGroupDefault))      def _clear_compiled_classification(self):
136          self.DefaultGroup = group          """Reset the compiled classification.
137    
138      def GetDefaultGroup(self):          If will be created on demand when self._compiled_classification
139          return self.DefaultGroup          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      # these SetDefault* methods are really only provided for
# Line 113  class Classification: Line 152  class Classification:
152      #      #
153    
154      def SetDefaultFill(self, fill):      def SetDefaultFill(self, fill):
155          assert(isinstance(fill, Color))          """Set the default fill color.
156          self.DefaultGroup.GetProperties().SetFill(fill)  
157          self.__SendMessage(LAYER_LEGEND_CHANGED)          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.DefaultGroup.GetProperties().GetFill()          """Return the default fill color."""
164            return self.GetDefaultGroup().GetProperties().GetFill()
165                    
166      def SetDefaultStroke(self, stroke):      def SetDefaultLineColor(self, color):
167          assert(isinstance(stroke, Color))          """Set the default line color.
168          self.DefaultGroup.GetProperties().SetStroke(stroke)  
169          self.__SendMessage(LAYER_LEGEND_CHANGED)          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.DefaultGroup.GetProperties().GetStroke()          """Return the default line color."""
176            return self.GetDefaultGroup().GetProperties().GetLineColor()
177                    
178      def SetDefaultStrokeWidth(self, strokeWidth):      def SetDefaultLineWidth(self, lineWidth):
179          assert(isinstance(strokeWidth, IntType))          """Set the default line width.
180          self.DefaultGroup.GetProperties().SetStrokeWidth(strokeWidth)  
181          self.__SendMessage(LAYER_LEGEND_CHANGED)          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.DefaultGroup.GetProperties().GetStrokeWidth()          """Return the default line width."""
189            return self.GetDefaultGroup().GetProperties().GetLineWidth()
190                    
     def AddGroup(self, item):  
         assert(isinstance(item, ClassGroup))  
191    
192          if isinstance(item, ClassGroupDefault):      #
193              self.SetDefaultGroup(item)      # The methods that manipulate self.__groups have to be kept in
194          elif isinstance(item, ClassGroupSingleton):      # sync. We store the default group in index 0 to make it
195              self.points.append(item)      # convienent to iterate over the classification's groups, but
196          elif isinstance(item, ClassGroupRange):      # from the user's perspective the first (non-default) group is
197              self.ranges.append(item)      # at index 0 and the DefaultGroup is a special entity.
198          elif isinstance(item, ClassGroupMap):      #
199              self.maps.append(item)  
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:          else:
209              raise ValueError(_("Unrecognized ClassGroup"))              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          self.__SendMessage(LAYER_LEGEND_CHANGED)      def FindGroup(self, value):
250            """Return the group that matches the value.
251    
252      def GetGroup(self, value):          Groups are effectively checked in the order the were added to
253          """Return the associated data, or the default data.          the Classification.
254    
255             The following search technique is used:          value -- the value to classify. If there is no mapping or value
256                 (1) if the field is None, return the default data                   is None, return the default properties
257                 (2) check if the value exists as a single value          """
258                 (3) check if the value falls within a range. Ranges  
259                     are checked in the order they were added to          if value is not None:
260                     the classification.              for typ, params in self._compiled_classification:
261                    if typ == "singletons":
262             value -- the value to classify. If there is no mapping,                      group = params.get(value)
263                      or value is None, return the default properties                      if group is not None:
264          """                          return group
265                    elif typ == "range":
266          if self.field is not None and value is not None:                      lfunc, min, max, rfunc, g = params
267                        if lfunc(min, value) and rfunc(max, value):
268              for p in self:                          return g
                 if p.Matches(value):  
                     return p  
 #           #  
 #           # check the discrete values  
 #           #  
 #           if self.points.has_key(value):  
 #               return self.points[value]  
 #           #for p in self.points:  
 #               #if p.Value  
   
 #           #  
 #           # check the ranges  
 #           #  
 #           for p in self.ranges:  
 #               if p.InRange(value):  
 #                   return p  
   
 #           #  
 #           # check the maps  
 #           #  
 #           for p in self.maps:  
 #               try:  
 #                   return p.Map(value)  
 #               except: pass  
269    
270          return self.DefaultGroup          return self.GetDefaultGroup()
271    
272      def GetProperties(self, value):      def GetProperties(self, value):
273          return self.GetGroup(value).GetProperties()          """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):      def TreeInfo(self):
287          items = []          items = []
288    
289          def build_color_item(text, color):          def build_color_item(text, color):
290              if color is Color.None:              if color is Transparent:
291                  return ("%s: %s" % (text, _("None")), None)                  return ("%s: %s" % (text, _("None")), None)
292    
293              return ("%s: (%.3f, %.3f, %.3f)" %              return ("%s: (%.3f, %.3f, %.3f)" %
# Line 219  class Classification: Line 303  class Classification:
303    
304              props = group.GetProperties()              props = group.GetProperties()
305              i = []              i = []
306              v = props.GetStroke()              v = props.GetLineColor()
307              i.append(build_color_item(_("Stroke"), v))              i.append(build_color_item(_("Line Color"), v))
308              v = props.GetStrokeWidth()              v = props.GetLineWidth()
309              i.append(_("Stroke Width: %s") % v)              i.append(_("Line Width: %s") % v)
310              v = props.GetFill()              v = props.GetFill()
311              i.append(build_color_item(_("Fill"), v))              i.append(build_color_item(_("Fill"), v))
312              return (label, i)              return (label, i)
313    
314          for p in self:          for p in self:
315              if isinstance(p, ClassGroupDefault):              items.append(build_item(p, p.GetDisplayText()))
                 items.append(build_item(self.DefaultGroup, _("'DEFAULT'")))  
             elif isinstance(p, ClassGroupSingleton):  
                 items.append(build_item(p, str(p.GetValue())))  
             elif isinstance(p, ClassGroupRange):  
                 items.append(build_item(p, "%s - %s" %  
                                            (p.GetMin(), p.GetMax())))  
   
 #       for p in self.points.values():  
 #           items.append(build_item(p, str(p.GetValue())))  
   
 #       for p in self.ranges:  
 #           items.append(build_item(p, "%s - %s" % (p.GetMin(), p.GetMax())))  
316    
317          return (_("Classification"), items)          return (_("Classification"), items)
318    
319  class ClassIterator:  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, default, points, ranges, maps):      def __init__(self, data): #default, points, ranges, maps):
327          self.data = [default, points, ranges, maps]          """Constructor.
328          self.data_iter = iter(self.data)  
329          self.iter = None          default -- the default group
330    
331            points -- a list of singleton groups
332    
333            ranges -- a list of range groups
334    
335            maps -- a list of map groups
336            """
337    
338            self.data = data
339            self.data_index = 0
340    
341      def __iter__(self):      def __iter__(self):
342          return self          return self
343    
344      def next(self):      def next(self):
345          if self.iter is None:          """Return the next item."""
             try:  
                 self.data_item = self.data_iter.next()  
                 self.iter = iter(self.data_item)  
             except TypeError:  
                 return self.data_item  
346    
347          try:          if self.data_index >= len(self.data):
348              return self.iter.next()              raise StopIteration
349          except StopIteration:          else:
350              self.iter = None              d = self.data[self.data_index]
351              return self.next()              self.data_index += 1
352                      return d
353            
354  class ClassGroupProperties:  class ClassGroupProperties:
355        """Represents the properties of a single Classification Group.
356      
357        These are used when rendering a layer."""
358    
359      def __init__(self, prop = None):      def __init__(self, props = None):
360            """Constructor.
361    
362          if prop is not None:          props -- a ClassGroupProperties object. The class is copied if
363              self.SetStroke(prop.GetStroke())                   prop is not None. Otherwise, a default set of properties
364              self.SetStrokeWidth(prop.GetStrokeWidth())                   is created such that: line color = Black, line width = 1,
365              self.SetFill(prop.GetFill())                   and fill color = Transparent
366            """
367    
368            if props is not None:
369                self.SetProperties(props)
370          else:          else:
371              self.SetStroke(Color.None)              self.SetLineColor(Black)
372              self.SetStrokeWidth(1)              self.SetLineWidth(1)
373              self.SetFill(Color.None)              self.SetFill(Transparent)
374    
375      def GetStroke(self):      def SetProperties(self, props):
376          return self.stroke          """Set this class's properties to those in class props."""
377    
378      def SetStroke(self, stroke):          assert isinstance(props, ClassGroupProperties)
379          assert(isinstance(stroke, Color))          self.SetLineColor(props.GetLineColor())
380          self.stroke = stroke          self.SetLineWidth(props.GetLineWidth())
381            self.SetFill(props.GetFill())
382      def GetStrokeWidth(self):          
383          return self.stroke_width      def GetLineColor(self):
384            """Return the line color as a Color object."""
385      def SetStrokeWidth(self, stroke_width):          return self.__stroke
386          assert(isinstance(stroke_width, IntType))  
387          if (stroke_width < 1):      def SetLineColor(self, color):
388              raise ValueError(_("stroke_width < 1"))          """Set the line color.
389    
390            color -- the color of the line. This must be a Color object.
391            """
392    
393            self.__stroke = color
394    
395        def GetLineWidth(self):
396            """Return the line width."""
397            return self.__strokeWidth
398    
399        def SetLineWidth(self, lineWidth):
400            """Set the line width.
401    
402            lineWidth -- the new line width. This must be > 0.
403            """
404            assert isinstance(lineWidth, types.IntType)
405            if (lineWidth < 1):
406                raise ValueError(_("lineWidth < 1"))
407    
408          self.stroke_width = stroke_width          self.__strokeWidth = lineWidth
409    
410      def GetFill(self):      def GetFill(self):
411          return self.fill          """Return the fill color as a Color object."""
412            return self.__fill
413    
414      def SetFill(self, fill):      def SetFill(self, fill):
415          assert(isinstance(fill, Color))          """Set the fill color.
416          self.fill = fill  
417            fill -- the color of the fill. This must be a Color object.
418            """
419    
420            self.__fill = fill
421    
422        def __eq__(self, other):
423            """Return true if 'props' has the same attributes as this class"""
424    
425            #
426            # using 'is' over '==' results in a huge performance gain
427            # in the renderer
428            #
429            return isinstance(other, ClassGroupProperties)   \
430                and (self.__stroke is other.__stroke or      \
431                     self.__stroke == other.__stroke)        \
432                and (self.__fill is other.__fill or          \
433                     self.__fill == other.__fill)            \
434                and self.__strokeWidth == other.__strokeWidth
435    
436        def __ne__(self, other):
437            return not self.__eq__(other)
438    
439        def __copy__(self):
440            return ClassGroupProperties(self)
441    
442        def __deepcopy__(self):
443            return ClassGroupProperties(self)
444    
445        def __repr__(self):
446            return repr((self.__stroke, self.__strokeWidth, self.__fill))
447    
448  class ClassGroup:  class ClassGroup:
449        """A base class for all Groups within a Classification"""
450    
451      def __init__(self, label = ""):      def __init__(self, label = "", props = None, group = None):
452          self.label = label          """Constructor.
453    
454            label -- A string representing the Group's label
455            """
456    
457            if group is not None:
458                self.SetLabel(copy.copy(group.GetLabel()))
459                self.SetProperties(copy.copy(group.GetProperties()))
460                self.SetVisible(group.IsVisible())
461            else:
462                self.SetLabel(label)
463                self.SetProperties(props)
464                self.SetVisible(True)
465    
466      def GetLabel(self):      def GetLabel(self):
467            """Return the Group's label."""
468          return self.label          return self.label
469    
470      def SetLabel(self, label):      def SetLabel(self, label):
471            """Set the Group's label.
472    
473            label -- a string representing the Group's label. This must
474                     not be None.
475            """
476            assert isinstance(label, types.StringTypes)
477          self.label = label          self.label = label
478    
479        def GetDisplayText(self):
480            assert False, "GetDisplay must be overridden by subclass!"
481            return ""
482    
483      def Matches(self, value):      def Matches(self, value):
484          """This needs to be implemented by all subclasses."""          """Determines if this Group is associated with the given value.
         pass  
485    
486      def GetProperties(self, value):          Returns False. This needs to be overridden by all subclasses.
487          """This needs to be implemented by all subclasses."""          """
488          pass          assert False, "GetMatches must be overridden by subclass!"
489            return False
490    
491        def GetProperties(self):
492            """Return the properties associated with the given value."""
493    
494            return self.prop
495    
496        def SetProperties(self, prop):
497            """Set the properties associated with this Group.
498    
499            prop -- a ClassGroupProperties object. if prop is None,
500                    a default set of properties is created.
501            """
502    
503            if prop is None: prop = ClassGroupProperties()
504            assert isinstance(prop, ClassGroupProperties)
505            self.prop = prop
506    
507        def IsVisible(self):
508            return self.visible
509    
510        def SetVisible(self, visible):
511            self.visible = visible
512    
513        def __eq__(self, other):
514            return isinstance(other, ClassGroup) \
515                and self.label == other.label \
516                and self.GetProperties() == other.GetProperties()
517    
518        def __ne__(self, other):
519            return not self.__eq__(other)
520    
521        def __repr__(self):
522            return repr(self.label) + ", " + repr(self.GetProperties())
523            
524  class ClassGroupSingleton(ClassGroup):  class ClassGroupSingleton(ClassGroup):
525        """A Group that is associated with a single value."""
526    
527      def __init__(self, value = 0, prop = None, label = ""):      def __init__(self, value = 0, props = None, label = "", group = None):
528          ClassGroup.__init__(self, label)          """Constructor.
529    
530            value -- the associated value.
531    
532            prop -- a ClassGroupProperites object. If prop is None a default
533                     set of properties is created.
534    
535            label -- a label for this group.
536            """
537            ClassGroup.__init__(self, label, props, group)
538    
539          self.SetValue(value)          self.SetValue(value)
         self.SetProperties(prop)  
540    
541      def __copy__(self):      def __copy__(self):
542          return ClassGroupSingleton(self.value, self.prop, self.label)          return ClassGroupSingleton(self.GetValue(),
543                                       self.GetProperties(),
544                                       self.GetLabel())
545    
546        def __deepcopy__(self, memo):
547            return ClassGroupSingleton(self.GetValue(), group = self)
548    
549      def GetValue(self):      def GetValue(self):
550          return self.value          """Return the associated value."""
551            return self.__value
552    
553      def SetValue(self, value):      def SetValue(self, value):
554          self.value = value          """Associate this Group with the given value."""
555            self.__value = value
556    
557      def Matches(self, value):      def Matches(self, value):
558          return self.value == value          """Determine if the given value matches the associated Group value."""
559    
560      def GetProperties(self, value = None):          """Returns True if the value matches, False otherwise."""
         if value is None: return self.prop  
561    
562          if self.Matches(value):          return self.__value == value
             return self.prop  
         else:  
             return None  
563    
564      def SetProperties(self, prop):      def GetDisplayText(self):
565          if prop is None: prop = ClassGroupProperties()          label = self.GetLabel()
566          assert(isinstance(prop, ClassGroupProperties))  
567          self.prop = prop          if label != "": return label
568    
569            return str(self.GetValue())
570    
571        def __eq__(self, other):
572            return ClassGroup.__eq__(self, other) \
573                and isinstance(other, ClassGroupSingleton) \
574                and self.__value == other.__value
575    
576        def __repr__(self):
577            return "(" + repr(self.__value) + ", " + ClassGroup.__repr__(self) + ")"
578    
579    class ClassGroupDefault(ClassGroup):
580        """The default Group. When values do not match any other
581           Group within a Classification, the properties from this
582           class are used."""
583    
584        def __init__(self, props = None, label = "", group = None):
585            """Constructor.
586    
587  class ClassGroupDefault(ClassGroupSingleton):          prop -- a ClassGroupProperites object. If prop is None a default
588      def __init__(self, prop = None, label = ""):                   set of properties is created.
589          ClassGroupSingleton.__init__(self, 0, prop, label)  
590            label -- a label for this group.
591            """
592    
593            ClassGroup.__init__(self, label, props, group)
594    
595      def __copy__(self):      def __copy__(self):
596          return ClassGroupDefault(self.prop, self.label)          return ClassGroupDefault(self.GetProperties(), self.GetLabel())
597    
598      def GetProperties(self, value = None):      def __deepcopy__(self, memo):
599          return self.prop          return ClassGroupDefault(label = self.GetLabel(), group = self)
600    
601        def Matches(self, value):
602            return True
603    
604        def GetDisplayText(self):
605            label = self.GetLabel()
606    
607            if label != "": return label
608    
609            return _("DEFAULT")
610    
611        def __eq__(self, other):
612            return ClassGroup.__eq__(self, other) \
613                and isinstance(other, ClassGroupDefault) \
614                and self.GetProperties() == other.GetProperties()
615    
616        def __repr__(self):
617            return "(" + ClassGroup.__repr__(self) + ")"
618    
619  class ClassGroupRange(ClassGroup):  class ClassGroupRange(ClassGroup):
620        """A Group that represents a range of values that map to the same
621           set of properties."""
622    
623      def __init__(self, min = 0, max = 1, prop = None, label = ""):      def __init__(self, _range = (0,1), props = None, label = "", group=None):
624          ClassGroup.__init__(self, label)          """Constructor.
625    
626            The minumum value must be strictly less than the maximum.
627    
628            _range -- either a tuple (min, max) where min < max or
629                      a Range object
630    
631            prop -- a ClassGroupProperites object. If prop is None a default
632                     set of properties is created.
633    
634          self.SetRange(min, max)          label -- a label for this group.
635          self.SetProperties(prop)          """
636    
637            ClassGroup.__init__(self, label, props, group)
638            self.SetRange(_range)
639    
640      def __copy__(self):      def __copy__(self):
641          return ClassGroupRange(self.min, self.max, self.prop, self.label)          return ClassGroupRange(self.__range,
642                                   props = self.GetProperties(),
643                                   label = self.GetLabel())
644    
645        def __deepcopy__(self, memo):
646            return ClassGroupRange(copy.copy(self.__range),
647                                   group = self)
648    
649      def GetMin(self):      def GetMin(self):
650          return self.min          """Return the range's minimum value."""
651            return self.__range.GetRange()[1]
652    
653      def SetMin(self, min):      def SetMin(self, min):
654          self.SetRange(min, self.max)          """Set the range's minimum value.
655        
656            min -- the new minimum. Note that this must be less than the current
657                   maximum value. Use SetRange() to change both min and max values.
658            """
659        
660            self.SetRange((min, self.__range.GetRange()[2]))
661    
662      def GetMax(self):      def GetMax(self):
663          return self.max          """Return the range's maximum value."""
664            return self.__range.GetRange()[2]
665    
666      def SetMax(self, max):      def SetMax(self, max):
667          self.SetRange(self.min, max)          """Set the range's maximum value.
668        
669            max -- the new maximum. Note that this must be greater than the current
670                   minimum value. Use SetRange() to change both min and max values.
671            """
672            self.SetRange((self.__range.GetRange()[1], max))
673    
674        def SetRange(self, _range):
675            """Set a new range.
676    
677      def SetRange(self, min, max):          _range -- Either a tuple (min, max) where min < max or
678          if min >= max:                    a Range object.
679              raise ValueError(_("ClassGroupRange: %i(min) >= %i(max)!") %  
680                               (min, max))          Raises ValueError on error.
681          self.min = min          """
682          self.max = max  
683            if isinstance(_range, Range):
684                self.__range = _range
685            elif isinstance(_range, types.TupleType) and len(_range) == 2:
686                self.__range = Range(("[", _range[0], _range[1], "["))
687            else:
688                raise ValueError()
689    
690      def GetRange(self):      def GetRange(self):
691          return (self.min, self.max)          """Return the range as a string"""
692            return self.__range.string(self.__range.GetRange())
693    
694        def GetRangeTuple(self):
695            return self.__range.GetRange()
696    
697      def Matches(self, value):      def Matches(self, value):
698          return self.min <= value < self.max          """Determine if the given value lies with the current range.
699    
700      def GetProperties(self, value):          The following check is used: min <= value < max.
701          if value is None: return self.prop          """
702    
703          if self.Matches(value):          return operator.contains(self.__range, value)
             return self.prop  
         else:  
             return None  
704    
705      def SetProperties(self, prop):      def GetDisplayText(self):
706          if prop is None: prop = ClassGroupProperties()          label = self.GetLabel()
707          assert(isinstance(prop, ClassGroupProperties))  
708          self.prop = prop          if label != "": return label
709    
710            return self.__range.string(self.__range.GetRange())
711    
712        def __eq__(self, other):
713            return ClassGroup.__eq__(self, other) \
714                and isinstance(other, ClassGroupRange) \
715                and self.__range == other.__range
716    
717        def __repr__(self):
718            return "(" + str(self.__range) + ClassGroup.__repr__(self) + ")"
719    
720  class ClassGroupMap(ClassGroup):  class ClassGroupMap(ClassGroup):
721        """Currently, this class is not used."""
722    
723      FUNC_ID = "id"      FUNC_ID = "id"
724    
725      def __init__(self, map_type = FUNC_ID, func = None, prop = None, label=""):      def __init__(self, map_type = FUNC_ID, func = None, prop = None, label=""):
726          ClassGroup.__init__(self, prop)          ClassGroup.__init__(self, label)
727    
728          self.map_type = map_type          self.map_type = map_type
729          self.func = func          self.func = func
# Line 435  class ClassGroupMap(ClassGroup): Line 734  class ClassGroupMap(ClassGroup):
734      def Map(self, value):      def Map(self, value):
735          return self.func(value)          return self.func(value)
736    
737        def GetProperties(self):
738            return None
739    
740        def GetPropertiesFromValue(self, value):
741            pass
742    
743        def GetDisplayText(self):
744            return "Map: " + self.map_type
745    
746      #      #
747      # built-in mappings      # built-in mappings
748      #      #

Legend:
Removed from v.436  
changed lines
  Added in v.1912

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26