/[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 740 - (hide annotations)
Fri Apr 25 09:14:04 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: 11241 byte(s)
(SessionSaver.write_layer): Save projection information.

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 366 self.open_element("projection")
214 bh 268 for param in projection.params:
215 jonathan 366 self.write_element('parameter value="%s"' % escape(param))
216     self.close_element("projection")
217 bh 268
218     def write_layer(self, layer, attrs = None):
219     """Write the layer.
220    
221     The optional argument attrs is for additional attributes and, if
222     given, should be a mapping from attribute names to attribute
223     values. The values should not be XML-escaped yet.
224     """
225 jonathan 414 lc = layer.GetClassification()
226 jonathan 391
227 bh 268 if attrs is None:
228     attrs = {}
229 jonathan 429
230     attrs["title"] = layer.title
231     attrs["filename"] = relative_filename(self.dir, layer.filename)
232 jonathan 466 attrs["stroke"] = lc.GetDefaultLineColor().hex()
233     attrs["stroke_width"] = str(lc.GetDefaultLineWidth())
234 jonathan 429 attrs["fill"] = lc.GetDefaultFill().hex()
235 bh 268
236 jonathan 366 self.open_element("layer", attrs)
237 jonathan 740
238     proj = layer.GetProjection()
239     if proj is not None:
240     self.write_projection(proj)
241    
242 jonathan 366 self.write_classification(layer)
243 jonathan 740
244 jonathan 366 self.close_element("layer")
245    
246     def write_classification(self, layer, attrs = None):
247     if attrs is None:
248     attrs = {}
249    
250 jonathan 414 lc = layer.GetClassification()
251 jonathan 366
252 jonathan 429 field = lc.GetField()
253 jonathan 366
254     #
255     # there isn't a classification of anything
256     # so don't do anything
257     #
258     if field is None: return
259    
260     attrs["field"] = field
261 jonathan 466 attrs["field_type"] = str(lc.GetFieldType())
262 jonathan 366 self.open_element("classification", attrs)
263    
264 jonathan 429
265 jonathan 683 types = [[lambda p: 'clnull label="%s"' % p.GetLabel(),
266 jonathan 440 lambda p: 'clnull'],
267 jonathan 683 [lambda p: 'clpoint label="%s" value="%s"' %
268     (p.GetLabel(), str(p.GetValue())),
269 jonathan 440 lambda p: 'clpoint'],
270 jonathan 683 [lambda p: 'clrange label="%s" min="%s" max="%s"' %
271     (p.GetLabel(),
272     str(p.GetMin()), (str(p.GetMax()))),
273 jonathan 440 lambda p: 'clrange']]
274 jonathan 429
275 jonathan 440 def write_class_group(group):
276     type = -1
277     if isinstance(group, ClassGroupDefault): type = 0
278     elif isinstance(group, ClassGroupSingleton): type = 1
279     elif isinstance(group, ClassGroupRange): type = 2
280     elif isinstance(group, ClassGroupMap): type = 3
281 jonathan 605 assert type >= 0
282 jonathan 366
283 jonathan 440 if type <= 2:
284     data = group.GetProperties()
285 jonathan 466 dict = {'stroke' : data.GetLineColor().hex(),
286     'stroke_width': str(data.GetLineWidth()),
287 jonathan 440 'fill' : data.GetFill().hex()}
288    
289     self.open_element(types[type][0](group))
290     self.write_element("cldata", dict)
291     self.close_element(types[type][1](group))
292     else: pass # XXX: we need to handle maps
293    
294 jonathan 429 for i in lc:
295 jonathan 440 write_class_group(i)
296 jonathan 429
297 jonathan 366 self.close_element("classification")
298    
299 bh 268 def write_label_layer(self, layer):
300     """Write the label layer.
301     """
302     labels = layer.Labels()
303 bh 6 if labels:
304 jonathan 366 self.open_element('labellayer')
305 bh 6 for label in labels:
306 jonathan 366 self.write_element(('label x="%g" y="%g" text="%s"'
307     ' halign="%s" valign="%s"')
308 bh 268 % (label.x, label.y, label.text, label.halign,
309     label.valign))
310 jonathan 366 self.close_element('labellayer')
311 bh 6
312 bh 268
313    
314     def save_session(session, file, saver_class = None):
315     """Save the session session to a file.
316    
317     The file argument may either be a filename or an open file object.
318    
319     The optional argument saver_class is the class to use to serialize
320     the session. By default or if it's None, the saver class will be
321 jonathan 697 SessionSaver.
322 bh 268
323     If writing the session is successful call the session's
324     UnsetModified method
325     """
326     if saver_class is None:
327 jonathan 697 saver_class = SessionSaver
328 bh 268 saver = saver_class(session)
329     saver.write(file)
330    
331 bh 6 # after a successful save consider the session unmodified.
332     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