/[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 428 by jonathan, Mon Feb 24 18:46:35 2003 UTC revision 627 by jonathan, Wed Apr 9 10:08:47 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  # fix for people using python2.1
24  from __future__ import nested_scopes  from __future__ import nested_scopes
25    
26  from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \  import copy
      LAYER_VISIBILITY_CHANGED  
27    
28  from Thuban import _  from Thuban import _
 from Thuban.Model.color import Color  
29    
30  from wxPython.wx import *  from types import *
31    
32    from messages import \
33        LAYER_PROJECTION_CHANGED, \
34        LAYER_LEGEND_CHANGED, \
35        LAYER_VISIBILITY_CHANGED
36    
37    from Thuban.Model.color import Color
38    
39  # constants  import Thuban.Model.layer
 RANGE_MIN  = 0  
 RANGE_MAX  = 1  
 RANGE_DATA = 2  
40    
41  class Classification:  class Classification:
42        """Encapsulates the classification of layer.
43        
44        The Classification divides some kind of data into Groups which
45        are associated with properties. Later the properties can be
46        retrieved by matching data values to the appropriate group.
47        """
48    
49      def __init__(self, layer = None, field = None):      def __init__(self, layer = None, field = None):
50          """Initialize a classification.          """Initialize a classification.
51    
52             layer -- the layer object who owns this classification          layer -- the Layer object who owns this classification
53    
54             field -- the name of the data table field that          field -- the name of the data table field that
55                      is to be used to classify layer properties                   is to be used to classify layer properties
56          """          """
57    
58          self.layer = layer          self.layer = None
59          self.points = {}          self.field = None
60          self.ranges = []          self.fieldType = None
61          self.maps   = []          self.__groups = []
62          self.DefaultData = ClassDataDefault()  
63          self.field = field          self.__setLayerLock = False
64          #self.SetField(field)  
65            self.SetDefaultGroup(ClassGroupDefault())
66    
67            self.SetLayer(layer)
68            self.SetField(field)
69    
70      def __iter__(self):      def __iter__(self):
71          return ClassIterator(self.DefaultData,          return ClassIterator(self.__groups)
72                               self.points.values(),  
73                               self.ranges,      def __deepcopy__(self, memo):
74                               self.maps)          clazz = Classification()
75    
76            # note: the only thing that isn't copied is the layer reference
77            clazz.field = self.field
78            clazz.fieldType = self.fieldType
79            clazz.__groups[0] = copy.deepcopy(self.__groups[0])
80    
81            for i in range(1, len(self.__groups)):
82                clazz.__groups.append(copy.deepcopy(self.__groups[i]))
83    
84            return clazz
85    
86      def __SendMessage(self, message):      def __SendNotification(self):
87            """Notify the layer that this class has changed."""
88          if self.layer is not None:          if self.layer is not None:
89              self.layer.changed(message, self.layer)              self.layer.ClassChanged()
90            
91      def SetField(self, field):      def SetField(self, field):
92          """Set the name of the data table field to use.          """Set the name of the data table field to use.
93                    
94             field -- if None then all values map to the default data          If there is no layer then the field type is set to None,
95            otherwise the layer is queried to find the type of the
96            field data
97    
98            field -- if None then all values map to the default data
99          """          """
100    
101            if field == "":
102                field = None
103    
104    
105            if field is None:
106                if self.layer is not None:
107                    self.fieldType = None
108            else:
109                if self.layer is not None:
110                    fieldType = self.layer.GetFieldType(field)
111                    if fieldType is None:
112                        raise ValueError("'%s' was not found in the layer's table."
113                                         % self.field)
114    
115                    #
116                    # unfortunately we cannot call SetFieldType() because it
117                    # requires the layer to be None
118                    #
119                    self.fieldType = fieldType
120                    #self.SetFieldType(fieldType)
121    
122          self.field = field          self.field = field
123          self.__SendMessage(LAYER_LEGEND_CHANGED)  
124            self.__SendNotification()
125    
126      def GetField(self):      def GetField(self):
127            """Return the name of the field."""
128          return self.field          return self.field
129    
130      def SetLayer(self, layer):      def GetFieldType(self):
131          self.layer = layer          """Return the field type."""
132          self.__SendMessage(LAYER_LEGEND_CHANGED)          return self.fieldType
133    
134      def GetLayer(self):      def SetFieldType(self, type):
135          return layer.self          """Set the type of the field used by this classification.
136    
137            A ValueError is raised if the owning layer is not None and
138            'type' is different from the current field type.
139            """
140    
141      def SetDefaultData(self, data):          if type != self.fieldType:
142          """Set the data to be used when a value can't be classified.              if self.layer is not None:
143                    raise ValueError()
144                else:
145                    self.fieldType = type
146                    self.__SendNotification()
147    
148             data -- data that the value maps to. See class description.      def SetLayer(self, layer):
149            """Set the owning Layer of this classification.
150    
151            A ValueError exception will be thrown either the field or
152            field type mismatch the information in the layer's table.
153          """          """
154    
155          assert(data.GetType() == ClassData.DEFAULT)          # prevent infinite recursion when calling SetClassification()
156          self.DefaultData = data          if self.__setLayerLock: return
157    
158            self.__setLayerLock = True
159    
160            if layer is None:
161                if self.layer is not None:
162                    l = self.layer
163                    self.layer = None
164                    l.SetClassification(None)
165            else:
166                assert isinstance(layer, Thuban.Model.layer.Layer)
167    
168                old_layer = self.layer
169    
170                self.layer = layer
171    
172                try:
173                    self.SetField(self.GetField()) # this sync's the fieldType
174                except ValueError:
175                    self.layer = old_layer
176                    self.__setLayerLock = False
177                    raise ValueError
178                else:
179                    self.layer.SetClassification(self)
180    
181            self.__setLayerLock = False
182    
183        def GetLayer(self):
184            """Return the parent layer."""
185            return self.layer
186    
     def GetDefaultData(self):  
         return self.DefaultData  
187    
188      #      #
189      # these SetDefault* methods are really only provided for      # these SetDefault* methods are really only provided for
# Line 103  class Classification: Line 192  class Classification:
192      #      #
193    
194      def SetDefaultFill(self, fill):      def SetDefaultFill(self, fill):
195          self.DefaultData.SetFill(fill)          """Set the default fill color.
196          self.__SendMessage(LAYER_LEGEND_CHANGED)  
197            fill -- a Color object.
198            """
199            assert isinstance(fill, Color)
200            self.GetDefaultGroup().GetProperties().SetFill(fill)
201            self.__SendNotification()
202                    
203      def GetDefaultFill(self):      def GetDefaultFill(self):
204          return self.DefaultData.GetFill()          """Return the default fill color."""
205            return self.GetDefaultGroup().GetProperties().GetFill()
206                    
207      def SetDefaultStroke(self, stroke):      def SetDefaultLineColor(self, color):
208          self.DefaultData.SetStroke(stroke)          """Set the default line color.
209          self.__SendMessage(LAYER_LEGEND_CHANGED)  
210            color -- a Color object.
211            """
212            assert isinstance(color, Color)
213            self.GetDefaultGroup().GetProperties().SetLineColor(color)
214            self.__SendNotification()
215                    
216      def GetDefaultStroke(self):      def GetDefaultLineColor(self):
217          return self.DefaultData.GetStroke()          """Return the default line color."""
218            return self.GetDefaultGroup().GetProperties().GetLineColor()
219                    
220      def SetDefaultStrokeWidth(self, strokeWidth):      def SetDefaultLineWidth(self, lineWidth):
221          self.DefaultData.SetStrokeWidth(strokeWidth)          """Set the default line width.
222          self.__SendMessage(LAYER_LEGEND_CHANGED)  
223            lineWidth -- an integer > 0.
224            """
225            assert isinstance(lineWidth, IntType)
226            self.GetDefaultGroup().GetProperties().SetLineWidth(lineWidth)
227            self.__SendNotification()
228                    
229      def GetDefaultStrokeWidth(self):      def GetDefaultLineWidth(self):
230          return self.DefaultData.GetStrokeWidth()          """Return the default line width."""
231            return self.GetDefaultGroup().GetProperties().GetLineWidth()
232                    
     def AddClassData(self, item):  
         type = item.GetType()  
233    
234          if type == ClassData.POINT:      #
235              self.points[item.GetValue()] = item      # The methods that manipulate self.__groups have to be kept in
236          elif type == ClassData.RANGE:      # sync. We store the default group in index 0 to make it
237              self.ranges.append(item)      # convienent to iterate over the classification's groups, but
238          elif type == ClassData.MAP:      # from the user's perspective the first (non-default) group is
239              self.maps.append(item)      # at index 0 and the DefaultGroup is a special entity.
240          elif type == ClassData.DEFAULT:      #
241              self.DefaultData = item  
242        def SetDefaultGroup(self, group):
243            """Set the group to be used when a value can't be classified.
244    
245            group -- group that the value maps to.
246            """
247    
248            assert isinstance(group, ClassGroupDefault)
249            if len(self.__groups) > 0:
250                self.__groups[0] = group
251          else:          else:
252              raise ValueError(_("Unrecognized ClassData type %s") % type)              self.__groups.append(group)
253    
254          self.__SendMessage(LAYER_LEGEND_CHANGED)      def GetDefaultGroup(self):
255            """Return the default group."""
256            return self.__groups[0]
257    
258      def GetClassData(self, value):      def AppendGroup(self, item):
259          """Return the associated data, or the default data.          """Append a new ClassGroup item to the classification.
260    
261             The following search technique is used:          item -- this must be a valid ClassGroup object
262                 (1) if the field is None, return the default data          """
263                 (2) check if the value exists as a single value  
264                 (3) check if the value falls within a range. Ranges          self.InsertGroup(self.GetNumGroups(), item)
265                     are checked in the order they were added to  
266                     the classification.      def InsertGroup(self, index, group):
267            
268             value -- the value to classify. If there is no mapping,          assert isinstance(group, ClassGroup)
269                      or value is None, return the default properties  
270          """          self.__groups.insert(index + 1, group)
271    
272          if self.field is not None and value is not None:          self.__SendNotification()
273              #  
274              # check the discrete values      def RemoveGroup(self, index):
275              #          return self.__groups.pop(index + 1)
276              if self.points.has_key(value):  
277                  return self.points[value]      def ReplaceGroup(self, index, group):
278            assert isinstance(group, ClassGroup)
279              #  
280              # check the ranges          self.__groups[index + 1] = group
281              #  
282              for p in self.ranges:          self.__SendNotification()
283                  if p.InRange(value):  
284                      return p      def GetGroup(self, index):
285            return self.__groups[index + 1]
286              #  
287              # check the maps      def GetNumGroups(self):
288              #          """Return the number of non-default groups in the classification."""
289              for p in self.maps:          return len(self.__groups) - 1
                 try:  
                     return p.Map(value)  
                 except: pass  
290    
291          return self.DefaultData  
292        def FindGroup(self, value):
293            """Return the associated group, or the default group.
294    
295            Groups are checked in the order the were added to the
296            Classification.
297    
298            value -- the value to classify. If there is no mapping,
299                     the field is None or value is None,
300                     return the default properties
301            """
302    
303            if self.GetField() is not None and value is not None:
304    
305                for i in range(1, len(self.__groups)):
306                    group = self.__groups[i]
307                    if group.Matches(value):
308                        return group
309    
310            return self.GetDefaultGroup()
311    
312        def GetProperties(self, value):
313            """Return the properties associated with the given value.
314          
315            Use this function rather than Classification.FindGroup().GetProperties()
316            since the returned group may be a ClassGroupMap which doesn't support
317            a call to GetProperties().
318            """
319    
320            group = self.FindGroup(value)
321            if isinstance(group, ClassGroupMap):
322                return group.GetPropertiesFromValue(value)
323            else:
324                return group.GetProperties()
325    
326      def TreeInfo(self):      def TreeInfo(self):
327          items = []          items = []
328    
329          def build_color_item(text, color):          def build_color_item(text, color):
330              if color is Color.None:              if color is Color.Transparent:
331                  return ("%s: %s" % (text, _("None")), None)                  return ("%s: %s" % (text, _("None")), None)
332    
333              return ("%s: (%.3f, %.3f, %.3f)" %              return ("%s: (%.3f, %.3f, %.3f)" %
334                      (text, color.red, color.green, color.blue),                      (text, color.red, color.green, color.blue),
335                      color)                      color)
336    
337          def build_item(data, string):          def build_item(group, string):
338              label = data.GetLabel()              label = group.GetLabel()
339              if label == "":              if label == "":
340                  label = string                  label = string
341              else:              else:
342                  label += " (%s)" % string                  label += " (%s)" % string
343    
344                props = group.GetProperties()
345              i = []              i = []
346              v = data.GetStroke()              v = props.GetLineColor()
347              i.append(build_color_item(_("Stroke"), v))              i.append(build_color_item(_("Line Color"), v))
348              v = data.GetStrokeWidth()              v = props.GetLineWidth()
349              i.append(_("Stroke Width: %s") % v)              i.append(_("Line Width: %s") % v)
350              v = data.GetFill()              v = props.GetFill()
351              i.append(build_color_item(_("Fill"), v))              i.append(build_color_item(_("Fill"), v))
352              return (label, i)              return (label, i)
353    
354          for p in self:          for p in self:
355              type = p.GetType()              items.append(build_item(p, p.GetDisplayText()))
             if type == ClassData.DEFAULT:  
                 items.append(build_item(self.DefaultData, _("'DEFAULT'")))  
             elif type == ClassData.POINT:  
                 items.append(build_item(p, str(p.GetValue())))  
             elif type == ClassData.RANGE:  
                 items.append(build_item(p, "%s - %s" %  
                                            (p.GetMin(), p.GetMax())))  
356    
357  #       for p in self.points.values():  #           if isinstance(p, ClassGroupDefault):
358  #           items.append(build_item(p, str(p.GetValue())))  #               items.append(build_item(self.GetDefaultGroup(), _("'DEFAULT'")))
359    #           elif isinstance(p, ClassGroupSingleton):
360    #               items.append(build_item(p, str(p.GetValue())))
361    #           elif isinstance(p, ClassGroupRange):
362    #               items.append(build_item(p, "%s - %s" %
363    #                                          (p.GetMin(), p.GetMax())))
364    
365  #       for p in self.ranges:          return (_("Classification"), items)
 #           items.append(build_item(p, "%s - %s" % (p.GetMin(), p.GetMax())))  
   
         return (_("Classifications"), items)  
366    
367  class ClassIterator:  class ClassIterator:
368        """Allows the Groups in a Classifcation to be interated over.
369    
370        The items are returned in the following order:
371            default data, singletons, ranges, maps
372        """
373    
374        def __init__(self, data): #default, points, ranges, maps):
375            """Constructor.
376    
377      def __init__(self, default, points, ranges, maps):          default -- the default group
378          self.data = [default, points, ranges, maps]  
379          self.data_iter = iter(self.data)          points -- a list of singleton groups
380          self.iter = None  
381            ranges -- a list of range groups
382    
383            maps -- a list of map groups
384            """
385    
386            self.data = data #[default, points, ranges, maps]
387            self.data_index = 0
388            #self.data_iter = iter(self.data)
389            #self.iter = None
390    
391      def __iter__(self):      def __iter__(self):
392          return self          return self
393    
394      def next(self):      def next(self):
395          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  
   
         try:  
             return self.iter.next()  
         except StopIteration:  
             self.iter = None  
             return self.next()  
         
 class ClassData:  
396    
397      INVALID = -1          if self.data_index >= len(self.data):
398      DEFAULT = 0              raise StopIteration
     POINT = 1  
     RANGE = 2  
     MAP   = 3  
   
     def __init__(self, classData = None, type = INVALID):  
   
         if classData is not None:  
             self.SetStroke(classData.GetStroke())  
             self.SetStrokeWidth(classData.GetStrokeWidth())  
             self.SetFill(classData.GetFill())  
399          else:          else:
400              self.SetStroke(Color.None)              d = self.data[self.data_index]
401              self.SetStrokeWidth(1)              self.data_index += 1
402              self.SetFill(Color.None)              return d
403            
404    #       if self.iter is None:
405    #           try:
406    #               self.data_item = self.data_iter.next()
407    #               self.iter = iter(self.data_item)
408    #           except TypeError:
409    #               return self.data_item
410    
411    #       try:
412    #           return self.iter.next()
413    #       except StopIteration:
414    #           self.iter = None
415    #           return self.next()
416          
417    class ClassGroupProperties:
418        """Represents the properties of a single Classification Group.
419      
420        These are used when rendering a layer."""
421    
422          self.type = type      def __init__(self, props = None):
423          self.label = ""          """Constructor.
424        
425      def GetType(self):          props -- a ClassGroupProperties object. The class is copied if
426          return self.type                   prop is not None. Otherwise, a default set of properties
427                     is created such that: line color = Color.Black, line width = 1,
428                     and fill color = Color.Transparent
429            """
430    
431            self.stroke = None
432            self.strokeWidth = 0
433            self.fill = None
434    
435      def GetStroke(self):          if props is not None:
436                self.SetProperties(props)
437            else:
438                self.SetLineColor(Color.Black)
439                self.SetLineWidth(1)
440                self.SetFill(Color.Transparent)
441    
442        def SetProperties(self, props):
443            """Set this class's properties to those in class props."""
444    
445            assert isinstance(props, ClassGroupProperties)
446            self.SetLineColor(props.GetLineColor())
447            self.SetLineWidth(props.GetLineWidth())
448            self.SetFill(props.GetFill())
449            
450        def GetLineColor(self):
451            """Return the line color as a Color object."""
452          return self.stroke          return self.stroke
453    
454      def SetStroke(self, stroke):      def SetLineColor(self, color):
455          assert(isinstance(stroke, Color))          """Set the line color.
456          self.stroke = stroke  
457            color -- the color of the line. This must be a Color object.
458      def GetStrokeWidth(self):          """
459          return self.stroke_width  
460            assert isinstance(color, Color)
461      def SetStrokeWidth(self, stroke_width):          self.stroke = color
462          if (stroke_width < 1):  
463              raise ValueError(_("stroke_width < 1"))      def GetLineWidth(self):
464            """Return the line width."""
465            return self.strokeWidth
466    
467        def SetLineWidth(self, lineWidth):
468            """Set the line width.
469    
470          self.stroke_width = stroke_width          lineWidth -- the new line width. This must be > 0.
471            """
472            assert isinstance(lineWidth, IntType)
473            if (lineWidth < 1):
474                raise ValueError(_("lineWidth < 1"))
475    
476            self.strokeWidth = lineWidth
477    
478      def GetFill(self):      def GetFill(self):
479            """Return the fill color as a Color object."""
480          return self.fill          return self.fill
481    
482      def SetFill(self, fill):      def SetFill(self, fill):
483          assert(isinstance(fill, Color))          """Set the fill color.
484    
485            fill -- the color of the fill. This must be a Color object.
486            """
487    
488            assert isinstance(fill, Color)
489          self.fill = fill          self.fill = fill
490    
491        def __eq__(self, other):
492            """Return true if 'props' has the same attributes as this class"""
493    
494            return isinstance(other, ClassGroupProperties)   \
495                and self.stroke      == other.GetLineColor() \
496                and self.strokeWidth == other.GetLineWidth() \
497                and self.fill        == other.GetFill()
498    
499        def __ne__(self, other):
500            return not self.__eq__(other)
501    
502        def __copy__(self):
503            return ClassGroupProperties(self)
504    
505        def __deepcopy__(self):
506            return ClassGroupProperties(self)
507    
508    class ClassGroup:
509        """A base class for all Groups within a Classification"""
510    
511        def __init__(self, label = ""):
512            """Constructor.
513    
514            label -- A string representing the Group's label
515            """
516    
517            self.label = None
518    
519            self.SetLabel(label)
520    
521      def GetLabel(self):      def GetLabel(self):
522            """Return the Group's label."""
523          return self.label          return self.label
524    
525      def SetLabel(self, label):      def SetLabel(self, label):
526            """Set the Group's label.
527    
528            label -- a string representing the Group's label. This must
529                     not be None.
530            """
531            assert isinstance(label, StringType)
532          self.label = label          self.label = label
533    
534  class ClassDataDefault(ClassData):      def GetDisplayText(self):
535      def __init__(self, classData = None):          assert False, "GetDisplay must be overridden by subclass!"
536          ClassData.__init__(self, classData, ClassData.DEFAULT)          return ""
537    
538        def Matches(self, value):
539            """Determines if this Group is associated with the given value.
540    
541            Returns False. This needs to be overridden by all subclasses.
542            """
543            assert False, "GetMatches must be overridden by subclass!"
544            return False
545    
546        def GetProperties(self):
547            """Return the properties associated with the given value.
548    
549            Returns None. This needs to be overridden by all subclasses.
550            """
551            assert False, "GetProperties must be overridden by subclass!"
552            return None
553    
554            
555  class ClassDataPoint(ClassData):  class ClassGroupSingleton(ClassGroup):
556        """A Group that is associated with a single value."""
557    
558      def __init__(self, value = 0, classData = None):      def __init__(self, value = 0, prop = None, label = ""):
559          ClassData.__init__(self, classData, ClassData.POINT)          """Constructor.
560    
561          self.value = value          value -- the associated value.
562    
563            prop -- a ClassGroupProperites object. If prop is None a default
564                     set of properties is created.
565    
566            label -- a label for this group.
567            """
568            ClassGroup.__init__(self, label)
569    
570            self.prop = None
571            self.value = None
572    
573            self.SetValue(value)
574            self.SetProperties(prop)
575    
576        def __copy__(self):
577            return ClassGroupSingleton(self.GetValue(),
578                                       self.GetProperties(),
579                                       self.GetLabel())
580    
581        def __deepcopy__(self, memo):
582            return ClassGroupSingleton(copy.copy(self.GetValue()),
583                                       copy.copy(self.GetProperties()),
584                                       copy.copy(self.GetLabel()))
585    
586      def GetValue(self):      def GetValue(self):
587            """Return the associated value."""
588          return self.value          return self.value
589    
590      def SetValue(self, value):      def SetValue(self, value):
591            """Associate this Group with the given value."""
592          self.value = value          self.value = value
593    
594  class ClassDataRange(ClassData):      def Matches(self, value):
595            """Determine if the given value matches the associated Group value."""
596    
597      def __init__(self, min = 0, max = 1, classData = None):          """Returns True if the value matches, False otherwise."""
         ClassData.__init__(self, classData, ClassData.RANGE)  
598    
599          if min >= max:          return self.value == value
600              raise ValueError(_("ClassDataRange: %i(min) >= %i(max)!") %  
601                               (min, max))      def GetProperties(self):
602            """Return the Properties associated with this Group."""
603    
604            return self.prop
605    
606        def SetProperties(self, prop):
607            """Set the properties associated with this Group.
608    
609            prop -- a ClassGroupProperties object. if prop is None,
610                    a default set of properties is created.
611            """
612    
613            if prop is None: prop = ClassGroupProperties()
614            assert isinstance(prop, ClassGroupProperties)
615            self.prop = prop
616    
617        def GetDisplayText(self):
618            label = self.GetLabel()
619    
620            if label != "": return label
621    
622            return str(self.GetValue())
623    
624        def __eq__(self, other):
625            return isinstance(other, ClassGroupSingleton) \
626                and self.GetProperties() == other.GetProperties() \
627                and self.GetValue() == other.GetValue()
628    
629        def __ne__(self, other):
630            return not self.__eq__(other)
631    
632    class ClassGroupDefault(ClassGroup):
633        """The default Group. When values do not match any other
634           Group within a Classification, the properties from this
635           class are used."""
636    
637        def __init__(self, prop = None, label = ""):
638            """Constructor.
639    
640            prop -- a ClassGroupProperites object. If prop is None a default
641                     set of properties is created.
642    
643            label -- a label for this group.
644            """
645    
646            ClassGroup.__init__(self, label)
647            self.SetProperties(prop)
648    
649        def __copy__(self):
650            return ClassGroupDefault(self.GetProperties(), self.GetLabel())
651    
652        def __deepcopy__(self, memo):
653            return ClassGroupDefault(copy.copy(self.GetProperties()),
654                                     copy.copy(self.GetLabel()))
655    
656        def Matches(self, value):
657            return True
658    
659        def GetProperties(self):
660            """Return the Properties associated with this Group."""
661            return self.prop
662    
663        def SetProperties(self, prop):
664            """Set the properties associated with this Group.
665    
666            prop -- a ClassGroupProperties object. if prop is None,
667                    a default set of properties is created.
668            """
669    
670            if prop is None: prop = ClassGroupProperties()
671            assert isinstance(prop, ClassGroupProperties)
672            self.prop = prop
673    
674        def GetDisplayText(self):
675            label = self.GetLabel()
676    
677            if label != "": return label
678    
679            return _("DEFAULT")
680    
681        def __eq__(self, other):
682            return isinstance(other, ClassGroupDefault) \
683                and self.GetProperties() == other.GetProperties()
684    
685        def __ne__(self, other):
686            return not self.__eq__(other)
687    
688    class ClassGroupRange(ClassGroup):
689        """A Group that represents a range of values that map to the same
690           set of properties."""
691    
692        def __init__(self, min = 0, max = 1, prop = None, label = ""):
693            """Constructor.
694    
695            The minumum value must be strictly less than the maximum.
696    
697            min -- the minimum range value
698    
699            max -- the maximum range value
700    
701            prop -- a ClassGroupProperites object. If prop is None a default
702                     set of properties is created.
703    
704            label -- a label for this group.
705            """
706    
707            ClassGroup.__init__(self, label)
708    
709            self.min = self.max = 0
710            self.prop = None
711    
712          self.SetRange(min, max)          self.SetRange(min, max)
713            self.SetProperties(prop)
714    
715        def __copy__(self):
716            return ClassGroupRange(self.GetMin(),
717                                   self.GetMax(),
718                                   self.GetProperties(),
719                                   self.GetLabel())
720    
721        def __deepcopy__(self, memo):
722            return ClassGroupRange(copy.copy(self.GetMin()),
723                                   copy.copy(self.GetMax()),
724                                   copy.copy(self.GetProperties()),
725                                   copy.copy(self.GetLabel()))
726    
727      def GetMin(self):      def GetMin(self):
728            """Return the range's minimum value."""
729          return self.min          return self.min
730    
731      def SetMin(self, min):      def SetMin(self, min):
732            """Set the range's minimum value.
733        
734            min -- the new minimum. Note that this must be less than the current
735                   maximum value. Use SetRange() to change both min and max values.
736            """
737        
738          self.SetRange(min, self.max)          self.SetRange(min, self.max)
739    
740      def GetMax(self):      def GetMax(self):
741            """Return the range's maximum value."""
742          return self.max          return self.max
743    
744      def SetMax(self, max):      def SetMax(self, max):
745            """Set the range's maximum value.
746        
747            max -- the new maximum. Note that this must be greater than the current
748                   minimum value. Use SetRange() to change both min and max values.
749            """
750          self.SetRange(self.min, max)          self.SetRange(self.min, max)
751    
752      def SetRange(self, min, max):      def SetRange(self, min, max):
753          self.min = min          """Set a new range.
754          self.max = max  
755            Note that min must be strictly less than max.
756    
757            min -- the new minimum value
758            min -- the new maximum value
759            """
760    
761          if min >= max:          if min >= max:
762              raise ValueError(_("ClassDataRange: %i(min) >= %i(max)!") %              raise ValueError(_("ClassGroupRange: %i(min) >= %i(max)!") %
763                               (min, max))                               (min, max))
764            self.min = min
765            self.max = max
766    
767      def GetRange(self):      def GetRange(self):
768            """Return the range as a tuple (min, max)"""
769          return (self.min, self.max)          return (self.min, self.max)
770    
771      def InRange(self, value):      def Matches(self, value):
772            """Determine if the given value lies with the current range.
773    
774            The following check is used: min <= value < max.
775            """
776    
777          return self.min <= value < self.max          return self.min <= value < self.max
778    
779  class ClassDataMap(ClassData):      def GetProperties(self):
780            """Return the Properties associated with this Group."""
781            return self.prop
782    
783        def SetProperties(self, prop):
784            """Set the properties associated with this Group.
785    
786            prop -- a ClassGroupProperties object. if prop is None,
787                    a default set of properties is created.
788            """
789            if prop is None: prop = ClassGroupProperties()
790            assert isinstance(prop, ClassGroupProperties)
791            self.prop = prop
792    
793        def GetDisplayText(self):
794            label = self.GetLabel()
795    
796            if label != "": return label
797    
798            return _("%s - %s") % (self.GetMin(), self.GetMax())
799    
800        def __eq__(self, other):
801            return isinstance(other, ClassGroupRange) \
802                and self.GetProperties() == other.GetProperties() \
803                and self.GetRange() == other.GetRange()
804    
805        def __ne__(self, other):
806            return not self.__eq__(other)
807    
808    class ClassGroupMap(ClassGroup):
809        """Currently, this class is not used."""
810    
811      FUNC_ID = "id"      FUNC_ID = "id"
812    
813      def __init__(self, map_type = FUNC_ID, func = None, classData = None):      def __init__(self, map_type = FUNC_ID, func = None, prop = None, label=""):
814          ClassData.__init__(self, classData, ClassData.MAP)          ClassGroup.__init__(self, label)
815    
816          self.map_type = map_type          self.map_type = map_type
817          self.func = func          self.func = func
# Line 369  class ClassDataMap(ClassData): Line 822  class ClassDataMap(ClassData):
822      def Map(self, value):      def Map(self, value):
823          return self.func(value)          return self.func(value)
824    
825        def GetProperties(self):
826            return None
827    
828        def GetPropertiesFromValue(self, value):
829            pass
830    
831        def GetDisplayText(self):
832            return "Map: " + self.map_type
833    
834      #      #
835      # built-in mappings      # built-in mappings
836      #      #

Legend:
Removed from v.428  
changed lines
  Added in v.627

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26