/[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 479 by jonathan, Thu Mar 6 16:46:07 2003 UTC revision 2374 by jan, Sun Oct 3 21:01:31 2004 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  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        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."""  
   
     def __init__(self, layer = None, field = None):  
         """Initialize a classification.  
39    
40             layer -- the Layer object who owns this classification  class Classification(Publisher):
41        """Encapsulates the classification of layer.
42        
43        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.__sendMessages = False  
52    
         self.__ToggleMessages(False)  
53          self.SetDefaultGroup(ClassGroupDefault())          self.SetDefaultGroup(ClassGroupDefault())
         self.SetLayer(layer)  
         self.SetField(field)  
   
         self.__ToggleMessages(True)  
54    
55      def __iter__(self):      def __iter__(self):
56          return ClassIterator(self.groups)          return ClassIterator(self.__groups)
   
     def __ToggleMessages(self, on):  
         self.__sendMessages = on  
   
     def __SendMessage(self, message):  
         """Send the message 'message' to the parent layer."""  
         if self.__sendMessages and self.layer is not None:  
             self.layer.changed(message, self.layer)  
       
     def SetField(self, field = None):  
         """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  
   
         self.field = field  
   
         if self.layer is not None:  
             fieldType = self.layer.GetFieldType(field)  
         else:  
             fieldType = None  
   
         self.SetFieldType(fieldType)  
   
         # XXX: if fieldType comes back None then field isn't in the table!  
   
         self.__SendMessage(LAYER_LEGEND_CHANGED)  
57    
58      def GetField(self):      def __deepcopy__(self, memo):
59          """Return the name of the field."""          clazz = Classification()
         return self.field  
60    
61      def GetFieldType(self):          clazz.__groups[0] = copy.deepcopy(self.__groups[0])
         """Return the field type."""  
         return self.fieldType  
62    
63      def SetFieldType(self, type):          for i in range(1, len(self.__groups)):
64          self.fieldType = type              clazz.__groups.append(copy.deepcopy(self.__groups[i]))
65    
66      def SetLayer(self, layer):          return clazz
67          """Set the owning Layer of this classification."""  
68        def __SendNotification(self):
69          if __debug__:          """Notify the layer that this class has changed."""
70              if layer is not None:          self.issue(CLASS_CHANGED)
71                  assert(isinstance(layer, Thuban.Model.layer.Layer))  
72        def __getattr__(self, attr):
73          # prevent infinite recursion when calling SetClassification()          """Generate the compiled classification on demand"""
74          if self.layer is not None and layer == self.layer:          if attr == "_compiled_classification":
75              return              self._compile_classification()
76                return self._compiled_classification
77          self.layer = layer          raise AttributeError(attr)
78          self.SetField(self.GetField()) # XXX: this sync's the fieldType  
79        def _compile_classification(self):
80          if self.layer is not None:          """Generate the compiled classification
81              self.layer.SetClassification(self)  
82            The compiled classification is a more compact representation of
83          #self.__SendMessage(LAYER_LEGEND_CHANGED)          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:
132                    raise TypeError("Unknown group type %s", group)
133            self._compiled_classification = compiled
134    
135      def GetLayer(self):      def _clear_compiled_classification(self):
136          """Return the parent layer."""          """Reset the compiled classification.
         return self.layer  
137    
138      def SetDefaultGroup(self, group):          If will be created on demand when self._compiled_classification
139          """Set the group to be used when a value can't be classified.          is accessed again.
140    
141             group -- group that the value maps to.          Call this method whenever self.__groups is modified.
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 161  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.__SendMessage(LAYER_LEGEND_CHANGED)          self.__SendNotification()
161                    
162      def GetDefaultFill(self):      def GetDefaultFill(self):
163          """Return the default fill color."""          """Return the default fill color."""
# Line 174  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.__SendMessage(LAYER_LEGEND_CHANGED)          self.__SendNotification()
173                    
174      def GetDefaultLineColor(self):      def GetDefaultLineColor(self):
175          """Return the default line color."""          """Return the default line color."""
# Line 187  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.__SendMessage(LAYER_LEGEND_CHANGED)          self.__SendNotification()
186                    
187      def GetDefaultLineWidth(self):      def GetDefaultLineWidth(self):
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              #self.SetDefaultGroup(item)          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.__SendMessage(LAYER_LEGEND_CHANGED)  
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 244  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 269  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    
319  class ClassIterator:  class ClassIterator:
320      """Allows the Groups in a Classifcation to be interated over.      """Allows the Groups in a Classifcation to be interated over.
321    
# Line 290  class ClassIterator: Line 327  class ClassIterator:
327          """Constructor.          """Constructor.
328    
329          default -- the default group          default -- the default group
330    
331          points -- a list of singleton groups          points -- a list of singleton groups
332    
333          ranges -- a list of range groups          ranges -- a list of range groups
334    
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 315  class ClassIterator: Line 350  class ClassIterator:
350              d = self.data[self.data_index]              d = self.data[self.data_index]
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      
357      These are used when rendering a layer."""      These are used when rendering a layer."""
358    
359        # TODO: Actually, size is only relevant for point objects.
360        # Eventually it should be spearated, e.g. when introducing symbols.
361    
362      def __init__(self, props = None):      def __init__(self, props = None):
363          """Constructor.          """Constructor.
364    
365          props -- a ClassGroupProperties object. The class is copied if          props -- a ClassGroupProperties object. The class is copied if
366                   prop is not None. Otherwise, a default set of properties                   prop is not None. Otherwise, a default set of properties
367                   is created such that: line color = Color.Black, line width = 1,                   is created such that: line color = Black, line width = 1,
368                   and fill color = Color.None                   size = 5 and fill color = Transparent
369          """          """
370    
         self.stroke = None  
         self.strokeWidth = 0  
         self.fill = None  
   
371          if props is not None:          if props is not None:
372              self.SetProperties(props)              self.SetProperties(props)
373          else:          else:
374              self.SetLineColor(Color.None)              self.SetLineColor(Black)
375              self.SetLineWidth(1)              self.SetLineWidth(1)
376              self.SetFill(Color.None)              self.SetSize(5)
377                self.SetFill(Transparent)
378    
379      def SetProperties(self, props):      def SetProperties(self, props):
380          """Set this class's properties to those in class props."""          """Set this class's properties to those in class props."""
381    
382          assert(isinstance(props, ClassGroupProperties))          assert isinstance(props, ClassGroupProperties)
383          self.SetLineColor(props.GetLineColor())          self.SetLineColor(props.GetLineColor())
384          self.SetLineWidth(props.GetLineWidth())          self.SetLineWidth(props.GetLineWidth())
385            self.SetSize(props.GetSize())
386          self.SetFill(props.GetFill())          self.SetFill(props.GetFill())
387            
388      def GetLineColor(self):      def GetLineColor(self):
389          """Return the line color as a Color object."""          """Return the line color as a Color object."""
390          return self.stroke          return self.__stroke
391    
392      def SetLineColor(self, color):      def SetLineColor(self, color):
393          """Set the line color.          """Set the line color.
# Line 372  class ClassGroupProperties: Line 395  class ClassGroupProperties:
395          color -- the color of the line. This must be a Color object.          color -- the color of the line. This must be a Color object.
396          """          """
397    
398          assert(isinstance(color, Color))          self.__stroke = color
         self.stroke = color  
399    
400      def GetLineWidth(self):      def GetLineWidth(self):
401          """Return the line width."""          """Return the line width."""
402          return self.strokeWidth          return self.__strokeWidth
403    
404      def SetLineWidth(self, lineWidth):      def SetLineWidth(self, lineWidth):
405          """Set the line width.          """Set the line width.
406    
407          lineWidth -- the new line width. This must be > 0.          lineWidth -- the new line width. This must be > 0.
408          """          """
409          assert(isinstance(lineWidth, IntType))          assert isinstance(lineWidth, types.IntType)
410          if (lineWidth < 1):          if (lineWidth < 1):
411              raise ValueError(_("lineWidth < 1"))              raise ValueError(_("lineWidth < 1"))
412    
413          self.strokeWidth = lineWidth          self.__strokeWidth = lineWidth
414    
415        def GetSize(self):
416            """Return the size."""
417            return self.__size
418    
419        def SetSize(self, size):
420            """Set the size.
421    
422            size -- the new size. This must be > 0.
423            """
424            assert isinstance(size, types.IntType)
425            if (size < 1):
426                raise ValueError(_("size < 1"))
427    
428            self.__size = size
429    
430      def GetFill(self):      def GetFill(self):
431          """Return the fill color as a Color object."""          """Return the fill color as a Color object."""
432          return self.fill          return self.__fill
433    
434      def SetFill(self, fill):      def SetFill(self, fill):
435          """Set the fill color.          """Set the fill color.
436    
437          fill -- the color of the fill. This must be a Color object.          fill -- the color of the fill. This must be a Color object.
438          """          """
439    
440          assert(isinstance(fill, Color))          self.__fill = fill
         self.fill = fill  
441    
442      def __eq__(self, other):      def __eq__(self, other):
443          """Return true if 'props' has the same attributes as this class"""          """Return true if 'props' has the same attributes as this class"""
444    
445            #
446            # using 'is' over '==' results in a huge performance gain
447            # in the renderer
448            #
449          return isinstance(other, ClassGroupProperties)   \          return isinstance(other, ClassGroupProperties)   \
450              and self.stroke      == other.GetLineColor() \              and (self.__stroke is other.__stroke or      \
451              and self.strokeWidth == other.GetLineWidth() \                   self.__stroke == other.__stroke)        \
452              and self.fill        == other.GetFill()              and (self.__fill is other.__fill or          \
453                     self.__fill == other.__fill)            \
454                and self.__strokeWidth == other.__strokeWidth\
455                and self.__size == other.__size
456    
457      def __ne__(self, other):      def __ne__(self, other):
458          return not self.__eq__(other)          return not self.__eq__(other)
459    
460        def __copy__(self):
461            return ClassGroupProperties(self)
462    
463        def __deepcopy__(self):
464            return ClassGroupProperties(self)
465    
466        def __repr__(self):
467            return repr((self.__stroke, self.__strokeWidth, self.__size,
468                        self.__fill))
469    
470  class ClassGroup:  class ClassGroup:
471      """A base class for all Groups within a Classification"""      """A base class for all Groups within a Classification"""
472    
473      def __init__(self, label = ""):      def __init__(self, label = "", props = None, group = None):
474          """Constructor.          """Constructor.
475    
476          label -- A string representing the Group's label          label -- A string representing the Group's label
477          """          """
478    
479          self.label = None          if group is not None:
480                self.SetLabel(copy.copy(group.GetLabel()))
481          self.SetLabel(label)              self.SetProperties(copy.copy(group.GetProperties()))
482                self.SetVisible(group.IsVisible())
483            else:
484                self.SetLabel(label)
485                self.SetProperties(props)
486                self.SetVisible(True)
487    
488      def GetLabel(self):      def GetLabel(self):
489          """Return the Group's label."""          """Return the Group's label."""
490          return self.label          return self.label
491    
492      def SetLabel(self, label):      def SetLabel(self, label):
493          """Set the Group's label.          """Set the Group's label.
494    
495          label -- a string representing the Group's label. This must          label -- a string representing the Group's label. This must
496                   not be None.                   not be None.
497          """          """
498          assert(isinstance(label, StringType))          assert isinstance(label, types.StringTypes)
499          self.label = label          self.label = label
500    
501        def GetDisplayText(self):
502            assert False, "GetDisplay must be overridden by subclass!"
503            return ""
504    
505      def Matches(self, value):      def Matches(self, value):
506          """Determines if this Group is associated with the given value.          """Determines if this Group is associated with the given value.
507    
508          Returns False. This needs to be overridden by all subclasses.          Returns False. This needs to be overridden by all subclasses.
509          """          """
510            assert False, "GetMatches must be overridden by subclass!"
511          return False          return False
512    
513      def GetProperties(self):      def GetProperties(self):
514          """Return the properties associated with the given value.          """Return the properties associated with the given value."""
515    
516          Returns None. This needs to be overridden by all subclasses.          return self.prop
         """  
         return None  
517    
518        def SetProperties(self, prop):
519            """Set the properties associated with this Group.
520    
521            prop -- a ClassGroupProperties object. if prop is None,
522                    a default set of properties is created.
523            """
524    
525            if prop is None: prop = ClassGroupProperties()
526            assert isinstance(prop, ClassGroupProperties)
527            self.prop = prop
528    
529        def IsVisible(self):
530            return self.visible
531    
532        def SetVisible(self, visible):
533            self.visible = visible
534    
535        def __eq__(self, other):
536            return isinstance(other, ClassGroup) \
537                and self.label == other.label \
538                and self.GetProperties() == other.GetProperties()
539    
540        def __ne__(self, other):
541            return not self.__eq__(other)
542    
543        def __repr__(self):
544            return repr(self.label) + ", " + repr(self.GetProperties())
545            
546  class ClassGroupSingleton(ClassGroup):  class ClassGroupSingleton(ClassGroup):
547      """A Group that is associated with a single value."""      """A Group that is associated with a single value."""
548    
549      def __init__(self, value = 0, prop = None, label = ""):      def __init__(self, value = 0, props = None, label = "", group = None):
550          """Constructor.          """Constructor.
551    
552          value -- the associated value.          value -- the associated value.
# Line 468  class ClassGroupSingleton(ClassGroup): Line 556  class ClassGroupSingleton(ClassGroup):
556    
557          label -- a label for this group.          label -- a label for this group.
558          """          """
559          ClassGroup.__init__(self, label)          ClassGroup.__init__(self, label, props, group)
   
         self.prop = None  
         self.value = None  
560    
561          self.SetValue(value)          self.SetValue(value)
         self.SetProperties(prop)  
562    
563      def __copy__(self):      def __copy__(self):
564          return ClassGroupSingleton(self.GetValue(),          return ClassGroupSingleton(self.GetValue(),
565                                     self.GetProperties(),                                     self.GetProperties(),
566                                     self.GetLabel())                                     self.GetLabel())
567    
568        def __deepcopy__(self, memo):
569            return ClassGroupSingleton(self.GetValue(), group = self)
570    
571      def GetValue(self):      def GetValue(self):
572          """Return the associated value."""          """Return the associated value."""
573          return self.value          return self.__value
574    
575      def SetValue(self, value):      def SetValue(self, value):
576          """Associate this Group with the given value."""          """Associate this Group with the given value."""
577          self.value = value          self.__value = value
578    
579      def Matches(self, value):      def Matches(self, value):
580          """Determine if the given value matches the associated Group value."""          """Determine if the given value matches the associated Group value."""
581    
582          """Returns True if the value matches, False otherwise."""          """Returns True if the value matches, False otherwise."""
583    
584          return self.value == value          return self.__value == value
585    
586      def GetProperties(self):      def GetDisplayText(self):
587          """Return the Properties associated with this Group."""          label = self.GetLabel()
588    
589          return self.prop          if label != "": return label
   
     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.  
         """  
590    
591          if prop is None: prop = ClassGroupProperties()          return str(self.GetValue())
         assert(isinstance(prop, ClassGroupProperties))  
         self.prop = prop  
592    
593      def __eq__(self, other):      def __eq__(self, other):
594          return isinstance(other, ClassGroupSingleton) \          return ClassGroup.__eq__(self, other) \
595              and self.GetProperties() == other.GetProperties() \              and isinstance(other, ClassGroupSingleton) \
596              and self.GetValue() == other.GetValue()              and self.__value == other.__value
597    
598      def __ne__(self, other):      def __repr__(self):
599          return not self.__eq__(other)          return "(" + repr(self.__value) + ", " + ClassGroup.__repr__(self) + ")"
600    
601  class ClassGroupDefault(ClassGroup):  class ClassGroupDefault(ClassGroup):
602      """The default Group. When values do not match any other      """The default Group. When values do not match any other
603         Group within a Classification, the properties from this         Group within a Classification, the properties from this
604         class are used."""         class are used."""
605    
606      def __init__(self, prop = None, label = ""):      def __init__(self, props = None, label = "", group = None):
607          """Constructor.          """Constructor.
608    
609          prop -- a ClassGroupProperites object. If prop is None a default          prop -- a ClassGroupProperites object. If prop is None a default
# Line 534  class ClassGroupDefault(ClassGroup): Line 612  class ClassGroupDefault(ClassGroup):
612          label -- a label for this group.          label -- a label for this group.
613          """          """
614    
615          ClassGroup.__init__(self, label)          ClassGroup.__init__(self, label, props, group)
         self.SetProperties(prop)  
616    
617      def __copy__(self):      def __copy__(self):
618          return ClassGroupDefault(self.GetProperties(), self.GetLabel())          return ClassGroupDefault(self.GetProperties(), self.GetLabel())
619    
620        def __deepcopy__(self, memo):
621            return ClassGroupDefault(label = self.GetLabel(), group = self)
622    
623      def Matches(self, value):      def Matches(self, value):
624          return True          return True
625    
626      def GetProperties(self):      def GetDisplayText(self):
627          """Return the Properties associated with this Group."""          label = self.GetLabel()
         return self.prop  
628    
629      def SetProperties(self, prop):          if label != "": return label
         """Set the properties associated with this Group.  
630    
631          prop -- a ClassGroupProperties object. if prop is None,          return _("DEFAULT")
                 a default set of properties is created.  
         """  
   
         if prop is None: prop = ClassGroupProperties()  
         assert(isinstance(prop, ClassGroupProperties))  
         self.prop = prop  
632    
633      def __eq__(self, other):      def __eq__(self, other):
634          return isinstance(other, ClassGroupDefault) \          return ClassGroup.__eq__(self, other) \
635                and isinstance(other, ClassGroupDefault) \
636              and self.GetProperties() == other.GetProperties()              and self.GetProperties() == other.GetProperties()
637    
638      def __ne__(self, other):      def __repr__(self):
639          return not self.__eq__(other)          return "(" + ClassGroup.__repr__(self) + ")"
640    
641  class ClassGroupRange(ClassGroup):  class ClassGroupRange(ClassGroup):
642      """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
643         set of properties."""         set of properties."""
644    
645      def __init__(self, min = 0, max = 1, prop = None, label = ""):      def __init__(self, _range = (0,1), props = None, label = "", group=None):
646          """Constructor.          """Constructor.
647    
648          The minumum value must be strictly less than the maximum.          The minumum value must be strictly less than the maximum.
649    
650          min -- the minimum range value          _range -- either a tuple (min, max) where min < max or
651                      a Range object
         max -- the maximum range value  
652    
653          prop -- a ClassGroupProperites object. If prop is None a default          prop -- a ClassGroupProperites object. If prop is None a default
654                   set of properties is created.                   set of properties is created.
# Line 584  class ClassGroupRange(ClassGroup): Line 656  class ClassGroupRange(ClassGroup):
656          label -- a label for this group.          label -- a label for this group.
657          """          """
658    
659          ClassGroup.__init__(self, label)          ClassGroup.__init__(self, label, props, group)
660            self.SetRange(_range)
         self.min = self.max = 0  
         self.prop = None  
   
         self.SetRange(min, max)  
         self.SetProperties(prop)  
661    
662      def __copy__(self):      def __copy__(self):
663          return ClassGroupRange(self.GetMin(),          return ClassGroupRange(self.__range,
664                                 self.GetMax(),                                 props = self.GetProperties(),
665                                 self.GetProperties(),                                 label = self.GetLabel())
666                                 self.GetLabel())  
667        def __deepcopy__(self, memo):
668            return ClassGroupRange(copy.copy(self.__range),
669                                   group = self)
670    
671      def GetMin(self):      def GetMin(self):
672          """Return the range's minimum value."""          """Return the range's minimum value."""
673          return self.min          return self.__range.GetRange()[1]
674    
675      def SetMin(self, min):      def SetMin(self, min):
676          """Set the range's minimum value.          """Set the range's minimum value.
# Line 609  class ClassGroupRange(ClassGroup): Line 679  class ClassGroupRange(ClassGroup):
679                 maximum value. Use SetRange() to change both min and max values.                 maximum value. Use SetRange() to change both min and max values.
680          """          """
681            
682          self.SetRange(min, self.max)          self.SetRange((min, self.__range.GetRange()[2]))
683    
684      def GetMax(self):      def GetMax(self):
685          """Return the range's maximum value."""          """Return the range's maximum value."""
686          return self.max          return self.__range.GetRange()[2]
687    
688      def SetMax(self, max):      def SetMax(self, max):
689          """Set the range's maximum value.          """Set the range's maximum value.
# Line 621  class ClassGroupRange(ClassGroup): Line 691  class ClassGroupRange(ClassGroup):
691          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
692                 minimum value. Use SetRange() to change both min and max values.                 minimum value. Use SetRange() to change both min and max values.
693          """          """
694          self.SetRange(self.min, max)          self.SetRange((self.__range.GetRange()[1], max))
695    
696      def SetRange(self, min, max):      def SetRange(self, _range):
697          """Set a new range.          """Set a new range.
698    
699          Note that min must be strictly less than max.          _range -- Either a tuple (min, max) where min < max or
700                      a Range object.
701    
702          min -- the new minimum value          Raises ValueError on error.
         min -- the new maximum value  
703          """          """
704    
705          if min >= max:          if isinstance(_range, Range):
706              raise ValueError(_("ClassGroupRange: %i(min) >= %i(max)!") %              self.__range = _range
707                               (min, max))          elif isinstance(_range, types.TupleType) and len(_range) == 2:
708          self.min = min              self.__range = Range(("[", _range[0], _range[1], "["))
709          self.max = max          else:
710                raise ValueError()
711    
712      def GetRange(self):      def GetRange(self):
713          """Return the range as a tuple (min, max)"""          """Return the range as a string"""
714          return (self.min, self.max)          return self.__range.string(self.__range.GetRange())
715    
716        def GetRangeTuple(self):
717            return self.__range.GetRange()
718    
719      def Matches(self, value):      def Matches(self, value):
720          """Determine if the given value lies with the current range.          """Determine if the given value lies with the current range.
# Line 648  class ClassGroupRange(ClassGroup): Line 722  class ClassGroupRange(ClassGroup):
722          The following check is used: min <= value < max.          The following check is used: min <= value < max.
723          """          """
724    
725          return self.min <= value < self.max          return operator.contains(self.__range, value)
726    
727      def GetProperties(self):      def GetDisplayText(self):
728          """Return the Properties associated with this Group."""          label = self.GetLabel()
         return self.prop  
729    
730      def SetProperties(self, prop):          if label != "": return label
         """Set the properties associated with this Group.  
731    
732          prop -- a ClassGroupProperties object. if prop is None,          return self.__range.string(self.__range.GetRange())
                 a default set of properties is created.  
         """  
         if prop is None: prop = ClassGroupProperties()  
         assert(isinstance(prop, ClassGroupProperties))  
         self.prop = prop  
733    
734      def __eq__(self, other):      def __eq__(self, other):
735          return isinstance(other, ClassGroupRange) \          return ClassGroup.__eq__(self, other) \
736              and self.GetProperties() == other.GetProperties() \              and isinstance(other, ClassGroupRange) \
737              and self.GetRange() == other.GetRange()              and self.__range == other.__range
738    
739      def __ne__(self, other):      def __repr__(self):
740          return not self.__eq__(other)          return "(" + str(self.__range) + ClassGroup.__repr__(self) + ")"
741    
742  class ClassGroupMap(ClassGroup):  class ClassGroupMap(ClassGroup):
743      """Currently, this class is not used."""      """Currently, this class is not used."""
# Line 695  class ClassGroupMap(ClassGroup): Line 762  class ClassGroupMap(ClassGroup):
762      def GetPropertiesFromValue(self, value):      def GetPropertiesFromValue(self, value):
763          pass          pass
764    
765        def GetDisplayText(self):
766            return "Map: " + self.map_type
767    
768      #      #
769      # built-in mappings      # built-in mappings
770      #      #

Legend:
Removed from v.479  
changed lines
  Added in v.2374

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26