/[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 414 - (show annotations)
Wed Feb 19 16:52:23 2003 UTC (22 years ago) by jonathan
Original Path: trunk/thuban/Thuban/Model/save.py
File MIME type: text/x-python
File size: 10575 byte(s)
(Saver): Use new Color and Classification methods

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