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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26