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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26