/[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 960 by jonathan, Wed May 21 17:23:11 2003 UTC revision 1426 by jonathan, Wed Jul 16 13:22:20 2003 UTC
# Line 20  See the description of FindGroup() for m Line 20  See the description of FindGroup() for m
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  
   
 import copy, operator  
24    
25  from Thuban import _  from Thuban import _
26    
 import types  
   
27  from messages import \  from messages import \
28      LAYER_PROJECTION_CHANGED, \      LAYER_PROJECTION_CHANGED, \
29      LAYER_LEGEND_CHANGED, \      LAYER_LEGEND_CHANGED, \
30      LAYER_VISIBILITY_CHANGED      LAYER_VISIBILITY_CHANGED,\
31        CLASS_CHANGED
32    
33  from Thuban.Model.color import Color  from Thuban.Model.color import Color, Transparent, Black
34  from Thuban.Model.range import Range  from Thuban.Model.range import Range
35    
36  import Thuban.Model.layer  import Thuban.Model.layer
37    
38  class Classification:  from Thuban.Lib.connector import Publisher
39    
40    class Classification(Publisher):
41      """Encapsulates the classification of layer.      """Encapsulates the classification of layer.
42            
43      The Classification divides some kind of data into Groups which      The Classification divides some kind of data into Groups which
# Line 47  class Classification: Line 45  class Classification:
45      retrieved by matching data values to the appropriate group.      retrieved by matching data values to the appropriate group.
46      """      """
47    
48      def __init__(self, layer = None, field = None):      def __init__(self):
49          """Initialize a classification.          """Initialize a classification."""
   
         layer -- the Layer object who owns this classification  
   
         field -- the name of the data table field that  
                  is to be used to classify layer properties  
         """  
50    
         self.layer = None  
         self.field = None  
         self.fieldType = None  
51          self.__groups = []          self.__groups = []
52    
         self.__setLayerLock = False  
   
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)
57    
58      def __deepcopy__(self, memo):      def __deepcopy__(self, memo):
59          clazz = Classification()          clazz = Classification()
60    
         # note: the only thing that isn't copied is the layer reference  
         clazz.field = self.field  
         clazz.fieldType = self.fieldType  
61          clazz.__groups[0] = copy.deepcopy(self.__groups[0])          clazz.__groups[0] = copy.deepcopy(self.__groups[0])
62    
63          for i in range(1, len(self.__groups)):          for i in range(1, len(self.__groups)):
# Line 86  class Classification: Line 67  class Classification:
67    
68      def __SendNotification(self):      def __SendNotification(self):
69          """Notify the layer that this class has changed."""          """Notify the layer that this class has changed."""
70          if self.layer is not None:          self.issue(CLASS_CHANGED)
             self.layer.ClassChanged()  
