/[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 773 - (hide annotations)
Tue Apr 29 14:34:23 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: 11384 byte(s)
(SessionSaver.write_layer): Save visible parameter.

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