/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/map.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/Model/map.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 6 by bh, Tue Aug 28 15:41:52 2001 UTC revision 2564 by jan, Wed Feb 16 23:14:35 2005 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001 by Intevation GmbH  # Copyright (c) 2001-2003, 2005 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4    # Jonathan Coles <[email protected]>
5  #  #
6  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
7  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
8    
9  __version__ = "$Revision$"  __version__ = "$Revision$"
10    
11  from messages import LAYERS_CHANGED, MAP_PROJECTION_CHANGED, \  from messages import MAP_LAYERS_CHANGED, MAP_PROJECTION_CHANGED, \
12       CHANGED, LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \       CHANGED, LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \
13       LAYER_VISIBILITY_CHANGED       LAYER_VISIBILITY_CHANGED, LAYER_CHANGED, MAP_STACKING_CHANGED, \
14         MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED
15    
16    from Thuban import _
17    
18  from base import TitledObject, Modifiable  from base import TitledObject, Modifiable
19    
20  from label import LabelLayer  from label import LabelLayer
21    
22    
   
23  class Map(TitledObject, Modifiable):  class Map(TitledObject, Modifiable):
24    
25      """Represent a map. A map is simply a list of layers.      """Represent a map. A map is a list of layers. Additionally
26        there is a special label layer containing all labels that
27        are defined for the map.
28    
29      Map objects send the following message types:      Map objects send the following message types:
30    
31          TITLE_CHANGED -- The title has changed. Parameter: the map.          TITLE_CHANGED -- The title has changed. Parameter: the map.
32    
33          LAYERS_CHANGED -- Layers were added, removed or rearranged.          MAP_LAYERS_CHANGED -- Layers were added, removed or rearranged.
34                          Parameters: the map                          Parameters: the map
35    
36          MAP_PROJECTION_CHANGED -- the map's projection has changed.          MAP_PROJECTION_CHANGED -- the map's projection has changed.
37                          Parameter: the map                          Parameter: the map
38      """      """
39    
40      forwarded_channels = (LAYER_PROJECTION_CHANGED,      forwarded_channels = (CHANGED,
41                              LAYER_PROJECTION_CHANGED,
42                            LAYER_LEGEND_CHANGED,                            LAYER_LEGEND_CHANGED,
43                              LAYER_CHANGED,
44                            LAYER_VISIBILITY_CHANGED)                            LAYER_VISIBILITY_CHANGED)
45    
46      def __init__(self, title, projection = None):      def __init__(self, title, projection = None):
47          """Initialize the map."""          """Initialize the map."""
48          TitledObject.__init__(self, title)          TitledObject.__init__(self, title)
49            Modifiable.__init__(self)
50          self.layers = []          self.layers = []
51          self.label_layer = LabelLayer("Labels")          self.label_layer = LabelLayer(_("Labels"))
52          self.label_layer.Subscribe(CHANGED, self.forward, LAYERS_CHANGED)          self.label_layer.Subscribe(CHANGED, self.forward, MAP_LAYERS_CHANGED)
53          self.projection = projection          self.projection = projection
54    
55      def Destroy(self):      def Destroy(self):
56          for layer in self.layers:          """Destroys the map object with all layers including
57              layer.Destroy()          the label layer.
58    
59            Calls Modifiable.Destroy first since it will call
60            Publisher.Destroy which removes all subscriptions. Otherwise
61            clearing the layers results in messages to be sent which can
62            cause problems.
63            """
64          Modifiable.Destroy(self)          Modifiable.Destroy(self)
65            self.ClearLayers()
66            self.label_layer.Unsubscribe(CHANGED, self.forward, MAP_LAYERS_CHANGED)
67            self.label_layer.Destroy()
68    
69      def AddLayer(self, layer):      def AddLayer(self, layer):
70            """Append layer to the map on top of all."""
71          self.layers.append(layer)          self.layers.append(layer)
72            self.subscribe_layer_channels(layer)
73            self.changed(MAP_LAYERS_CHANGED, self)
74            self.changed(MAP_LAYERS_ADDED, self)
75    
76        def RemoveLayer(self, layer):
77            """Remove layer from the map.
78            This can not be applied for the label layer of the map.
79            """
80            self.unsubscribe_layer_channels(layer)
81            self.layers.remove(layer)
82            self.changed(MAP_LAYERS_CHANGED, self)
83            self.changed(MAP_LAYERS_REMOVED, self)
84            layer.Destroy()
85    
86        def CanRemoveLayer(self, layer):
87            """Return true if the layer can be deleted.
88    
89            The default implementation always returns 1. Derived classes
90            should override this method if they have e.g. special layers
91            that the user should not be able to remove.
92            """
93            return 1
94    
95        def ClearLayers(self):
96            """Delete all layers and also remove all labels from the
97            label layer.
98            """
99            for layer in self.layers:
100                self.unsubscribe_layer_channels(layer)
101                layer.Destroy()
102            del self.layers[:]
103            self.label_layer.ClearLabels()
104            self.changed(MAP_LAYERS_CHANGED, self)
105            self.changed(MAP_LAYERS_REMOVED, self)
106    
107        def subscribe_layer_channels(self, layer):
108            """Subscribe to some of layer's channels."""
109          for channel in self.forwarded_channels:          for channel in self.forwarded_channels:
110              layer.Subscribe(channel, self.forward, channel)              layer.Subscribe(channel, self.forward, channel)
         self.changed(LAYERS_CHANGED, self)  