71            
     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.  
         """  
   
         if type != self.fieldType:  
             if self.layer is not None:  
                 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  
   
         self.__setLayerLock = True  
   
         if layer is None:  
             if self.layer is not None:  
                 l = self.layer  
                 self.layer = None  
                 l.SetClassification(None)  
         else:  
             assert isinstance(layer, Thuban.Model.layer.Layer)  
   
             old_layer = self.layer  
   
             self.layer = layer  
   
             try:  
                 self.SetField(self.GetField()) # this sync's the fieldType  
             except ValueError:  
                 self.layer = old_layer  
                 self.__setLayerLock = False  
                 raise ValueError  
             else:  
                 self.layer.SetClassification(self)  
   
         self.__setLayerLock = False  
   
     def GetLayer(self):  
         """Return the parent layer."""  
         return self.layer  
   
   
72      #      #
73      # these SetDefault* methods are really only provided for      # these SetDefault* methods are really only provided for
74      # some backward compatibility. they should be considered      # some backward compatibility. they should be considered
# Line 197  class Classification: Line 80  class Classification:
80    
81          fill -- a Color object.          fill -- a Color object.
82          """          """
         assert isinstance(fill, Color)  
83          self.GetDefaultGroup().GetProperties().SetFill(fill)          self.GetDefaultGroup().GetProperties().SetFill(fill)
84          self.__SendNotification()          self.__SendNotification()
85                    
# Line 210  class Classification: Line 92  class Classification:
92    
93          color -- a Color object.          color -- a Color object.
94          """          """
         assert isinstance(color, Color)  
95          self.GetDefaultGroup().GetProperties().SetLineColor(color)          self.GetDefaultGroup().GetProperties().SetLineColor(color)
96          self.__SendNotification()          self.__SendNotification()
97                    
# Line 265  class Classification: Line 146  class Classification:
146          self.InsertGroup(self.GetNumGroups(), item)          self.InsertGroup(self.GetNumGroups(), item)
147    
148      def InsertGroup(self, index, group):      def InsertGroup(self, index, group):
           
149          assert isinstance(group, ClassGroup)          assert isinstance(group, ClassGroup)
   
150          self.__groups.insert(index + 1, group)          self.__groups.insert(index + 1, group)
   
151          self.__SendNotification()          self.__SendNotification()
152    
153      def RemoveGroup(self, index):      def RemoveGroup(self, index):
# Line 277  class Classification: Line 155  class Classification:
155    
156      def ReplaceGroup(self, index, group):      def ReplaceGroup(self, index, group):
157          assert isinstance(group, ClassGroup)          assert isinstance(group, ClassGroup)
   
158          self.__groups[index + 1] = group          self.__groups[index + 1] = group
   
159          self.__SendNotification()          self.__SendNotification()
160    
161      def GetGroup(self, index):      def GetGroup(self, index):
# Line 289  class Classification: Line 165  class Classification:
165          """Return the number of non-default groups in the classification."""          """Return the number of non-default groups in the classification."""
166          return len(self.__groups) - 1          return len(self.__groups) - 1
167    
   
168      def FindGroup(self, value):      def FindGroup(self, value):
169          """Return the associated group, or the default group.          """Return the associated group, or the default group.
170    
# Line 301  class Classification: Line 176  class Classification:
176                   return the default properties                   return the default properties
177          """          """
178    
179          if self.GetField() is not None and value is not None:          if value is not None:
   
180              for i in range(1, len(self.__groups)):              for i in range(1, len(self.__groups)):
181                  group = self.__groups[i]                  group = self.__groups[i]
182                  if group.Matches(value):                  if group.Matches(value):
# Line 328  class Classification: Line 202  class Classification:
202          items = []          items = []
203    
204          def build_color_item(text, color):          def build_color_item(text, color):
205              if color is Color.Transparent:              if color is Transparent:
206                  return ("%s: %s" % (text, _("None")), None)                  return ("%s: %s" % (text, _("None")), None)
207    
208              return ("%s: (%.3f, %.3f, %.3f)" %              return ("%s: (%.3f, %.3f, %.3f)" %
# Line 355  class Classification: Line 229  class Classification:
229          for p in self:          for p in self:
230              items.append(build_item(p, p.GetDisplayText()))              items.append(build_item(p, p.GetDisplayText()))
231    
 #           if isinstance(p, ClassGroupDefault):  
 #               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())))  
   
232          return (_("Classification"), items)          return (_("Classification"), items)
233    
234  class ClassIterator:  class ClassIterator:
# Line 384  class ClassIterator: Line 250  class ClassIterator:
250          maps -- a list of map groups          maps -- a list of map groups
251          """          """
252    
253          self.data = data #[default, points, ranges, maps]          self.data = data
254          self.data_index = 0          self.data_index = 0
         #self.data_iter = iter(self.data)  
         #self.iter = None  
255    
256      def __iter__(self):      def __iter__(self):
257          return self          return self
# Line 402  class ClassIterator: Line 266  class ClassIterator:
266              self.data_index += 1              self.data_index += 1
267              return d              return d
268                    
 #       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()  
         
269  class ClassGroupProperties:  class ClassGroupProperties:
270      """Represents the properties of a single Classification Group.      """Represents the properties of a single Classification Group.
271        
# Line 425  class ClassGroupProperties: Line 276  class ClassGroupProperties:
276    
277          props -- a ClassGroupProperties object. The class is copied if          props -- a ClassGroupProperties object. The class is copied if
278                   prop is not None. Otherwise, a default set of properties                   prop is not None. Otherwise, a default set of properties
279                   is created such that: line color = Color.Black, line width = 1,                   is created such that: line color = Black, line width = 1,
280                   and fill color = Color.Transparent                   and fill color = Transparent
281          """          """
282    
         #self.stroke = None  
         #self.strokeWidth = 0  
         #self.fill = None  
   
283          if props is not None:          if props is not None:
284              self.SetProperties(props)              self.SetProperties(props)
285          else:          else:
286              self.SetLineColor(Color.Black)              self.SetLineColor(Black)
287              self.SetLineWidth(1)              self.SetLineWidth(1)
288              self.SetFill(Color.Transparent)              self.SetFill(Transparent)
289    
290      def SetProperties(self, props):      def SetProperties(self, props):
291          """Set this class's properties to those in class props."""          """Set this class's properties to those in class props."""
# Line 458  class ClassGroupProperties: Line 305  class ClassGroupProperties:
305          color -- the color of the line. This must be a Color object.          color -- the color of the line. This must be a Color object.
306          """          """
307    
         assert isinstance(color, Color)  
308          self.__stroke = color          self.__stroke = color
309    
310      def GetLineWidth(self):      def GetLineWidth(self):
# Line 486  class ClassGroupProperties: Line 332  class ClassGroupProperties:
332          fill -- the color of the fill. This must be a Color object.          fill -- the color of the fill. This must be a Color object.
333          """          """
334    
         assert isinstance(fill, Color)  
335          self.__fill = fill          self.__fill = fill
336    
337      def __eq__(self, other):      def __eq__(self, other):
# Line 690  class ClassGroupRange(ClassGroup): Line 535  class ClassGroupRange(ClassGroup):
535      """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
536         set of properties."""         set of properties."""
537    
538      def __init__(self, min = 0, max = 1, props = None, label = "", group=None):      def __init__(self, _range = (0,1), props = None, label = "", group=None):
539          """Constructor.          """Constructor.
540    
541          The minumum value must be strictly less than the maximum.          The minumum value must be strictly less than the maximum.
542    
543          min -- the minimum range value          _range -- either a tuple (min, max) where min < max or
544                      a Range object
         max -- the maximum range value  
