/[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 544 by jonathan, Thu Mar 20 09:43:48 2003 UTC revision 1912 by bh, Mon Nov 3 13:55:41 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  
24    
25  import copy  from Thuban import _
   
 from types 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        CLASS_CHANGED
32    
33  from Thuban import _  from Thuban.Model.color import Color, Transparent, Black
34  from Thuban.Model.color import Color  from Thuban.Model.range import Range
35    
36  import Thuban.Model.layer  import Thuban.Model.layer
37    
38  # constants  from Thuban.Lib.connector import Publisher
 RANGE_MIN  = 0  
 RANGE_MAX  = 1  
 RANGE_DATA = 2  
   
 class Classification:  
     """Encapsulates the classification of layer. The Classification  
     divides some kind of data into Groups which are associated with  
     properties. Later the properties can be retrieved by matching  
     data values to the appropriate group."""  
39    
40      def __init__(self, layer = None, field = None):  class Classification(Publisher):
41          """Initialize a classification.      """Encapsulates the classification of layer.
42        
43             layer -- the Layer object who owns this classification      The Classification divides some kind of data into Groups which
44        are associated with properties. Later the properties can be
45        retrieved by matching data values to the appropriate group.
46        """
47    
48             field -- the name of the data table field that      def __init__(self):
49                      is to be used to classify layer properties          """Initialize a classification."""
         """  
50    
51          self.layer = None          self.__groups = []
         self.field = None  
         self.fieldType = None  
         self.groups = []  
   
         self.__setLayerLock = False  
52    
53          self.SetDefaultGroup(ClassGroupDefault())          self.SetDefaultGroup(ClassGroupDefault())
54    
         self.SetLayer(layer)  
         self.SetField(field)  
   
55      def __iter__(self):      def __iter__(self):
56          return ClassIterator(self.groups)          return ClassIterator(self.__groups)
   
     def __SendNotification(self):  
         """Notify the layer that this class has changed."""  
         if self.layer is not None:  
             self.layer.ClassChanged()  
       
     def SetField(self, field):  
         """Set the name of the data table field to use.  
           
            If there is no layer then the field type is set to None,  
            otherwise the layer is queried to find the type of the  
            field data  
   
            field -- if None then all values map to the default data  
         """  
   
         if field == "":  
             field = None  
   
   
         if field is None:  
             if self.layer is not None:  
                 self.fieldType = None  
         else:  
             if self.layer is not None:  
                 fieldType = self.layer.GetFieldType(field)  
                 if fieldType is None:  
                     raise ValueError("'%s' was not found in the layer's table."  
                                      % self.field)  
   
                 #  
                 # unfortunately we cannot call SetFieldType() because it  
                 # requires the layer to be None  
                 #  
                 self.fieldType = fieldType  
                 #self.SetFieldType(fieldType)  
   
         self.field = field  
   
         self.__SendNotification()  
   
     def GetField(self):  
         """Return the name of the field."""  
         return self.field  
   
     def GetFieldType(self):  
         """Return the field type."""  
         return self.fieldType  
   
     def SetFieldType(self, type):  
         """Set the type of the field used by this classification.  
   
         A ValueError is raised if the owning layer is not None and  
         'type' is different from the current field type.  
         """  
57    
58          if type != self.fieldType:      def __deepcopy__(self, memo):
59              if self.layer is not None:          clazz = Classification()
                 raise ValueError()  
             else:  
                 self.fieldType = type  
                 self.__SendNotification()  
   
     def SetLayer(self, layer):  
         """Set the owning Layer of this classification.  
   
            A ValueError exception will be thrown either the field or  
            field type mismatch the information in the layer's table.  
         """  
   
         # prevent infinite recursion when calling SetClassification()  
         if self.__setLayerLock: return  
60    
61          self.__setLayerLock = True          clazz.__groups[0] = copy.deepcopy(self.__groups[0])
62    
63          if layer is None:          for i in range(1, len(self.__groups)):
64              if self.layer is not None:              clazz.__groups.append(copy.deepcopy(self.__groups[i]))
                 l = self.layer  
                 self.layer = None  
                 l.SetClassification(None)  
         else:  
             assert(isinstance(layer, Thuban.Model.layer.Layer))  
65    
66              old_layer = self.layer          return clazz
67    
68              self.layer = layer      def __SendNotification(self):
69            """Notify the layer that this class has changed."""
70            self.issue(CLASS_CHANGED)
71    
72              try:      def __getattr__(self, attr):
73                  self.SetField(self.GetField()) # this sync's the fieldType          """Generate the compiled classification on demand"""
74              except ValueError:          if attr == "_compiled_classification":
75                  self.layer = old_layer              self._compile_classification()
76                  self.__setLayerLock = False              return self._compiled_classification
77                  raise ValueError          raise AttributeError(attr)
78    
79        def _compile_classification(self):
80            """Generate the compiled classification
81    
82            The compiled classification is a more compact representation of
83            the classification groups that is also more efficient for
84            performing the classification.
85    
86            The compiled classification is a list of tuples. The first
87            element of the tuple is a string which describes the rest of the
88            tuple. There are two kinds of tuples:
89    
90              'singletons'
91    
92                The second element of the tuple is a dictionary which
93                combines several consecutive ClassGroupSingleton instances.
94                The dictionary maps the values of the singletons (as
95                returned by the GetValue() method) to the corresponding
96                group.
97    
98              'range'
99    
100                The tuple describes a ClassGroupRange instance. The tuples
101                second element is a tuple fo the form (lfunc, min, max,
102                rfunc, group) where group is the original group object,
103                lfunc and rfuct are comparison functions and min and max are
104                lower and upper bounds of the range. Given a value and such
105                a tuple the group matches if and only if
106    
107                    lfunc(min, value) and rfunc(max, value)
108    
109                is true.
110    
111            The compiled classification is bound to
112            self._compile_classification.
113            """
114            compiled = []
115            for group in self.__groups[1:]:
116                if isinstance(group, ClassGroupSingleton):
117                    if not compiled or compiled[-1][0] != "singletons":
118                        compiled.append(("singletons", {}))
119                    compiled[-1][1].setdefault(group.GetValue(), group)
120                elif isinstance(group, ClassGroupRange):
121                    left, min, max, right = group.GetRangeTuple()
122                    if left == "[":
123                        lfunc = operator.le
124                    elif left == "]":
125                        lfunc = operator.lt
126                    if right == "[":
127                        rfunc = operator.gt
128                    elif right == "]":
129                        rfunc = operator.ge
130                    compiled.append(("range", (lfunc, min, max, rfunc, group)))
131              else:              else:
132                  self.layer.SetClassification(self)                  raise TypeError("Unknown group type %s", group)
133            self._compiled_classification = compiled
134    
135          self.__setLayerLock = False      def _clear_compiled_classification(self):
136            """Reset the compiled classification.
137    
138      def GetLayer(self):          If will be created on demand when self._compiled_classification
139          """Return the parent layer."""          is accessed again.
         return self.layer  
140    
141      def SetDefaultGroup(self, group):          Call this method whenever self.__groups is modified.
         """Set the group to be used when a value can't be classified.  
   
            group -- group that the value maps to.  
142          """          """
143            try:
144          assert(isinstance(group, ClassGroupDefault))              del self._compiled_classification
145          self.AddGroup(group)          except:
146                pass
     def GetDefaultGroup(self):  
         """Return the default group."""  
         return self.groups[0]  
147    
148      #      #
149      # these SetDefault* methods are really only provided for      # these SetDefault* methods are really only provided for
# Line 195  class Classification: Line 156  class Classification:
156    
157          fill -- a Color object.          fill -- a Color object.
158          """          """
         assert(isinstance(fill, Color))  
159          self.GetDefaultGroup().GetProperties().SetFill(fill)          self.GetDefaultGroup().GetProperties().SetFill(fill)
160          self.__SendNotification()          self.__SendNotification()
161                    
# Line 208  class Classification: Line 168  class Classification:
168    
169          color -- a Color object.          color -- a Color object.
170          """          """
         assert(isinstance(color, Color))  
171          self.GetDefaultGroup().GetProperties().SetLineColor(color)          self.GetDefaultGroup().GetProperties().SetLineColor(color)
172          self.__SendNotification()          self.__SendNotification()
173                    
# Line 221  class Classification: Line 180  class Classification:
180    
181          lineWidth -- an integer > 0.          lineWidth -- an integer > 0.
182          """          """
183          assert(isinstance(lineWidth, IntType))          assert isinstance(lineWidth, types.IntType)
184          self.GetDefaultGroup().GetProperties().SetLineWidth(lineWidth)          self.GetDefaultGroup().GetProperties().SetLineWidth(lineWidth)
185          self.__SendNotification()          self.__SendNotification()
186                    
# Line 229  class Classification: Line 188  class Classification:
188          """Return the default line width."""          """Return the default line width."""
189          return self.GetDefaultGroup().GetProperties().GetLineWidth()          return self.GetDefaultGroup().GetProperties().GetLineWidth()
190                    
     def AddGroup(self, item):  
         """Add a new ClassGroup item to the classification.  
191    
192          item -- this must be a valid ClassGroup object      #
193          """      # The methods that manipulate self.__groups have to be kept in
194        # sync. We store the default group in index 0 to make it
195        # convienent to iterate over the classification's groups, but
196        # from the user's perspective the first (non-default) group is
197        # at index 0 and the DefaultGroup is a special entity.
198        #
199    
200          assert(isinstance(item, ClassGroup))      def SetDefaultGroup(self, group):
201            """Set the group to be used when a value can't be classified.
202    
203          if len(self.groups) > 0 and isinstance(item, ClassGroupDefault):          group -- group that the value maps to.
204              self.groups[0] = item          """
205            assert isinstance(group, ClassGroupDefault)
206            if len(self.__groups) > 0:
207                self.__groups[0] = group
208          else:          else:
209              self.groups.append(item)              self.__groups.append(group)
   
210          self.__SendNotification()          self.__SendNotification()
211    
212      def GetGroup(self, value):      def GetDefaultGroup(self):
213          """Return the associated group, or the default group.          """Return the default group."""
214            return self.__groups[0]
215    
216             Groups are checked in the order the were added to the      def AppendGroup(self, item):
217             Classification.          """Append a new ClassGroup item to the classification.
218    
219             value -- the value to classify. If there is no mapping,          item -- this must be a valid ClassGroup object
                     the field is None or value is None,  
                     return the default properties  
220          """          """
221    
222          if self.GetField() is not None and value is not None:          self.InsertGroup(self.GetNumGroups(), item)
223    
224              for i in range(1, len(self.groups)):      def InsertGroup(self, index, group):
225                  group = self.groups[i]          assert isinstance(group, ClassGroup)
226                  if group.Matches(value):          self.__groups.insert(index + 1, group)
227                      return group          self._clear_compiled_classification()
228            self.__SendNotification()
229    
230        def RemoveGroup(self, index):
231            """Remove the classification group with the given index"""
232            self.__groups.pop(index + 1)
233            self._clear_compiled_classification()
234            self.__SendNotification()
235    
236        def ReplaceGroup(self, index, group):
237            assert isinstance(group, ClassGroup)
238            self.__groups[index + 1] = group
239            self._clear_compiled_classification()
240            self.__SendNotification()
241    
242        def GetGroup(self, index):
243            return self.__groups[index + 1]
244    
245        def GetNumGroups(self):
246            """Return the number of non-default groups in the classification."""
247            return len(self.__groups) - 1
248    
249        def FindGroup(self, value):
250            """Return the group that matches the value.
251    
252            Groups are effectively checked in the order the were added to
253            the Classification.
254    
255            value -- the value to classify. If there is no mapping or value
256                     is None, return the default properties
257            """
258    
259            if value is not None:
260                for typ, params in self._compiled_classification:
261                    if typ == "singletons":
262                        group = params.get(value)
263                        if group is not None:
264                            return group
265                    elif typ == "range":
266                        lfunc, min, max, rfunc, g = params
267                        if lfunc(min, value) and rfunc(max, value):
268                            return g
269    
270          return self.GetDefaultGroup()          return self.GetDefaultGroup()
271    
272      def GetProperties(self, value):      def GetProperties(self, value):
273          """Return the properties associated with the given value."""          """Return the properties associated with the given value.
274          
275            Use this function rather than Classification.FindGroup().GetProperties()
276            since the returned group may be a ClassGroupMap which doesn't support
277            a call to GetProperties().
278            """
279    
280          group = self.GetGroup(value)          group = self.FindGroup(value)
281          if isinstance(group, ClassGroupMap):          if isinstance(group, ClassGroupMap):
282              return group.GetPropertiesFromValue(value)              return group.GetPropertiesFromValue(value)
283          else:          else:
# Line 277  class Classification: Line 287  class Classification:
287          items = []          items = []
288    
289          def build_color_item(text, color):          def build_color_item(text, color):
290              if color is Color.None:              if color is Transparent:
291                  return ("%s: %s" % (text, _("None")), None)                  return ("%s: %s" % (text, _("None")), None)
292    
293              return ("%s: (%.3f, %.3f, %.3f)" %              return ("%s: (%.3f, %.3f, %.3f)" %
# Line 302  class Classification: Line 312  class Classification:
312              return (label, i)              return (label, i)
313    
314          for p in self:          for p in self:
315              if isinstance(p, ClassGroupDefault):              items.append(build_item(p, p.GetDisplayText()))
                 items.append(build_item(self.GetDefaultGroup(), _("'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())))  
316    
317          return (_("Classification"), items)          return (_("Classification"), items)
318    
# Line 331  class ClassIterator: Line 335  class ClassIterator:
335          maps -- a list of map groups          maps -- a list of map groups
336          """          """
337    
338          self.data = data #[default, points, ranges, maps]          self.data = data
339          self.data_index = 0          self.data_index = 0
         #self.data_iter = iter(self.data)  
         #self.iter = None  
340    
341      def __iter__(self):      def __iter__(self):
342          return self          return self
# Line 349  class ClassIterator: Line 351  class ClassIterator:
351              self.data_index += 1              self.data_index += 1
352              return d              return d
353                    
 #       if self.iter is None:  
 #           try:  
 #               self.data_item = self.data_iter.next()  
 #               self.iter = iter(self.data_item)  
 #           except TypeError:  
 #               return self.data_item  
   
 #       try:  
 #           return self.iter.next()  
 #       except StopIteration:  
 #           self.iter = None  
 #           return self.next()  
         
354  class ClassGroupProperties:  class ClassGroupProperties:
355      """Represents the properties of a single Classification Group.      """Represents the properties of a single Classification Group.
356        
# Line 372  class ClassGroupProperties: Line 361  class ClassGroupProperties:
361    
362          props -- a ClassGroupProperties object. The class is copied if          props -- a ClassGroupProperties object. The class is copied if
363                   prop is not None. Otherwise, a default set of properties                   prop is not None. Otherwise, a default set of properties
364                   is created such that: line color = Color.Black, line width = 1,                   is created such that: line color = Black, line width = 1,
365                   and fill color = Color.None                   and fill color = Transparent
366          """          """
367    
         self.stroke = None  
         self.strokeWidth = 0  
         self.fill = None  
   
368          if props is not None:          if props is not None:
369              self.SetProperties(props)              self.SetProperties(props)
370          else:          else:
371              self.SetLineColor(Color.Black)              self.SetLineColor(Black)
372              self.SetLineWidth(1)              self.SetLineWidth(1)
373              self.SetFill(Color.None)              self.SetFill(Transparent)
374    
375      def SetProperties(self, props):      def SetProperties(self, props):
376          """Set this class's properties to those in class props."""          """Set this class's properties to those in class props."""
377    
378          assert(isinstance(props, ClassGroupProperties))          assert isinstance(props, ClassGroupProperties)
379          self.SetLineColor(props.GetLineColor())          self.SetLineColor(props.GetLineColor())
380          self.SetLineWidth(props.GetLineWidth())          self.SetLineWidth(props.GetLineWidth())
381          self.SetFill(props.GetFill())          self.SetFill(props.GetFill())
382                    
383      def GetLineColor(self):      def GetLineColor(self):
384          """Return the line color as a Color object."""          """Return the line color as a Color object."""
385          return self.stroke          return self.__stroke
386    
387      def SetLineColor(self, color):      def SetLineColor(self, color):
388          """Set the line color.          """Set the line color.
# Line 405  class ClassGroupProperties: Line 390  class ClassGroupProperties:
390          color -- the color of the line. This must be a Color object.          color -- the color of the line. This must be a Color object.
391          """          """
392    
393          assert(isinstance(color, Color))          self.__stroke = color
         self.stroke = color  
394    
395      def GetLineWidth(self):      def GetLineWidth(self):
396          """Return the line width."""          """Return the line width."""
397          return self.strokeWidth          return self.__strokeWidth
398    
399      def SetLineWidth(self, lineWidth):      def SetLineWidth(self, lineWidth):
400          """Set the line width.          """Set the line width.
401    
402          lineWidth -- the new line width. This must be > 0.          lineWidth -- the new line width. This must be > 0.
403          """          """
404          assert(isinstance(lineWidth, IntType))          assert isinstance(lineWidth, types.IntType)
405          if (lineWidth < 1):          if (lineWidth < 1):
406              raise ValueError(_("lineWidth < 1"))              raise ValueError(_("lineWidth < 1"))
407    
408          self.strokeWidth = lineWidth          self.__strokeWidth = lineWidth
409    
410      def GetFill(self):      def GetFill(self):
411          """Return the fill color as a Color object."""          """Return the fill color as a Color object."""
412          return self.fill          return self.__fill
413    
414      def SetFill(self, fill):      def SetFill(self, fill):
415          """Set the fill color.          """Set the fill color.
# Line 433  class ClassGroupProperties: Line 417  class ClassGroupProperties:
417          fill -- the color of the fill. This must be a Color object.          fill -- the color of the fill. This must be a Color object.
418          """          """
419    
420          assert(isinstance(fill, Color))          self.__fill = fill
         self.fill = fill  
421    
422      def __eq__(self, other):      def __eq__(self, other):
423          """Return true if 'props' has the same attributes as this class"""          """Return true if 'props' has the same attributes as this class"""
424    
425            #
426            # using 'is' over '==' results in a huge performance gain
427            # in the renderer
428            #
429          return isinstance(other, ClassGroupProperties)   \          return isinstance(other, ClassGroupProperties)   \
430              and self.stroke      == other.GetLineColor() \              and (self.__stroke is other.__stroke or      \
431              and self.strokeWidth == other.GetLineWidth() \                   self.__stroke == other.__stroke)        \
432              and self.fill        == other.GetFill()              and (self.__fill is other.__fill or          \
433                     self.__fill == other.__fill)            \
434                and self.__strokeWidth == other.__strokeWidth
435    
436      def __ne__(self, other):      def __ne__(self, other):
437          return not self.__eq__(other)          return not self.__eq__(other)
# Line 450  class ClassGroupProperties: Line 439  class ClassGroupProperties:
439      def __copy__(self):      def __copy__(self):
440          return ClassGroupProperties(self)          return ClassGroupProperties(self)
441    
442        def __deepcopy__(self):
443            return ClassGroupProperties(self)
444    
445        def __repr__(self):
446            return repr((self.__stroke, self.__strokeWidth, self.__fill))
447    
448  class ClassGroup:  class ClassGroup:
449      """A base class for all Groups within a Classification"""      """A base class for all Groups within a Classification"""
450    
451      def __init__(self, label = ""):      def __init__(self, label = "", props = None, group = None):
452          """Constructor.          """Constructor.
453    
454          label -- A string representing the Group's label          label -- A string representing the Group's label
455          """          """
456    
457          self.label = None          if group is not None:
458                self.SetLabel(copy.copy(group.GetLabel()))
459          self.SetLabel(label)              self.SetProperties(copy.copy(group.GetProperties()))
460                self.SetVisible(group.IsVisible())
461            else:
462                self.SetLabel(label)
463                self.SetProperties(props)
464                self.SetVisible(True)
465    
466      def GetLabel(self):      def GetLabel(self):
467          """Return the Group's label."""          """Return the Group's label."""
# Line 473  class ClassGroup: Line 473  class ClassGroup:
473          label -- a string representing the Group's label. This must          label -- a string representing the Group's label. This must
474                   not be None.                   not be None.
475          """          """
476          assert(isinstance(label, StringType))          assert isinstance(label, types.StringTypes)
477          self.label = label          self.label = label
478    
479      def GetDisplayText(self):      def GetDisplayText(self):
480          assert(False, "GetDisplay must be overridden by subclass!")          assert False, "GetDisplay must be overridden by subclass!"
481          return ""          return ""
482    
483      def Matches(self, value):      def Matches(self, value):
# Line 485  class ClassGroup: Line 485  class ClassGroup:
485    
486          Returns False. This needs to be overridden by all subclasses.          Returns False. This needs to be overridden by all subclasses.
487          """          """
488          assert(False, "GetMatches must be overridden by subclass!")          assert False, "GetMatches must be overridden by subclass!"
489          return False          return False
490    
491      def GetProperties(self):      def GetProperties(self):
492          """Return the properties associated with the given value.          """Return the properties associated with the given value."""
493    
494          Returns None. This needs to be overridden by all subclasses.          return self.prop
         """  
         assert(False, "GetProperties must be overridden by subclass!")  
         return None  
495    
496        def SetProperties(self, prop):
497            """Set the properties associated with this Group.
498    
499            prop -- a ClassGroupProperties object. if prop is None,
500                    a default set of properties is created.
501            """
502    
503            if prop is None: prop = ClassGroupProperties()
504            assert isinstance(prop, ClassGroupProperties)
505            self.prop = prop
506    
507        def IsVisible(self):
508            return self.visible
509    
510        def SetVisible(self, visible):
511            self.visible = visible
512    
513        def __eq__(self, other):
514            return isinstance(other, ClassGroup) \
515                and self.label == other.label \
516                and self.GetProperties() == other.GetProperties()
517    
518        def __ne__(self, other):
519            return not self.__eq__(other)
520    
521        def __repr__(self):
522            return repr(self.label) + ", " + repr(self.GetProperties())
523            
524  class ClassGroupSingleton(ClassGroup):  class ClassGroupSingleton(ClassGroup):
525      """A Group that is associated with a single value."""      """A Group that is associated with a single value."""
526    
527      def __init__(self, value = 0, prop = None, label = ""):      def __init__(self, value = 0, props = None, label = "", group = None):
528          """Constructor.          """Constructor.
529    
530          value -- the associated value.          value -- the associated value.
# Line 510  class ClassGroupSingleton(ClassGroup): Line 534  class ClassGroupSingleton(ClassGroup):
534    
535          label -- a label for this group.          label -- a label for this group.
536          """          """
537          ClassGroup.__init__(self, label)          ClassGroup.__init__(self, label, props, group)
   
         self.prop = None  
         self.value = None  
538    
539          self.SetValue(value)          self.SetValue(value)
         self.SetProperties(prop)  
540    
541      def __copy__(self):      def __copy__(self):
542          return ClassGroupSingleton(self.GetValue(),          return ClassGroupSingleton(self.GetValue(),
# Line 524  class ClassGroupSingleton(ClassGroup): Line 544  class ClassGroupSingleton(ClassGroup):
544                                     self.GetLabel())                                     self.GetLabel())
545    
546      def __deepcopy__(self, memo):      def __deepcopy__(self, memo):
547          return ClassGroupSingleton(copy.copy(self.GetValue()),          return ClassGroupSingleton(self.GetValue(), group = self)
                                    copy.copy(self.GetProperties()),  
                                    copy.copy(self.GetLabel()))  
548    
549      def GetValue(self):      def GetValue(self):
550          """Return the associated value."""          """Return the associated value."""
551          return self.value          return self.__value
552    
553      def SetValue(self, value):      def SetValue(self, value):
554          """Associate this Group with the given value."""          """Associate this Group with the given value."""
555          self.value = value          self.__value = value
556    
557      def Matches(self, value):      def Matches(self, value):
558          """Determine if the given value matches the associated Group value."""          """Determine if the given value matches the associated Group value."""
559    
560          """Returns True if the value matches, False otherwise."""          """Returns True if the value matches, False otherwise."""
561    
562          return self.value == value          return self.__value == value
   
     def GetProperties(self):  
         """Return the Properties associated with this Group."""  
   
         return self.prop  
   
     def SetProperties(self, prop):  
         """Set the properties associated with this Group.  
   
         prop -- a ClassGroupProperties object. if prop is None,  
                 a default set of properties is created.  
         """  
   
         if prop is None: prop = ClassGroupProperties()  
         assert(isinstance(prop, ClassGroupProperties))  
         self.prop = prop  
563    
564      def GetDisplayText(self):      def GetDisplayText(self):
565          label = self.GetLabel()          label = self.GetLabel()
# Line 567  class ClassGroupSingleton(ClassGroup): Line 569  class ClassGroupSingleton(ClassGroup):
569          return str(self.GetValue())          return str(self.GetValue())
570    
571      def __eq__(self, other):      def __eq__(self, other):
572          return isinstance(other, ClassGroupSingleton) \          return ClassGroup.__eq__(self, other) \
573              and self.GetProperties() == other.GetProperties() \              and isinstance(other, ClassGroupSingleton) \
574              and self.GetValue() == other.GetValue()              and self.__value == other.__value
575    
576      def __ne__(self, other):      def __repr__(self):
577          return not self.__eq__(other)          return "(" + repr(self.__value) + ", " + ClassGroup.__repr__(self) + ")"
578    
579  class ClassGroupDefault(ClassGroup):  class ClassGroupDefault(ClassGroup):
580      """The default Group. When values do not match any other      """The default Group. When values do not match any other
581         Group within a Classification, the properties from this         Group within a Classification, the properties from this
582         class are used."""         class are used."""
583    
584      def __init__(self, prop = None, label = ""):      def __init__(self, props = None, label = "", group = None):
585          """Constructor.          """Constructor.
586    
587          prop -- a ClassGroupProperites object. If prop is None a default          prop -- a ClassGroupProperites object. If prop is None a default
# Line 588  class ClassGroupDefault(ClassGroup): Line 590  class ClassGroupDefault(ClassGroup):
590          label -- a label for this group.          label -- a label for this group.
591          """          """
592    
593          ClassGroup.__init__(self, label)          ClassGroup.__init__(self, label, props, group)
         self.SetProperties(prop)  
594    
595      def __copy__(self):      def __copy__(self):
596          return ClassGroupDefault(self.GetProperties(), self.GetLabel())          return ClassGroupDefault(self.GetProperties(), self.GetLabel())
597    
598      def __deepcopy__(self, memo):      def __deepcopy__(self, memo):
599          return ClassGroupDefault(copy.copy(self.GetProperties()),          return ClassGroupDefault(label = self.GetLabel(), group = self)
                                  copy.copy(self.GetLabel()))  
600    
601      def Matches(self, value):      def Matches(self, value):
602          return True          return True
603    
     def GetProperties(self):  
         """Return the Properties associated with this Group."""  
         return self.prop  
   
     def SetProperties(self, prop):  
         """Set the properties associated with this Group.  
   
         prop -- a ClassGroupProperties object. if prop is None,  
                 a default set of properties is created.  
         """  
   
         if prop is None: prop = ClassGroupProperties()  
         assert(isinstance(prop, ClassGroupProperties))  
         self.prop = prop  
   
604      def GetDisplayText(self):      def GetDisplayText(self):
605          label = self.GetLabel()          label = self.GetLabel()
606    
607          if label != "": return label          if label != "": return label
608    
609          return "DEFAULT"          return _("DEFAULT")
610    
611      def __eq__(self, other):      def __eq__(self, other):
612          return isinstance(other, ClassGroupDefault) \          return ClassGroup.__eq__(self, other) \
613                and isinstance(other, ClassGroupDefault) \
614              and self.GetProperties() == other.GetProperties()              and self.GetProperties() == other.GetProperties()
615    
616      def __ne__(self, other):      def __repr__(self):
617          return not self.__eq__(other)          return "(" + ClassGroup.__repr__(self) + ")"
618    
619  class ClassGroupRange(ClassGroup):  class ClassGroupRange(ClassGroup):
620      """A Group that represents a range of values that map to the same      """A Group that represents a range of values that map to the same
621         set of properties."""         set of properties."""
622    
623      def __init__(self, min = 0, max = 1, prop = None, label = ""):      def __init__(self, _range = (0,1), props = None, label = "", group=None):
624          """Constructor.          """Constructor.
625    
626          The minumum value must be strictly less than the maximum.          The minumum value must be strictly less than the maximum.
627    
628          min -- the minimum range value          _range -- either a tuple (min, max) where min < max or
629                      a Range object
         max -- the maximum range value  
630    
631          prop -- a ClassGroupProperites object. If prop is None a default          prop -- a ClassGroupProperites object. If prop is None a default
632                   set of properties is created.                   set of properties is created.
# Line 649  class ClassGroupRange(ClassGroup): Line 634  class ClassGroupRange(ClassGroup):
634          label -- a label for this group.          label -- a label for this group.
635          """          """
636    
637          ClassGroup.__init__(self, label)          ClassGroup.__init__(self, label, props, group)
638            self.SetRange(_range)
         self.min = self.max = 0  
         self.prop = None  
   
         self.SetRange(min, max)  
         self.SetProperties(prop)  
639    
640      def __copy__(self):      def __copy__(self):
641          return ClassGroupRange(self.GetMin(),          return ClassGroupRange(self.__range,
642                                 self.GetMax(),                                 props = self.GetProperties(),
643                                 self.GetProperties(),                                 label = self.GetLabel())
                                self.GetLabel())  
644    
645      def __deepcopy__(self, memo):      def __deepcopy__(self, memo):
646          return ClassGroupRange(copy.copy(self.GetMin()),          return ClassGroupRange(copy.copy(self.__range),
647                                 copy.copy(self.GetMax()),                                 group = self)
                                copy.copy(self.GetProperties()),  
                                copy.copy(self.GetLabel()))  
648    
649      def GetMin(self):      def GetMin(self):
650          """Return the range's minimum value."""          """Return the range's minimum value."""
651          return self.min          return self.__range.GetRange()[1]
652    
653      def SetMin(self, min):      def SetMin(self, min):
654          """Set the range's minimum value.          """Set the range's minimum value.
# Line 680  class ClassGroupRange(ClassGroup): Line 657  class ClassGroupRange(ClassGroup):
657                 maximum value. Use SetRange() to change both min and max values.                 maximum value. Use SetRange() to change both min and max values.
658          """          """
659            
660          self.SetRange(min, self.max)          self.SetRange((min, self.__range.GetRange()[2]))
661    
662      def GetMax(self):      def GetMax(self):
663          """Return the range's maximum value."""          """Return the range's maximum value."""
664          return self.max          return self.__range.GetRange()[2]
665    
666      def SetMax(self, max):      def SetMax(self, max):
667          """Set the range's maximum value.          """Set the range's maximum value.
# Line 692  class ClassGroupRange(ClassGroup): Line 669  class ClassGroupRange(ClassGroup):
669          max -- the new maximum. Note that this must be greater than the current          max -- the new maximum. Note that this must be greater than the current
670                 minimum value. Use SetRange() to change both min and max values.                 minimum value. Use SetRange() to change both min and max values.
671          """          """
672          self.SetRange(self.min, max)          self.SetRange((self.__range.GetRange()[1], max))
673    
674      def SetRange(self, min, max):      def SetRange(self, _range):
675          """Set a new range.          """Set a new range.
676    
677          Note that min must be strictly less than max.          _range -- Either a tuple (min, max) where min < max or
678                      a Range object.
679    
680          min -- the new minimum value          Raises ValueError on error.
         min -- the new maximum value  
681          """          """
682    
683          if min >= max:          if isinstance(_range, Range):
684              raise ValueError(_("ClassGroupRange: %i(min) >= %i(max)!") %              self.__range = _range
685                               (min, max))          elif isinstance(_range, types.TupleType) and len(_range) == 2:
686          self.min = min              self.__range = Range(("[", _range[0], _range[1], "["))
687          self.max = max          else:
688                raise ValueError()
689    
690      def GetRange(self):      def GetRange(self):
691          """Return the range as a tuple (min, max)"""          """Return the range as a string"""
692          return (self.min, self.max)          return self.__range.string(self.__range.GetRange())
693    
694        def GetRangeTuple(self):
695            return self.__range.GetRange()
696    
697      def Matches(self, value):      def Matches(self, value):
698          """Determine if the given value lies with the current range.          """Determine if the given value lies with the current range.
# Line 719  class ClassGroupRange(ClassGroup): Line 700  class ClassGroupRange(ClassGroup):
700          The following check is used: min <= value < max.          The following check is used: min <= value < max.
701          """          """
702    
703          return self.min <= value < self.max          return operator.contains(self.__range, value)
   
     def GetProperties(self):  
         """Return the Properties associated with this Group."""  
         return self.prop  
   
     def SetProperties(self, prop):  
         """Set the properties associated with this Group.  
   
         prop -- a ClassGroupProperties object. if prop is None,  
                 a default set of properties is created.  
         """  
         if prop is None: prop = ClassGroupProperties()  
         assert(isinstance(prop, ClassGroupProperties))  
         self.prop = prop  
704    
705      def GetDisplayText(self):      def GetDisplayText(self):
706          label = self.GetLabel()          label = self.GetLabel()
707    
708          if label != "": return label          if label != "": return label
709    
710          return _("%s - %s") % (self.GetMin(), self.GetMax())          return self.__range.string(self.__range.GetRange())
711    
712      def __eq__(self, other):      def __eq__(self, other):
713          return isinstance(other, ClassGroupRange) \          return ClassGroup.__eq__(self, other) \
714              and self.GetProperties() == other.GetProperties() \              and isinstance(other, ClassGroupRange) \
715              and self.GetRange() == other.GetRange()              and self.__range == other.__range
716    
717      def __ne__(self, other):      def __repr__(self):
718          return not self.__eq__(other)          return "(" + str(self.__range) + ClassGroup.__repr__(self) + ")"
719    
720  class ClassGroupMap(ClassGroup):  class ClassGroupMap(ClassGroup):
721      """Currently, this class is not used."""      """Currently, this class is not used."""

Legend:
Removed from v.544  
changed lines
  Added in v.1912

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26