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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 754 - (hide annotations)
Fri Apr 25 14:48:15 2003 UTC (21 years, 10 months ago) by jonathan
Original Path: trunk/thuban/Thuban/Model/save.py
File MIME type: text/x-python
File size: 11312 byte(s)
(SessionSaver.write_projection): Make sure to save the name of the projection.

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