545    
546          prop -- a ClassGroupProperites object. If prop is None a default          prop -- a ClassGroupProperites object. If prop is None a default
547                   set of properties is created.                   set of properties is created.
# Line 706  class ClassGroupRange(ClassGroup): Line 550  class ClassGroupRange(ClassGroup):
550          """          """
551    
552          ClassGroup.__init__(self, label, props, group)          ClassGroup.__init__(self, label, props, group)
553            self.SetRange(_range)
         #self.__min = self.__max = 0  
         #self.__range = Range("[" + repr(float(min)) + ";" +  
                                    #repr(float(max)) + "[")  
         self.SetRange(min, max)  
554    
555      def __copy__(self):      def __copy__(self):
556          return ClassGroupRange(min = self.__range,          return ClassGroupRange(self.__range,
                                max = None,  
557                                 props = self.GetProperties(),                                 props = self.GetProperties(),
558                                 label = self.GetLabel())                                 label = self.GetLabel())
559    
560      def __deepcopy__(self, memo):      def __deepcopy__(self, memo):
561          return ClassGroupRange(min = copy.copy(self.__range),          return ClassGroupRange(copy.copy(self.__range),
                                max = copy.copy(self.GetMax()),  
562                                 group = self)                                 group = self)
563    
564      def GetMin(self):      def GetMin(self):
# Line 734  class ClassGroupRange(ClassGroup): Line 572  class ClassGroupRange(ClassGroup):
572                 maximum value. Use SetRange() to change both min and max values.                 maximum value. Use SetRange() to change both min and max values.
573          """          """
574            
575          self.SetRange(min, self.__range.GetRange()[2])          self.SetRange((min, self.__range.GetRange()[2]))
576    
577      def GetMax(self):      def GetMax(self):
578          """Return the range's maximum value."""          """Return the range's maximum value."""
# Line 746  class ClassGroupRange(ClassGroup): Line 584  class ClassGroupRange(ClassGroup):
584          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
585                 minimum value. Use SetRange() to change both min and max values.                 minimum value. Use SetRange() to change both min and max values.
586          """          """
587          self.SetRange(self.__range.GetRange()[1], max)          self.SetRange((self.__range.GetRange()[1], max))
588    
589      def SetRange(self, min, max = None):      def SetRange(self, _range):
590          """Set a new range.          """Set a new range.
591    
592          Note that min must be strictly less than max.          _range -- Either a tuple (min, max) where min < max or
593                      a Range object.
594    
595          min -- the new minimum value          Raises ValueError on error.
         min -- the new maximum value  
596          """          """
597    
598          if isinstance(min, Range):          if isinstance(_range, Range):
599              self.__range = min              self.__range = _range
600            elif isinstance(_range, types.TupleType) and len(_range) == 2:
601                self.__range = Range(("[", _range[0], _range[1], "["))
602          else:          else:
603              if max is None:              raise ValueError()
                 raise ValueError()  
   
             self.__range = Range(("[", min, max, "["))  
604    
605      def GetRange(self):      def GetRange(self):
606          """Return the range as a string"""          """Return the range as a string"""
         #return (self.__min, self.__max)  
607          return self.__range.string(self.__range.GetRange())          return self.__range.string(self.__range.GetRange())
608    
609      def Matches(self, value):      def Matches(self, value):
# Line 777  class ClassGroupRange(ClassGroup): Line 613  class ClassGroupRange(ClassGroup):
613          """          """
614    
615          return operator.contains(self.__range, value)          return operator.contains(self.__range, value)
         #return self.__min <= value < self.__max  
616    
617      def GetDisplayText(self):      def GetDisplayText(self):
618          label = self.GetLabel()          label = self.GetLabel()
619    
620          if label != "": return label          if label != "": return label
621    
         #return _("%s - %s") % (self.GetMin(), self.GetMax())  
         #return repr(self.__range)  
622          return self.__range.string(self.__range.GetRange())          return self.__range.string(self.__range.GetRange())
623    
624      def __eq__(self, other):      def __eq__(self, other):
625          return ClassGroup.__eq__(self, other) \          return ClassGroup.__eq__(self, other) \
626              and isinstance(other, ClassGroupRange) \              and isinstance(other, ClassGroupRange) \
627              and self.__range == other.__range              and self.__range == other.__range
             #and self.__min == other.__min \  
             #and self.__max == other.__max  
628    
629      def __repr__(self):      def __repr__(self):
630          return "(" + str(self.__range) + ClassGroup.__repr__(self) + ")"          return "(" + str(self.__range) + ClassGroup.__repr__(self) + ")"
         #return "(" + repr(self.__min) + ", " + repr(self.__max) + ", " + \  
                #ClassGroup.__repr__(self) + ")"  
631    
632  class ClassGroupMap(ClassGroup):  class ClassGroupMap(ClassGroup):
633      """Currently, this class is not used."""      """Currently, this class is not used."""

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26