111    
112      def RemoveLayer(self, layer):      def unsubscribe_layer_channels(self, layer):
113            """Unsubscribe to some of layer's channels."""
114          for channel in self.forwarded_channels:          for channel in self.forwarded_channels:
115              layer.Unsubscribe(channel, self.forward, channel)              layer.Unsubscribe(channel, self.forward, channel)
         self.layers.remove(layer)  
         self.changed(LAYERS_CHANGED, self)  
         layer.Destroy()  
116    
117      def LabelLayer(self):      def LabelLayer(self):
118          """Return the Map's label layer"""          """Return the Map's label layer"""
119          return self.label_layer          return self.label_layer
120    
121      def Layers(self):      def Layers(self):
122            """Return the list of layers contained in the map.
123    
124            The list does not include the label layer which
125            can be retrieved by a separate method."""
126          return self.layers          return self.layers
127    
128      def HasLayers(self):      def HasLayers(self):
129            """Return true if the map has at least one layer other
130            than the label layer."""
131          return len(self.layers) > 0          return len(self.layers) > 0
132    
133        def MoveLayerToTop(self, layer):
134            """Put the layer on top of the layer stack. This can not
135            be applied to the label layer.
136    
137            If the layer is already at the top do nothing. If the stacking
138            order has been changed, issue a MAP_LAYERS_CHANGED message.
139            """
140            index = self.layers.index(layer)
141            if index < len(self.layers) - 1:
142                del self.layers[index]
143                self.layers.append(layer)
144                self.changed(MAP_LAYERS_CHANGED, self)
145                self.changed(MAP_STACKING_CHANGED, self)
146    
147      def RaiseLayer(self, layer):      def RaiseLayer(self, layer):
148            """Swap the layer with the one above it. This does
149            not apply to the label layer.
150    
151            If the layer is already at the top do nothing. If the stacking
152            order has been changed, issue a MAP_LAYERS_CHANGED message.
153            """
154          index = self.layers.index(layer)          index = self.layers.index(layer)
155          if index < len(self.layers) - 1:          if index < len(self.layers) - 1:
156              del self.layers[index]              del self.layers[index]
157              self.layers.insert(index + 1, layer)              self.layers.insert(index + 1, layer)
158          self.changed(LAYERS_CHANGED, self)              self.changed(MAP_LAYERS_CHANGED, self)
159                self.changed(MAP_STACKING_CHANGED, self)
160    
161      def LowerLayer(self, layer):      def LowerLayer(self, layer):
162            """Swap the layer with the one below it. This does
163            not apply to the label layer.
164    
165            If the layer is already at the bottom do nothing. If the
166            stacking order has been changed, issue a MAP_LAYERS_CHANGED message.
167            """
168          index = self.layers.index(layer)          index = self.layers.index(layer)
169          if index > 0:          if index > 0:
170              del self.layers[index]              del self.layers[index]
171              self.layers.insert(index - 1, layer)              self.layers.insert(index - 1, layer)
172          self.changed(LAYERS_CHANGED, self)              self.changed(MAP_LAYERS_CHANGED, self)
173                self.changed(MAP_STACKING_CHANGED, self)
174    
175        def MoveLayerToBottom(self, layer):
176            """Put the layer at the bottom of the stack. This does
177            not apply to the label layer.
178    
179            If the layer is already at the bottom do nothing. If the
180            stacking order has been changed, issue a MAP_LAYERS_CHANGED message.
181            """
182            index = self.layers.index(layer)
183            if index > 0:
184                del self.layers[index]
185                self.layers.insert(0, layer)
186                self.changed(MAP_LAYERS_CHANGED, self)
187                self.changed(MAP_STACKING_CHANGED, self)
188    
189      def BoundingBox(self):      def BoundingBox(self):
190            """Return the bounding box of the map in Lat/Lon coordinates.
191            The label layer is not considered for the computation of the
192            bounding box.
193    
194            Return None if there are no layers (except the label layer) or
195            no layer contains any shapes.
196            """
197          if not self.layers:          if not self.layers:
198              return None              return None
199          llx = []          llx = []
# Line 94  class Map(TitledObject, Modifiable): Line 201  class Map(TitledObject, Modifiable):
201          urx = []          urx = []
202          ury = []          ury = []
203          for layer in self.layers:          for layer in self.layers:
204              if layer is self.label_layer:              # the layer's bbox may be None if it doesn't have any shapes
205                  continue              bbox = layer.LatLongBoundingBox()
206              left, bottom, right, top = layer.LatLongBoundingBox()              if bbox is not None:
207              llx.append(left)                  left, bottom, right, top = bbox
208              lly.append(bottom)                  llx.append(left)
209              urx.append(right)                  lly.append(bottom)
210              ury.append(top)                  urx.append(right)
211          return (min(llx), min(lly), max(urx), max(ury))                  ury.append(top)
212    
213            # check whether there were any empty layers.
214            if llx:
215                return (min(llx), min(lly), max(urx), max(ury))
216            else:
217                return None
218    
219      def ProjectedBoundingBox(self):      def ProjectedBoundingBox(self):
220            """Return the bounding box of the map in projected coordinates.
221            The label layer is not considered for the computation of the
222            bounding box.
223    
224            Return None if there are no layers (except the label layer) or
225            no layer contains any shapes.
226            """
227          # This simply returns the rectangle given by the projected          # This simply returns the rectangle given by the projected
228          # corners of the non-projected bbox.          # corners of the non-projected bbox.
229          bbox = self.BoundingBox()          bbox = self.BoundingBox()
# Line 111  class Map(TitledObject, Modifiable): Line 231  class Map(TitledObject, Modifiable):
231              bbox = self.projection.ForwardBBox(bbox)              bbox = self.projection.ForwardBBox(bbox)
232          return bbox          return bbox
233    
234        def GetProjection(self):
235            """Return the projection of the map."""
236            return self.projection
237    
238      def SetProjection(self, projection):      def SetProjection(self, projection):
239            """Set the projection of the map.
240    
241            Issue a MAP_PROJECTION_CHANGED message."""
242            old_proj = self.projection
243          self.projection = projection          self.projection = projection
244          self.changed(MAP_PROJECTION_CHANGED, self)          self.changed(MAP_PROJECTION_CHANGED, self, old_proj)
245    
246      def forward(self, *args):      def forward(self, *args):
247          """Reissue events"""          """Reissue events"""
# Line 138  class Map(TitledObject, Modifiable): Line 266  class Map(TitledObject, Modifiable):
266              layer.UnsetModified()              layer.UnsetModified()
267          self.label_layer.UnsetModified()          self.label_layer.UnsetModified()
268    
269        def TreeInfo(self):
270            """Return a tuple of (title, tupel) describing the contents
271            of the object in a tree-structure.
272            """
273            items = []
274            if self.BoundingBox() != None:
275                items.append(_("Extent (lat-lon): (%g, %g, %g, %g)")
276                             % self.BoundingBox())
277                if self.projection and len(self.projection.params) > 0:
278                    items.append(_("Extent (projected): (%g, %g, %g, %g)")
279                                 % self.ProjectedBoundingBox())
280                    items.append((_("Projection"),
281                                  [str(param)
282                                   for param in self.projection.params]))
283    
284            layers = self.layers[:]
285            layers.reverse()
286            items.extend(layers)
287            items.append(self.label_layer)
288    
289            return (_("Map: %s") % self.title, items)

Legend:
Removed from v.6  
changed lines
  Added in v.2564

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26