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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26