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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 6 by bh, Tue Aug 28 15:41:52 2001 UTC revision 683 by jonathan, Tue Apr 15 21:54:56 2003 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2  # Authors:  # Authors:
3  # Jan-Oliver Wagner <[email protected]>  # Jan-Oliver Wagner <[email protected]>
4  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
5    # Jonathan Coles <[email protected]>
6  #  #
7  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
8  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
# Line 12  Functions to save a session to a file Line 13  Functions to save a session to a file
13    
14  __version__ = "$Revision$"  __version__ = "$Revision$"
15    
16    # fix for people using python2.1
17    from __future__ import nested_scopes
18    
19  import os  import os
20  import string  import string
21    
22  from Thuban.Lib.fileutil import relative_filename  import Thuban.Lib.fileutil
23    
24    from Thuban.Model.color import Color
25    
26    from Thuban.Model.classification import *
27    
28    #
29    # one level of indention
30    #
31    TAB = "    "
32    
33    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  def escape(data):  def escape(data):
46      """Escape &, \", ', <, and > in a string of data.      """Escape &, \", ', <, and > in a string of data.
# Line 27  def escape(data): Line 52  def escape(data):
52      data = string.replace(data, "'", "&apos;")      data = string.replace(data, "'", "&apos;")
53      return data      return data
54    
55  def save_session(session, filename):  class Saver:
56      """Save the session session to the file given by filename"""  
57      dir = os.path.dirname(filename)      """Class to serialize a session into an XML file.
58      file = open(filename, 'w')  
59      write = file.write      Applications built on top of Thuban may derive from this class and
60      write('<?xml version="1.0" encoding="UTF-8"?>\n')      override or extend the methods to save additional information. This
61      write('<!DOCTYPE session SYSTEM "thuban.dtd">\n')      additional information should take the form of additional attributes
62      write('<session title="%s">\n' % escape(session.title))      or elements whose names are prefixed with a namespace. To define a
63      for map in session.Maps():      namespace derived classes should extend the write_session method to
64          write('\t<map title="%s">\n' % escape(map.title))      pass the namespaces to the default implementation.
65          if map.projection and len(map.projection.params) > 0:      """
66              write('\t\t<projection>\n')  
67              for param in map.projection.params:  
68                  write('\t\t\t<parameter value="%s"/>\n' % escape(param))      def __init__(self, session):
69              write('\t\t</projection>\n')          self.session = session
70    
71        def write(self, file_or_filename):
72            """Write the session to a file.
73    
74            The argument may be either a file object or a filename. If it's
75            a filename, the file will be opened for writing. Files of
76            shapefiles will be stored as filenames relative to the directory
77            the file is stored in (as given by os.path.dirname(filename)) if
78            they have a common parent directory other than the root
79            directory.
80    
81            If the argument is a file object (which is determined by the
82            presence of a write method) all filenames will be absolut
83            filenames.
84            """
85    
86            # keep track of how many levels of indentation to write
87            self.indent_level = 0
88            # track whether an element is currently open. see open_element().
89            self.element_open = 0
90    
91            if hasattr(file_or_filename, "write"):
92                # it's a file object
93                self.file = file_or_filename
94                self.dir = ""
95            else:
96                filename = file_or_filename
97                self.dir = os.path.dirname(filename)
98                self.file = open(filename, 'w')
99            self.write_header()
100            self.write_session(self.session)
101    
102            assert self.indent_level == 0
103    
104        def write_attribs(self, attrs):
105            for name, value in attrs.items():
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            assert self.indent_level >= 0
131    
132            # see open_element() for an explanation
133            if self.element_open == 1:
134                self.element_open = 0
135                self.file.write("/>\n")
136            else:
137                self.file.write("%s</%s>\n" % (TAB*self.indent_level, element))
138    
139        def write_element(self, element, attrs = {}):
140            """write an element that won't need a closing tag"""
141            self.open_element(element, attrs)
142            self.close_element(element)
143    
144        def write_header(self):
145            """Write the XML header"""
146            self.file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
147            self.file.write('<!DOCTYPE session SYSTEM "thuban.dtd">\n')
148    
149        def write_session(self, session, attrs = None, namespaces = ()):
150            """Write the session and its contents
151    
152            By default, write a session element with the title attribute and
153            call write_map for each map contained in the session.
154    
155            The optional argument attrs is for additional attributes and, if
156            given, should be a mapping from attribute names to attribute
157            values. The values should not be XML-escaped yet.
158    
159            The optional argument namespaces, if given, should be a sequence
160            of (name, URI) pairs. The namespaces are written as namespace
161            attributes into the session element. This is mainly useful for
162            derived classes that need to store additional information in a
163            thuban session file.
164            """
165            if attrs is None:
166                attrs = {}
167            attrs["title"] = session.title
168            for name, uri in namespaces:
169                attrs["xmlns:" + name] = uri
170            self.open_element("session", attrs)
171            for map in session.Maps():
172                self.write_map(map)
173            self.close_element("session")
174    
175        def write_map(self, map):
176            """Write the map and its contents.
177    
178            By default, write a map element element with the title
179            attribute, call write_projection to write the projection
180            element, call write_layer for each layer contained in the map
181            and finally call write_label_layer to write the label layer.
182            """
183            #write = self.file.write
184            self.open_element('map title="%s"' % escape(map.title))
185            self.write_projection(map.projection)
186          for layer in map.Layers():          for layer in map.Layers():
187              fill = layer.fill              self.write_layer(layer)
188              if fill is None:          self.write_label_layer(map.LabelLayer())
189                  fill = "None"          self.close_element('map')
190              else:  
191                  fill = fill.hex()      def write_projection(self, projection):
192              stroke = layer.stroke          """Write the projection.
193              if stroke is None:          """
194                  stroke = "None"          if projection and len(projection.params) > 0:
195              else:              self.open_element("projection")
196                  stroke = stroke.hex()              for param in projection.params:
197              write(('\t\t<layer title="%s" filename="%s"'                  self.write_element('parameter value="%s"' % escape(param))
198                     ' fill="%s" stroke="%s"/>\n') %              self.close_element("projection")
199                    (escape(layer.title),  
200                     escape(relative_filename(dir, layer.filename)),      def write_layer(self, layer, attrs = None):
201                     fill, stroke))          """Write the layer.
202          labels = map.LabelLayer().Labels()  
203            The optional argument attrs is for additional attributes and, if
204            given, should be a mapping from attribute names to attribute
205            values. The values should not be XML-escaped yet.
206            """
207            lc = layer.GetClassification()
208    
209            if attrs is None:
210                attrs = {}
211    
212            attrs["title"]        = layer.title
213            attrs["filename"]     = relative_filename(self.dir, layer.filename)
214            attrs["stroke"]       = lc.GetDefaultLineColor().hex()
215            attrs["stroke_width"] = str(lc.GetDefaultLineWidth())
216            attrs["fill"]         = lc.GetDefaultFill().hex()
217    
218            self.open_element("layer", attrs)
219            self.write_classification(layer)
220            self.close_element("layer")
221    
222        def write_classification(self, layer, attrs = None):
223            if attrs is None:
224                attrs = {}
225    
226            lc = layer.GetClassification()
227    
228            field = lc.GetField()
229    
230            #
231            # there isn't a classification of anything
232            # so don't do anything
233            #
234            if field is None: return
235    
236            attrs["field"] = field
237            attrs["field_type"] = str(lc.GetFieldType())
238            self.open_element("classification", attrs)
239    
240    
241    #       self.open_element("clnull")
242    #       write_class_data(lc.GetDefaultData())
243    #       self.close_element("clnull")
244                
245            # just playing now with lambdas and dictionaries
246    
247            types = [[lambda p: 'clnull label="%s"' % p.GetLabel(),
248                      lambda p: 'clnull'],
249                     [lambda p: 'clpoint label="%s" value="%s"' %
250                                 (p.GetLabel(), str(p.GetValue())),
251                      lambda p: 'clpoint'],
252                     [lambda p: 'clrange label="%s" min="%s" max="%s"' %
253                                 (p.GetLabel(),
254                                  str(p.GetMin()), (str(p.GetMax()))),
255                      lambda p: 'clrange']]
256    
257            def write_class_group(group):
258                type = -1
259                if isinstance(group, ClassGroupDefault): type = 0
260                elif isinstance(group, ClassGroupSingleton): type = 1
261                elif isinstance(group, ClassGroupRange): type = 2
262                elif isinstance(group, ClassGroupMap):   type = 3
263                assert type >= 0
264    
265                if type <= 2:
266                    data = group.GetProperties()
267                    dict = {'stroke'      : data.GetLineColor().hex(),
268                            'stroke_width': str(data.GetLineWidth()),
269                            'fill'        : data.GetFill().hex()}
270    
271                    self.open_element(types[type][0](group))
272                    self.write_element("cldata", dict)
273                    self.close_element(types[type][1](group))
274                else: pass # XXX: we need to handle maps
275    
276            for i in lc:
277                write_class_group(i)
278    
279    #       for i in lc:
280    #           t = i.GetType()
281    #           self.open_element(types[t][0](i))
282    #           write_class_data(i)
283    #           self.close_element(types[t][1](i))
284    
285    #       for p in lc:
286    #           type = p.GetType()
287    #           if p == ClassData.DEFAULT:
288    #               lopen = lclose = 'clnull'
289    #           elif p == ClassData.POINTS:
290    #               lopen = 'clpoint value="%s"' % escape(str(p.GetValue()))
291    #               lclose = 'clpoint'
292    #           elif p == ClassData.RANGES:
293    #               lopen = 'clrange min="%s" max="%s"'
294    #                   % (escape(str(p.GetMin())), escape(str(p.GetMax()))))
295    #               lclose = 'clrange'
296    
297    #           self.open_element(lopen)
298    #           write_class_data(p)
299    #           self.close_element(lclose)
300                
301    #       if lc.points != {}:
302    #           for p in lc.points.values():
303    #               self.open_element('clpoint value="%s"' %
304    #                   (escape(str(p.GetValue()))))
305    #               write_class_data(p)
306    #               self.close_element('clpoint')
307    #          
308    #       if lc.ranges != []:
309    #           for p in lc.ranges:
310    #               self.open_element('clrange min="%s" max="%s"'
311    #                   % (escape(str(p.GetMin())), escape(str(p.GetMax()))))
312    #               write_class_data(p)
313    #               self.close_element('clrange')
314    
315            self.close_element("classification")
316    
317        def write_label_layer(self, layer):
318            """Write the label layer.
319            """
320            labels = layer.Labels()
321          if labels:          if labels:
322              write('\t\t<labellayer>\n')              self.open_element('labellayer')
323              for label in labels:              for label in labels:
324                  write(('\t\t\t<label x="%g" y="%g" text="%s"'                  self.write_element(('label x="%g" y="%g" text="%s"'
325                         ' halign="%s" valign="%s"/>\n')                                      ' halign="%s" valign="%s"')
326                        % (label.x, label.y, label.text, label.halign,                                  % (label.x, label.y, label.text, label.halign,
327                           label.valign))                                     label.valign))
328              write('\t\t</labellayer>\n')              self.close_element('labellayer')
329          write('\t</map>\n')  
330      write('</session>\n')  
331    
332    def save_session(session, file, saver_class = None):
333        """Save the session session to a file.
334    
335        The file argument may either be a filename or an open file object.
336    
337        The optional argument saver_class is the class to use to serialize
338        the session. By default or if it's None, the saver class will be
339        Saver.
340    
341        If writing the session is successful call the session's
342        UnsetModified method
343        """
344        if saver_class is None:
345            saver_class = Saver
346        saver = saver_class(session)
347        saver.write(file)
348    
349      # after a successful save consider the session unmodified.      # after a successful save consider the session unmodified.
350      session.UnsetModified()      session.UnsetModified()

Legend:
Removed from v.6  
changed lines
  Added in v.683

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26