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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 429 - (show annotations)
Mon Feb 24 18:46:51 2003 UTC (22 years ago) by jonathan
Original Path: trunk/thuban/Thuban/Model/save.py
File MIME type: text/x-python
File size: 11648 byte(s)
(Saver.write_classificaton): Uses
        the new iterator to save the classification information.

1 # Copyright (c) 2001, 2002 by Intevation GmbH
2 # Authors:
3 # Jan-Oliver Wagner <[email protected]>
4 # Bernhard Herzog <[email protected]>
5 # Jonathan Coles <[email protected]>
6 #
7 # This program is free software under the GPL (>=v2)
8 # Read the file COPYING coming with Thuban for details.
9
10 """
11 Functions to save a session to a file
12 """
13
14 __version__ = "$Revision$"
15
16 import os
17 import string
18
19 import Thuban.Lib.fileutil
20
21 from Thuban.Model.color import Color
22
23 from Thuban.Model.classification import *
24
25 #
26 # one level of indention
27 #
28 TAB = " "
29
30 def relative_filename(dir, filename):
31 """Return a filename relative to dir for the absolute file name absname.
32
33 This is almost the same as the function in fileutil, except that dir
34 can be an empty string in which case filename will be returned
35 unchanged.
36 """
37 if dir:
38 return Thuban.Lib.fileutil.relative_filename(dir, filename)
39 else:
40 return filename
41
42 def escape(data):
43 """Escape &, \", ', <, and > in a string of data.
44 """
45 data = string.replace(data, "&", "&amp;")
46 data = string.replace(data, "<", "&lt;")
47 data = string.replace(data, ">", "&gt;")
48 data = string.replace(data, '"', "&quot;")
49 data = string.replace(data, "'", "&apos;")
50 return data
51
52 class Saver:
53
54 """Class to serialize a session into an XML file.
55
56 Applications built on top of Thuban may derive from this class and
57 override or extend the methods to save additinal information. This
58 additional information should take the form of additional attributes
59 or elements whose names are prefixed with a namespace. To define a
60 namespace derived classes should extend the write_session method to
61 pass the namespaces to the default implementation.
62 """
63
64
65 def __init__(self, session):
66 self.session = session
67
68 def write(self, file_or_filename):
69 """Write the session to a file.
70
71 The argument may be either a file object or a filename. If it's
72 a filename, the file will be opened for writing. Files of
73 shapefiles will be stored as filenames relative to the directory
74 the file is stored in (as given by os.path.dirname(filename)) if
75 they have a common parent directory other than the root
76 directory.
77
78 If the argument is a file object (which is determined by the
79 presence of a write method) all filenames will be absolut
80 filenames.
81 """
82
83 # keep track of how many levels of indentation to write
84 self.indent_level = 0
85 # track whether an element is currently open. see open_element().
86 self.element_open = 0
87
88 if hasattr(file_or_filename, "write"):
89 # it's a file object
90 self.file = file_or_filename
91 self.dir = ""
92 else:
93 filename = file_or_filename
94 self.dir = os.path.dirname(filename)
95 self.file = open(filename, 'w')
96 self.write_header()
97 self.write_session(self.session)
98
99 assert(self.indent_level == 0)
100
101 def write_attribs(self, attrs):
102 for name, value in attrs.items():
103 self.file.write(' %s="%s"' % (escape(name), value))
104
105 def open_element(self, element, attrs = {}):
106
107 #
108 # we note when an element is opened so that if two open_element()
109 # calls are made successively we can end the currently open
110 # tag and will later write a proper close tag. otherwise,
111 # if a close_element() call is made directly after an open_element()
112 # call we will close the tag with a />
113 #
114 if self.element_open == 1:
115 self.file.write(">\n")
116
117 self.element_open = 1
118
119 # Helper function to write an element open tag with attributes
120 self.file.write("%s<%s" % (TAB*self.indent_level, element))
121 self.write_attribs(attrs)
122
123 self.indent_level += 1
124
125 def close_element(self, element):
126 self.indent_level -= 1
127 assert(self.indent_level >= 0)
128
129 # see open_element() for an explanation
130 if self.element_open == 1:
131 self.element_open = 0
132 self.file.write("/>\n")
133 else:
134 self.file.write("%s</%s>\n" % (TAB*self.indent_level, element))
135
136 def write_element(self, element, attrs = {}):
137 """write an element that won't need a closing tag"""
138 self.open_element(element, attrs)
139 self.close_element(element)
140
141 def write_header(self):
142 """Write the XML header"""
143 self.file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
144 self.file.write('<!DOCTYPE session SYSTEM "thuban.dtd">\n')
145
146 def write_session(self, session, attrs = None, namespaces = ()):
147 """Write the session and its contents
148
149 By default, write a session element with the title attribute and
150 call write_map for each map contained in the session.
151
152 The optional argument attrs is for additional attributes and, if
153 given, should be a mapping from attribute names to attribute
154 values. The values should not be XML-escaped yet.
155
156 The optional argument namespaces, if given, should be a sequence
157 of (name, URI) pairs. The namespaces are written as namespace
158 attributes into the session element. This is mainly useful for
159 derived classes that need to store additional information in a
160 thuban session file.
161 """
162 if attrs is None:
163 attrs = {}
164 attrs["title"] = session.title
165 for name, uri in namespaces:
166 attrs["xmlns:" + name] = uri
167 self.open_element("session", attrs)
168 for map in session.Maps():
169 self.write_map(map)
170 self.close_element("session")
171
172 def write_map(self, map):
173 """Write the map and its contents.
174
175 By default, write a map element element with the title
176 attribute, call write_projection to write the projection
177 element, call write_layer for each layer contained in the map
178 and finally call write_label_layer to write the label layer.
179 """
180 write = self.file.write
181 self.open_element('map title="%s"' % escape(map.title))
182 self.write_projection(map.projection)
183 for layer in map.Layers():
184 self.write_layer(layer)
185 self.write_label_layer(map.LabelLayer())
186 self.close_element('map')
187
188 def write_projection(self, projection):
189 """Write the projection.
190 """
191 if projection and len(projection.params) > 0:
192 self.open_element("projection")
193 for param in projection.params:
194 self.write_element('parameter value="%s"' % escape(param))
195 self.close_element("projection")
196
197 def write_layer(self, layer, attrs = None):
198 """Write the layer.
199
200 The optional argument attrs is for additional attributes and, if
201 given, should be a mapping from attribute names to attribute
202 values. The values should not be XML-escaped yet.
203 """
204 lc = layer.GetClassification()
205
206 if attrs is None:
207 attrs = {}
208
209 attrs["title"] = layer.title
210 attrs["filename"] = relative_filename(self.dir, layer.filename)
211 attrs["stroke"] = lc.GetDefaultStroke().hex()
212 attrs["stroke_width"] = str(lc.GetDefaultStrokeWidth())
213 attrs["fill"] = lc.GetDefaultFill().hex()
214
215 self.open_element("layer", attrs)
216 self.write_classification(layer)
217 self.close_element("layer")
218
219 def write_classification(self, layer, attrs = None):
220 if attrs is None:
221 attrs = {}
222
223 lc = layer.GetClassification()
224
225 field = lc.GetField()
226
227 #
228 # there isn't a classification of anything
229 # so don't do anything
230 #
231 if field is None: return
232
233 attrs["field"] = field
234 self.open_element("classification", attrs)
235
236
237 # self.open_element("clnull")
238 # write_class_data(lc.GetDefaultData())
239 # self.close_element("clnull")
240
241 # just playing now with lambdas and dictionaries
242
243 types = {ClassData.DEFAULT:
244 [lambda p: 'clnull',
245 lambda p: 'clnull'],
246 ClassData.POINT:
247 [lambda p: 'clpoint value="%s"' %
248 str(p.GetValue()),
249 lambda p: 'clpoint'],
250 ClassData.RANGE:
251 [lambda p: 'clrange min="%s" max="%s"' %
252 (str(p.GetMin()),
253 (str(p.GetMax()))),
254 lambda p: 'clrange']}
255
256 def write_class_data(data):
257 dict = {'stroke' : data.GetStroke().hex(),
258 'stroke_width': str(data.GetStrokeWidth()),
259 'fill' : data.GetFill().hex()}
260 t = data.GetType()
261 self.open_element(types[t][0](data))
262 self.write_element("cldata", dict)
263 self.close_element(types[t][1](data))
264
265 for i in lc:
266 write_class_data(i)
267
268 # for i in lc:
269 # t = i.GetType()
270 # self.open_element(types[t][0](i))
271 # write_class_data(i)
272 # self.close_element(types[t][1](i))
273
274 # for p in lc:
275 # type = p.GetType()
276 # if p == ClassData.DEFAULT:
277 # lopen = lclose = 'clnull'
278 # elif p == ClassData.POINTS:
279 # lopen = 'clpoint value="%s"' % escape(str(p.GetValue()))
280 # lclose = 'clpoint'
281 # elif p == ClassData.RANGES:
282 # lopen = 'clrange min="%s" max="%s"'
283 # % (escape(str(p.GetMin())), escape(str(p.GetMax()))))
284 # lclose = 'clrange'
285
286 # self.open_element(lopen)
287 # write_class_data(p)
288 # self.close_element(lclose)
289
290 # if lc.points != {}:
291 # for p in lc.points.values():
292 # self.open_element('clpoint value="%s"' %
293 # (escape(str(p.GetValue()))))
294 # write_class_data(p)
295 # self.close_element('clpoint')
296 #
297 # if lc.ranges != []:
298 # for p in lc.ranges:
299 # self.open_element('clrange min="%s" max="%s"'
300 # % (escape(str(p.GetMin())), escape(str(p.GetMax()))))
301 # write_class_data(p)
302 # self.close_element('clrange')
303
304 self.close_element("classification")
305
306 def write_label_layer(self, layer):
307 """Write the label layer.
308 """
309 labels = layer.Labels()
310 if labels:
311 self.open_element('labellayer')
312 for label in labels:
313 self.write_element(('label x="%g" y="%g" text="%s"'
314 ' halign="%s" valign="%s"')
315 % (label.x, label.y, label.text, label.halign,
316 label.valign))
317 self.close_element('labellayer')
318
319
320
321 def save_session(session, file, saver_class = None):
322 """Save the session session to a file.
323
324 The file argument may either be a filename or an open file object.
325
326 The optional argument saver_class is the class to use to serialize
327 the session. By default or if it's None, the saver class will be
328 Saver.
329
330 If writing the session is successful call the session's
331 UnsetModified method
332 """
333 if saver_class is None:
334 saver_class = Saver
335 saver = saver_class(session)
336 saver.write(file)
337
338 # after a successful save consider the session unmodified.
339 session.UnsetModified()

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26