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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26