/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/classification.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/Model/classification.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26