/[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 414 - (hide 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 bh 74 # Copyright (c) 2001, 2002 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     import os
17     import string
18    
19 bh 201 import Thuban.Lib.fileutil
20 bh 6
21 jonathan 366 from Thuban.Model.color import Color
22    
23     #
24     # one level of indention
25     #
26     TAB = " "
27    
28 bh 201 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 bh 6 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 bh 268 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 jonathan 366
63 bh 268 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 jonathan 366
81 jonathan 391 # 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 jonathan 366
86 bh 268 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 jonathan 366 if self.indent_level != 0:
98     raise ValueError("indent_level still positive!")
99    
100     def write_attribs(self, attrs):
101 bh 268 for name, value in attrs.items():
102 jonathan 366 if isinstance(value, Color):
103     value = value.hex()
104     else:
105     value = str(value)
106 bh 268 self.file.write(' %s="%s"' % (escape(name), escape(value)))
107 jonathan 366
108     def open_element(self, element, attrs = {}):
109 jonathan 391
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 jonathan 366 # 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 bh 268
126 jonathan 366 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 jonathan 391 # 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 jonathan 366 def write_element(self, element, attrs = {}):
141 jonathan 391 """write an element that won't need a closing tag"""
142     self.open_element(element, attrs)
143     self.close_element(element)
144 jonathan 366
145 bh 268 def write_header(self):
146     """Write the XML header"""
147 jonathan 366 self.file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
148     self.file.write('<!DOCTYPE session SYSTEM "thuban.dtd">\n')
149 bh 268
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 jonathan 366 self.open_element("session", attrs)
172 bh 268 for map in session.Maps():
173     self.write_map(map)
174 jonathan 366 self.close_element("session")
175 bh 268
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 jonathan 366 self.open_element('map title="%s"' % escape(map.title))
186 bh 268 self.write_projection(map.projection)
187     for layer in map.Layers():
188     self.write_layer(layer)
189     self.write_label_layer(map.LabelLayer())
190 jonathan 366 self.close_element('map')
191 bh 6
192 bh 268 def write_projection(self, projection):
193     """Write the projection.
194     """
195     if projection and len(projection.params) > 0:
196 jonathan 366 self.open_element("projection")
197 bh 268 for param in projection.params:
198 jonathan 366 self.write_element('parameter value="%s"' % escape(param))
199     self.close_element("projection")
200 bh 268
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 jonathan 414 lc = layer.GetClassification()
209 jonathan 391
210 bh 268 if attrs is None:
211     attrs = {}
212     attrs["title"] = layer.title
213     attrs["filename"] = relative_filename(self.dir, layer.filename)
214 jonathan 414 attrs["stroke"] = lc.GetDefaultStroke().hex()
215 jonathan 391 attrs["stroke_width"] = str(lc.GetDefaultStrokeWidth())
216 jonathan 414 attrs["fill"] = lc.GetDefaultFill().hex()
217 bh 268
218 jonathan 414 #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 jonathan 366 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 jonathan 414 lc = layer.GetClassification()
240 jonathan 366
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 jonathan 391 def write_class_data(data):
253 jonathan 414 dict = {'stroke' : data.GetStroke().hex(),
254     'stroke_width': str(data.GetStrokeWidth()),
255     'fill' : data.GetFill().hex()}
256 jonathan 391 self.write_element("cldata", dict)
257 jonathan 366
258 jonathan 391 self.open_element("clnull")
259     write_class_data(lc.GetDefaultData())
260     self.close_element("clnull")
261    
262 jonathan 366 if lc.points != {}:
263 jonathan 414 for p in lc.points.values():
264     self.open_element('clpoint value="%s"' %
265     (escape(str(p.GetValue()))))
266     write_class_data(p)
267 jonathan 366 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 jonathan 414 % (escape(str(p.GetMin())), escape(str(p.GetMax()))))
273     write_class_data(p)
274 jonathan 366 self.close_element('clrange')
275    
276     self.close_element("classification")
277    
278 bh 268 def write_label_layer(self, layer):
279     """Write the label layer.
280     """
281     labels = layer.Labels()
282 bh 6 if labels:
283 jonathan 366 self.open_element('labellayer')
284 bh 6 for label in labels:
285 jonathan 366 self.write_element(('label x="%g" y="%g" text="%s"'
286     ' halign="%s" valign="%s"')
287 bh 268 % (label.x, label.y, label.text, label.halign,
288     label.valign))
289 jonathan 366 self.close_element('labellayer')
290 bh 6
291 bh 268
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 bh 6 # 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