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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26