/[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 491 by jonathan, Mon Mar 10 10:44:42 2003 UTC revision 613 by jonathan, Mon Apr 7 08:55:55 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        
# Line 25  from __future__ import nested_scopes Line 25  from __future__ import nested_scopes
25    
26  import copy  import copy
27    
28    from Thuban import _
29    
30  from types import *  from types import *
31    
32  from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \  from messages import \
33       LAYER_VISIBILITY_CHANGED      LAYER_PROJECTION_CHANGED, \
34        LAYER_LEGEND_CHANGED, \
35        LAYER_VISIBILITY_CHANGED
36    
 from Thuban import _  
37  from Thuban.Model.color import Color  from Thuban.Model.color import Color
38    
39  import Thuban.Model.layer  import Thuban.Model.layer
40    
 # constants  
 RANGE_MIN  = 0  
 RANGE_MAX  = 1  
 RANGE_DATA = 2  
   
41  class Classification:  class Classification:
42      """Encapsulates the classification of layer. The Classification      """Encapsulates the classification of layer.
43      divides some kind of data into Groups which are associated with      
44      properties. Later the properties can be retrieved by matching      The Classification divides some kind of data into Groups which
45      data values to the appropriate group."""      are associated with properties. Later the properties can be
46        retrieved by matching data values to the appropriate group.
47        """
48    
49      def __init__(self, layer = None, field = None):      def __init__(self, layer = None, field = None):
50          """Initialize a classification.          """Initialize a classification.
51    
52             layer -- the Layer object who owns this classification          layer -- the Layer object who owns this classification
53    
54             field -- the name of the data table field that          field -- the name of the data table field that
55                      is to be used to classify layer properties                   is to be used to classify layer properties
56          """          """
57    
58          self.layer = None          self.layer = None
59          self.field = None          self.field = None
60          self.fieldType = None          self.fieldType = None
61          self.groups = []          self.__groups = []
62    
63            self.__setLayerLock = False
64    
65          self.SetDefaultGroup(ClassGroupDefault())          self.SetDefaultGroup(ClassGroupDefault())
66    
# Line 66  class Classification: Line 68  class Classification:
68          self.SetField(field)          self.SetField(field)
69    
70      def __iter__(self):      def __iter__(self):
71          return ClassIterator(self.groups)          return ClassIterator(self.__groups)
72    
73        def __deepcopy__(self, memo):
74            clazz = Classification()
75    
76            clazz.__groups[0] = copy.deepcopy(self.__groups[0])
77    
78            for i in range(1, len(self.__groups)):
79                clazz.__groups.append(copy.deepcopy(self.__groups[i]))
80    
81            print "Classification.__deepcopy__"
82            return clazz
83    
84      def __SendNotification(self):      def __SendNotification(self):
85          """Notify the layer that this class has changed."""          """Notify the layer that this class has changed."""
# Line 76  class Classification: Line 89  class Classification:
89      def SetField(self, field):      def SetField(self, field):
90          """Set the name of the data table field to use.          """Set the name of the data table field to use.
91                    
92             If there is no layer then the field type is set to None,          If there is no layer then the field type is set to None,
93             otherwise the layer is queried to find the type of the          otherwise the layer is queried to find the type of the
94             field data          field data
95    
96             field -- if None then all values map to the default data          field -- if None then all values map to the default data
97          """          """
98    
99          if field == "":          if field == "":
# Line 133  class Classification: Line 146  class Classification:
146      def SetLayer(self, layer):      def SetLayer(self, layer):
147          """Set the owning Layer of this classification.          """Set the owning Layer of this classification.
148    
149             A ValueError exception will be thrown either the field or          A ValueError exception will be thrown either the field or
150             field type mismatch the information in the layer's table.          field type mismatch the information in the layer's table.
151          """          """
152    
153            # prevent infinite recursion when calling SetClassification()
154            if self.__setLayerLock: return
155    
156            self.__setLayerLock = True
157    
158          if layer is None:          if layer is None:
159              if self.layer is not None:              if self.layer is not None:
160                  l = self.layer                  l = self.layer
161                  self.layer = None                  self.layer = None
162                  l.SetClassification(None)                  l.SetClassification(None)
163          else:          else:
164              assert(isinstance(layer, Thuban.Model.layer.Layer))              assert isinstance(layer, Thuban.Model.layer.Layer)
165    
             # prevent infinite recursion when calling SetClassification()  
             if layer == self.layer:  
                 return  
               
166              old_layer = self.layer              old_layer = self.layer
167    
168              self.layer = layer              self.layer = layer
# Line 157  class Classification: Line 171  class Classification:
171                  self.SetField(self.GetField()) # this sync's the fieldType                  self.SetField(self.GetField()) # this sync's the fieldType
172              except ValueError:              except ValueError:
173                  self.layer = old_layer                  self.layer = old_layer
174                    self.__setLayerLock = False
175                  raise ValueError                  raise ValueError
176              else:              else:
177                  self.layer.SetClassification(self)                  self.layer.SetClassification(self)
178    
179            self.__setLayerLock = False
180    
181      def GetLayer(self):      def GetLayer(self):
182          """Return the parent layer."""          """Return the parent layer."""
183          return self.layer          return self.layer
184    
     def SetDefaultGroup(self, group):  
         """Set the group to be used when a value can't be classified.  
   
            group -- group that the value maps to.  
         """  
   
         assert(isinstance(group, ClassGroupDefault))  
         self.AddGroup(group)  
   
     def GetDefaultGroup(self):  
         """Return the default group."""  
         return self.groups[0]  
185    
186      #      #
187      # these SetDefault* methods are really only provided for      # these SetDefault* methods are really only provided for
# Line 189  class Classification: Line 194  class Classification:
194    
195          fill -- a Color object.          fill -- a Color object.
196          """          """
197          assert(isinstance(fill, Color))          assert isinstance(fill, Color)
198          self.GetDefaultGroup().GetProperties().SetFill(fill)          self.GetDefaultGroup().GetProperties().SetFill(fill)
199          self.__SendNotification()          self.__SendNotification()
200                    
# Line 202  class Classification: Line 207  class Classification:
207    
208          color -- a Color object.          color -- a Color object.
209          """          """
210          assert(isinstance(color, Color))          assert isinstance(color, Color)
211          self.GetDefaultGroup().GetProperties().SetLineColor(color)          self.GetDefaultGroup().GetProperties().SetLineColor(color)
212          self.__SendNotification()          self.__SendNotification()
213                    
# Line 215  class Classification: Line 220  class Classification:
220    
221          lineWidth -- an integer > 0.          lineWidth -- an integer > 0.
222          """          """
223          assert(isinstance(lineWidth, IntType))          assert isinstance(lineWidth, IntType)
224          self.GetDefaultGroup().GetProperties().SetLineWidth(lineWidth)          self.GetDefaultGroup().GetProperties().SetLineWidth(lineWidth)
225          self.__SendNotification()          self.__SendNotification()
226                    
# Line 223  class Classification: Line 228  class Classification:
228          """Return the default line width."""          """Return the default line width."""
229          return self.GetDefaultGroup().GetProperties().GetLineWidth()          return self.GetDefaultGroup().GetProperties().GetLineWidth()
230                    
231      def AddGroup(self, item):  
232          """Add a new ClassGroup item to the classification.      #
233        # The methods that manipulate self.__groups have to be kept in
234        # sync. We store the default group in index 0 to make it
235        # convienent to iterate over the classification's groups, but
236        # from the user's perspective the first (non-default) group is
237        # at index 0 and the DefaultGroup is a special entity.
238        #
239    
240        def SetDefaultGroup(self, group):
241            """Set the group to be used when a value can't be classified.
242    
243            group -- group that the value maps to.
244            """
245    
246            assert isinstance(group, ClassGroupDefault)
247            if len(self.__groups) > 0:
248                self.__groups[0] = group
249            else:
250                self.__groups.append(group)
251    
252        def GetDefaultGroup(self):
253            """Return the default group."""
254            return self.__groups[0]
255    
256        def AppendGroup(self, item):
257            """Append a new ClassGroup item to the classification.
258    
259          item -- this must be a valid ClassGroup object          item -- this must be a valid ClassGroup object
260          """          """
261    
262          assert(isinstance(item, ClassGroup))          self.InsertGroup(self.GetNumGroups(), item)
263    
264          if len(self.groups) > 0 and isinstance(item, ClassGroupDefault):      def InsertGroup(self, index, group):
265              self.groups[0] = item          
266          else:          assert isinstance(group, ClassGroup)
267              self.groups.append(item)  
268            self.__groups.insert(index + 1, group)
269    
270          self.__SendNotification()          self.__SendNotification()
271    
272      def GetGroup(self, value):      def RemoveGroup(self, index):
273            return self.__groups.pop(index + 1)
274    
275        def ReplaceGroup(self, index, group):
276            assert isinstance(group, ClassGroup)
277    
278            self.__groups[index + 1] = group
279    
280            self.__SendNotification()
281    
282        def GetGroup(self, index):
283            return self.__groups[index + 1]
284    
285        def GetNumGroups(self):
286            """Return the number of non-default groups in the classification."""
287            return len(self.__groups) - 1
288    
289    
290        def FindGroup(self, value):
291          """Return the associated group, or the default group.          """Return the associated group, or the default group.
292    
293             Groups are checked in the order the were added to the          Groups are checked in the order the were added to the
294             Classification.          Classification.
295    
296             value -- the value to classify. If there is no mapping,          value -- the value to classify. If there is no mapping,
297                      the field is None or value is None,                   the field is None or value is None,
298                      return the default properties                   return the default properties
299          """          """
300    
301          if self.GetField() is not None and value is not None:          if self.GetField() is not None and value is not None:
302    
303              for i in range(1, len(self.groups)):              for i in range(1, len(self.__groups)):
304                  group = self.groups[i]                  group = self.__groups[i]
305                  if group.Matches(value):                  if group.Matches(value):
306                      return group                      return group
307    
308          return self.GetDefaultGroup()          return self.GetDefaultGroup()
309    
310      def GetProperties(self, value):      def GetProperties(self, value):
311          """Return the properties associated with the given value."""          """Return the properties associated with the given value.
312          
313            Use this function rather than Classification.FindGroup().GetProperties()
314            since the returned group may be a ClassGroupMap which doesn't support
315            a call to GetProperties().
316            """
317    
318          group = self.GetGroup(value)          group = self.FindGroup(value)
319          if isinstance(group, ClassGroupMap):          if isinstance(group, ClassGroupMap):
320              return group.GetPropertiesFromValue(value)              return group.GetPropertiesFromValue(value)
321          else:          else:
# Line 271  class Classification: Line 325  class Classification:
325          items = []          items = []
326    
327          def build_color_item(text, color):          def build_color_item(text, color):
328              if color is Color.None:              if color is Color.Transparent:
329                  return ("%s: %s" % (text, _("None")), None)                  return ("%s: %s" % (text, _("None")), None)
330    
331              return ("%s: (%.3f, %.3f, %.3f)" %              return ("%s: (%.3f, %.3f, %.3f)" %
# Line 296  class Classification: Line 350  class Classification:
350              return (label, i)              return (label, i)
351    
352          for p in self:          for p in self:
353              if isinstance(p, ClassGroupDefault):              items.append(build_item(p, p.GetDisplayText()))
354                  items.append(build_item(self.GetDefaultGroup(), _("'DEFAULT'")))  
355              elif isinstance(p, ClassGroupSingleton):  #           if isinstance(p, ClassGroupDefault):
356                  items.append(build_item(p, str(p.GetValue())))  #               items.append(build_item(self.GetDefaultGroup(), _("'DEFAULT'")))
357              elif isinstance(p, ClassGroupRange):  #           elif isinstance(p, ClassGroupSingleton):
358                  items.append(build_item(p, "%s - %s" %  #               items.append(build_item(p, str(p.GetValue())))
359                                             (p.GetMin(), p.GetMax())))  #           elif isinstance(p, ClassGroupRange):
360    #               items.append(build_item(p, "%s - %s" %
361    #                                          (p.GetMin(), p.GetMax())))
362    
363          return (_("Classification"), items)          return (_("Classification"), items)
364    
# Line 367  class ClassGroupProperties: Line 423  class ClassGroupProperties:
423          props -- a ClassGroupProperties object. The class is copied if          props -- a ClassGroupProperties object. The class is copied if
424                   prop is not None. Otherwise, a default set of properties                   prop is not None. Otherwise, a default set of properties
425                   is created such that: line color = Color.Black, line width = 1,                   is created such that: line color = Color.Black, line width = 1,
426                   and fill color = Color.None                   and fill color = Color.Transparent
427          """          """
428    
429          self.stroke = None          self.stroke = None
# Line 379  class ClassGroupProperties: Line 435  class ClassGroupProperties:
435          else:          else:
436              self.SetLineColor(Color.Black)              self.SetLineColor(Color.Black)
437              self.SetLineWidth(1)              self.SetLineWidth(1)
438              self.SetFill(Color.None)              self.SetFill(Color.Transparent)
439    
440      def SetProperties(self, props):      def SetProperties(self, props):
441          """Set this class's properties to those in class props."""          """Set this class's properties to those in class props."""
442    
443          assert(isinstance(props, ClassGroupProperties))          assert isinstance(props, ClassGroupProperties)
444          self.SetLineColor(props.GetLineColor())          self.SetLineColor(props.GetLineColor())
445          self.SetLineWidth(props.GetLineWidth())          self.SetLineWidth(props.GetLineWidth())
446          self.SetFill(props.GetFill())          self.SetFill(props.GetFill())
# Line 399  class ClassGroupProperties: Line 455  class ClassGroupProperties:
455          color -- the color of the line. This must be a Color object.          color -- the color of the line. This must be a Color object.
456          """          """
457    
458          assert(isinstance(color, Color))          assert isinstance(color, Color)
459          self.stroke = color          self.stroke = color
460    
461      def GetLineWidth(self):      def GetLineWidth(self):
# Line 411  class ClassGroupProperties: Line 467  class ClassGroupProperties:
467    
468          lineWidth -- the new line width. This must be > 0.          lineWidth -- the new line width. This must be > 0.
469          """          """
470          assert(isinstance(lineWidth, IntType))          assert isinstance(lineWidth, IntType)
471          if (lineWidth < 1):          if (lineWidth < 1):
472              raise ValueError(_("lineWidth < 1"))              raise ValueError(_("lineWidth < 1"))
473    
# Line 427  class ClassGroupProperties: Line 483  class ClassGroupProperties:
483          fill -- the color of the fill. This must be a Color object.          fill -- the color of the fill. This must be a Color object.
484          """          """
485    
486          assert(isinstance(fill, Color))          assert isinstance(fill, Color)
487          self.fill = fill          self.fill = fill
488    
489      def __eq__(self, other):      def __eq__(self, other):
# Line 444  class ClassGroupProperties: Line 500  class ClassGroupProperties:
500      def __copy__(self):      def __copy__(self):
501          return ClassGroupProperties(self)          return ClassGroupProperties(self)
502    
503        def __deepcopy__(self):
504            return ClassGroupProperties(self)
505    
506  class ClassGroup:  class ClassGroup:
507      """A base class for all Groups within a Classification"""      """A base class for all Groups within a Classification"""
508    
# Line 467  class ClassGroup: Line 526  class ClassGroup:
526          label -- a string representing the Group's label. This must          label -- a string representing the Group's label. This must
527                   not be None.                   not be None.
528          """          """
529          assert(isinstance(label, StringType))          assert isinstance(label, StringType)
530          self.label = label          self.label = label
531    
532        def GetDisplayText(self):
533            assert False, "GetDisplay must be overridden by subclass!"
534            return ""
535    
536      def Matches(self, value):      def Matches(self, value):
537          """Determines if this Group is associated with the given value.          """Determines if this Group is associated with the given value.
538    
539          Returns False. This needs to be overridden by all subclasses.          Returns False. This needs to be overridden by all subclasses.
540          """          """
541            assert False, "GetMatches must be overridden by subclass!"
542          return False          return False
543    
544      def GetProperties(self):      def GetProperties(self):
# Line 482  class ClassGroup: Line 546  class ClassGroup:
546    
547          Returns None. This needs to be overridden by all subclasses.          Returns None. This needs to be overridden by all subclasses.
548          """          """
549            assert False, "GetProperties must be overridden by subclass!"
550          return None          return None
551    
552            
# Line 544  class ClassGroupSingleton(ClassGroup): Line 609  class ClassGroupSingleton(ClassGroup):
609          """          """
610    
611          if prop is None: prop = ClassGroupProperties()          if prop is None: prop = ClassGroupProperties()
612          assert(isinstance(prop, ClassGroupProperties))          assert isinstance(prop, ClassGroupProperties)
613          self.prop = prop          self.prop = prop
614    
615        def GetDisplayText(self):
616            label = self.GetLabel()
617    
618            if label != "": return label
619    
620            return str(self.GetValue())
621    
622      def __eq__(self, other):      def __eq__(self, other):
623          return isinstance(other, ClassGroupSingleton) \          return isinstance(other, ClassGroupSingleton) \
624              and self.GetProperties() == other.GetProperties() \              and self.GetProperties() == other.GetProperties() \
# Line 594  class ClassGroupDefault(ClassGroup): Line 666  class ClassGroupDefault(ClassGroup):
666          """          """
667    
668          if prop is None: prop = ClassGroupProperties()          if prop is None: prop = ClassGroupProperties()
669          assert(isinstance(prop, ClassGroupProperties))          assert isinstance(prop, ClassGroupProperties)
670          self.prop = prop          self.prop = prop
671    
672        def GetDisplayText(self):
673            label = self.GetLabel()
674    
675            if label != "": return label
676    
677            return _("DEFAULT")
678    
679      def __eq__(self, other):      def __eq__(self, other):
680          return isinstance(other, ClassGroupDefault) \          return isinstance(other, ClassGroupDefault) \
681              and self.GetProperties() == other.GetProperties()              and self.GetProperties() == other.GetProperties()
# Line 706  class ClassGroupRange(ClassGroup): Line 785  class ClassGroupRange(ClassGroup):
785                  a default set of properties is created.                  a default set of properties is created.
786          """          """
787          if prop is None: prop = ClassGroupProperties()          if prop is None: prop = ClassGroupProperties()
788          assert(isinstance(prop, ClassGroupProperties))          assert isinstance(prop, ClassGroupProperties)
789          self.prop = prop          self.prop = prop
790    
791        def GetDisplayText(self):
792            label = self.GetLabel()
793    
794            if label != "": return label
795    
796            return _("%s - %s") % (self.GetMin(), self.GetMax())
797    
798      def __eq__(self, other):      def __eq__(self, other):
799          return isinstance(other, ClassGroupRange) \          return isinstance(other, ClassGroupRange) \
800              and self.GetProperties() == other.GetProperties() \              and self.GetProperties() == other.GetProperties() \
# Line 740  class ClassGroupMap(ClassGroup): Line 826  class ClassGroupMap(ClassGroup):
826      def GetPropertiesFromValue(self, value):      def GetPropertiesFromValue(self, value):
827          pass          pass
828    
829        def GetDisplayText(self):
830            return "Map: " + self.map_type
831    
832      #      #
833      # built-in mappings      # built-in mappings
834      #      #

Legend:
Removed from v.491  
changed lines
  Added in v.613

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26