/[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 1176 by jonathan, Thu Jun 12 15:46:22 2003 UTC revision 1909 by bh, Fri Oct 31 18:16:34 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 243  class Classification: Line 126  class Classification:
126    
127          group -- group that the value maps to.          group -- group that the value maps to.
128          """          """
   
129          assert isinstance(group, ClassGroupDefault)          assert isinstance(group, ClassGroupDefault)
130          if len(self.__groups) > 0:          if len(self.__groups) > 0:
131              self.__groups[0] = group              self.__groups[0] = group
132          else:          else:
133              self.__groups.append(group)              self.__groups.append(group)
134            self.__SendNotification()
135    
136      def GetDefaultGroup(self):      def GetDefaultGroup(self):
137          """Return the default group."""          """Return the default group."""
# Line 263  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):
154          return self.__groups.pop(index + 1)          """Remove the classification group with the given index"""
155            self.__groups.pop(index + 1)
156            self.__SendNotification()
157    
158      def ReplaceGroup(self, index, group):      def ReplaceGroup(self, index, group):
159          assert isinstance(group, ClassGroup)          assert isinstance(group, ClassGroup)
   
160          self.__groups[index + 1] = group          self.__groups[index + 1] = group
   
161          self.__SendNotification()          self.__SendNotification()
162    
163      def GetGroup(self, index):      def GetGroup(self, index):
# Line 287  class Classification: Line 167  class Classification:
167          """Return the number of non-default groups in the classification."""          """Return the number of non-default groups in the classification."""
168          return len(self.__groups) - 1          return len(self.__groups) - 1
169    
   
170      def FindGroup(self, value):      def FindGroup(self, value):
171          """Return the associated group, or the default group.          """Return the associated group, or the default group.
172    
# Line 299  class Classification: Line 178  class Classification:
178                   return the default properties                   return the default properties
179          """          """
180    
181          if self.GetField() is not None and value is not None:          if value is not None:
   
182              for i in range(1, len(self.__groups)):              for i in range(1, len(self.__groups)):
183                  group = self.__groups[i]                  group = self.__groups[i]
184                  if group.Matches(value):                  if group.Matches(value):
# Line 326  class Classification: Line 204  class Classification:
204          items = []          items = []
205    
206          def build_color_item(text, color):          def build_color_item(text, color):
207              if color is Color.Transparent:              if color is Transparent:
208                  return ("%s: %s" % (text, _("None")), None)                  return ("%s: %s" % (text, _("None")), None)
209    
210              return ("%s: (%.3f, %.3f, %.3f)" %              return ("%s: (%.3f, %.3f, %.3f)" %
# Line 353  class Classification: Line 231  class Classification:
231          for p in self:          for p in self:
232              items.append(build_item(p, p.GetDisplayText()))              items.append(build_item(p, p.GetDisplayText()))
233    
 #           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())))  
   
234          return (_("Classification"), items)          return (_("Classification"), items)
235    
236  class ClassIterator:  class ClassIterator:
# Line 382  class ClassIterator: Line 252  class ClassIterator:
252          maps -- a list of map groups          maps -- a list of map groups
253          """          """
254    
255          self.data = data #[default, points, ranges, maps]          self.data = data
256          self.data_index = 0          self.data_index = 0
         #self.data_iter = iter(self.data)  
         #self.iter = None  
257    
258      def __iter__(self):      def __iter__(self):
259          return self          return self
# Line 400  class ClassIterator: Line 268  class ClassIterator:
268              self.data_index += 1              self.data_index += 1
269              return d              return d
270                    
 #       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()  
         
271  class ClassGroupProperties:  class ClassGroupProperties:
272      """Represents the properties of a single Classification Group.      """Represents the properties of a single Classification Group.
273        
# Line 423  class ClassGroupProperties: Line 278  class ClassGroupProperties:
278    
279          props -- a ClassGroupProperties object. The class is copied if          props -- a ClassGroupProperties object. The class is copied if
280                   prop is not None. Otherwise, a default set of properties                   prop is not None. Otherwise, a default set of properties
281                   is created such that: line color = Color.Black, line width = 1,                   is created such that: line color = Black, line width = 1,
282                   and fill color = Color.Transparent                   and fill color = Transparent
283          """          """
284    
         #self.stroke = None  
         #self.strokeWidth = 0  
         #self.fill = None  
   
285          if props is not None:          if props is not None:
286              self.SetProperties(props)              self.SetProperties(props)
287          else:          else:
288              self.SetLineColor(Color.Black)              self.SetLineColor(Black)
289              self.SetLineWidth(1)              self.SetLineWidth(1)
290              self.SetFill(Color.Transparent)              self.SetFill(Transparent)
291    
292      def SetProperties(self, props):      def SetProperties(self, props):
293          """Set this class's properties to those in class props."""          """Set this class's properties to those in class props."""
# Line 686  class ClassGroupRange(ClassGroup): Line 537  class ClassGroupRange(ClassGroup):
537      """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
538         set of properties."""         set of properties."""
539    
540      def __init__(self, min = 0, max = 1, props = None, label = "", group=None):      def __init__(self, _range = (0,1), props = None, label = "", group=None):
541          """Constructor.          """Constructor.
542    
543          The minumum value must be strictly less than the maximum.          The minumum value must be strictly less than the maximum.
544    
545          min -- the minimum range value          _range -- either a tuple (min, max) where min < max or
546                      a Range object
         max -- the maximum range value  
547    
548          prop -- a ClassGroupProperites object. If prop is None a default          prop -- a ClassGroupProperites object. If prop is None a default
549                   set of properties is created.                   set of properties is created.
# Line 702  class ClassGroupRange(ClassGroup): Line 552  class ClassGroupRange(ClassGroup):
552          """          """
553    
554          ClassGroup.__init__(self, label, props, group)          ClassGroup.__init__(self, label, props, group)
555            self.SetRange(_range)
         #self.__min = self.__max = 0  
         #self.__range = Range("[" + repr(float(min)) + ";" +  
                                    #repr(float(max)) + "[")  
         self.SetRange(min, max)  
556    
557      def __copy__(self):      def __copy__(self):
558          return ClassGroupRange(min = self.__range,          return ClassGroupRange(self.__range,
                                max = None,  
559                                 props = self.GetProperties(),                                 props = self.GetProperties(),
560                                 label = self.GetLabel())                                 label = self.GetLabel())
561    
562      def __deepcopy__(self, memo):      def __deepcopy__(self, memo):
563          return ClassGroupRange(min = copy.copy(self.__range),          return ClassGroupRange(copy.copy(self.__range),
                                max = copy.copy(self.GetMax()),  
564                                 group = self)                                 group = self)
565    
566      def GetMin(self):      def GetMin(self):
# Line 730  class ClassGroupRange(ClassGroup): Line 574  class ClassGroupRange(ClassGroup):
574                 maximum value. Use SetRange() to change both min and max values.                 maximum value. Use SetRange() to change both min and max values.
575          """          """
576            
577          self.SetRange(min, self.__range.GetRange()[2])          self.SetRange((min, self.__range.GetRange()[2]))
578    
579      def GetMax(self):      def GetMax(self):
580          """Return the range's maximum value."""          """Return the range's maximum value."""
# Line 742  class ClassGroupRange(ClassGroup): Line 586  class ClassGroupRange(ClassGroup):
586          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
587                 minimum value. Use SetRange() to change both min and max values.                 minimum value. Use SetRange() to change both min and max values.
588          """          """
589          self.SetRange(self.__range.GetRange()[1], max)          self.SetRange((self.__range.GetRange()[1], max))
590    
591      def SetRange(self, min, max = None):      def SetRange(self, _range):
592          """Set a new range.          """Set a new range.
593    
594          Note that min must be strictly less than max.          _range -- Either a tuple (min, max) where min < max or
595                      a Range object.
596    
597          min -- the new minimum value          Raises ValueError on error.
         min -- the new maximum value  
598          """          """
599    
600          if isinstance(min, Range):          if isinstance(_range, Range):
601              self.__range = min              self.__range = _range
602            elif isinstance(_range, types.TupleType) and len(_range) == 2:
603                self.__range = Range(("[", _range[0], _range[1], "["))
604          else:          else:
605              if max is None:              raise ValueError()
                 raise ValueError()  
   
             self.__range = Range(("[", min, max, "["))  
606    
607      def GetRange(self):      def GetRange(self):
608          """Return the range as a string"""          """Return the range as a string"""
         #return (self.__min, self.__max)  
609          return self.__range.string(self.__range.GetRange())          return self.__range.string(self.__range.GetRange())
610    
611      def Matches(self, value):      def Matches(self, value):
# Line 773  class ClassGroupRange(ClassGroup): Line 615  class ClassGroupRange(ClassGroup):
615          """          """
616    
617          return operator.contains(self.__range, value)          return operator.contains(self.__range, value)
         #return self.__min <= value < self.__max  
618    
619      def GetDisplayText(self):      def GetDisplayText(self):
620          label = self.GetLabel()          label = self.GetLabel()
621    
622          if label != "": return label          if label != "": return label
623    
         #return _("%s - %s") % (self.GetMin(), self.GetMax())  
         #return repr(self.__range)  
624          return self.__range.string(self.__range.GetRange())          return self.__range.string(self.__range.GetRange())
625    
626      def __eq__(self, other):      def __eq__(self, other):
627          return ClassGroup.__eq__(self, other) \          return ClassGroup.__eq__(self, other) \
628              and isinstance(other, ClassGroupRange) \              and isinstance(other, ClassGroupRange) \
629              and self.__range == other.__range              and self.__range == other.__range
             #and self.__min == other.__min \  
             #and self.__max == other.__max  
630    
631      def __repr__(self):      def __repr__(self):
632          return "(" + str(self.__range) + ClassGroup.__repr__(self) + ")"          return "(" + str(self.__range) + ClassGroup.__repr__(self) + ")"
         #return "(" + repr(self.__min) + ", " + repr(self.__max) + ", " + \  
                #ClassGroup.__repr__(self) + ")"  
633    
634  class ClassGroupMap(ClassGroup):  class ClassGroupMap(ClassGroup):
635      """Currently, this class is not used."""      """Currently, this class is not used."""

Legend:
Removed from v.1176  
changed lines
  Added in v.1909

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26