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

Legend:
Removed from v.453  
changed lines
  Added in v.1353

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26