/[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 201 by bh, Mon Jul 8 10:50:53 2002 UTC revision 391 by jonathan, Mon Feb 10 15:26:11 2003 UTC
# Line 17  import string Line 17  import string
17    
18  import Thuban.Lib.fileutil  import Thuban.Lib.fileutil
19    
20    from Thuban.Model.color import Color
21    
22    #
23    # one level of indention
24    #
25    TAB = "    "
26    
27  def relative_filename(dir, filename):  def relative_filename(dir, filename):
28      """Return a filename relative to dir for the absolute file name absname.      """Return a filename relative to dir for the absolute file name absname.
29    
# Line 39  def escape(data): Line 46  def escape(data):
46      data = string.replace(data, "'", "'")      data = string.replace(data, "'", "'")
47      return data      return data
48    
49  def save_session(session, filename):  class Saver:
     """Save the session session to the file given by filename"""  
     dir = os.path.dirname(filename)  
     file = open(filename, 'w')  
     write = file.write  
     write('<?xml version="1.0" encoding="UTF-8"?>\n')  
     write('<!DOCTYPE session SYSTEM "thuban.dtd">\n')  
     write('<session title="%s">\n' % escape(session.title))  
     for map in session.Maps():  
         write('\t<map title="%s">\n' % escape(map.title))  
         if map.projection and len(map.projection.params) > 0:  
             write('\t\t<projection>\n')  
             for param in map.projection.params:  
                 write('\t\t\t<parameter value="%s"/>\n' % escape(param))  
             write('\t\t</projection>\n')  
50    
51          for layer in map.Layers():      """Class to serialize a session into an XML file.
52              fill = layer.fill  
53              if fill is None:      Applications built on top of Thuban may derive from this class and
54                  fill = "None"      override or extend the methods to save additinal information. This
55              else:      additional information should take the form of additional attributes
56                  fill = fill.hex()      or elements whose names are prefixed with a namespace. To define a
57              stroke = layer.stroke      namespace derived classes should extend the write_session method to
58              if stroke is None:      pass the namespaces to the default implementation.
59                  stroke = "None"      """
60    
61    
62        def __init__(self, session):
63            self.session = session
64    
65        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            presence of a write method) all filenames will be absolut
77            filenames.
78            """
79    
80            # 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    
85            if hasattr(file_or_filename, "write"):
86                # it's a file object
87                self.file = file_or_filename
88                self.dir = ""
89            else:
90                filename = file_or_filename
91                self.dir = os.path.dirname(filename)
92                self.file = open(filename, 'w')
93            self.write_header()
94            self.write_session(self.session)
95    
96            if self.indent_level != 0:
97                raise ValueError("indent_level still positive!")
98    
99        def write_attribs(self, attrs):
100            for name, value in attrs.items():
101                if isinstance(value, Color):
102                    value = value.hex()
103              else:              else:
104                  stroke = stroke.hex()                  value = str(value)
105              write(('\t\t<layer title="%s" filename="%s"'              self.file.write(' %s="%s"' % (escape(name), escape(value)))
106                     ' fill="%s" stroke="%s" stroke_width="%d"/>\n') %      
107                    (escape(layer.title),      def open_element(self, element, attrs = {}):
108                     escape(relative_filename(dir, layer.filename)),  
109                     fill, stroke, layer.stroke_width))          #
110          labels = map.LabelLayer().Labels()          # we note when an element is opened so that if two open_element()
111            # calls are made successively we can end the currently open
112            # tag and will later write a proper close tag. otherwise,
113            # if a close_element() call is made directly after an open_element()
114            # call we will close the tag with a />
115            #
116            if self.element_open == 1:
117                self.file.write(">\n")
118    
119            self.element_open = 1
120    
121            # Helper function to write an element open tag with attributes
122            self.file.write("%s<%s" % (TAB*self.indent_level, element))
123            self.write_attribs(attrs)
124    
125            self.indent_level += 1
126    
127        def close_element(self, element):
128            self.indent_level -= 1
129            if self.indent_level < 0:
130                raise ValueError("close_element called too many times!")
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():
187                self.write_layer(layer)
188            self.write_label_layer(map.LabelLayer())
189            self.close_element('map')
190    
191        def write_projection(self, projection):
192            """Write the projection.
193            """
194            if projection and len(projection.params) > 0:
195                self.open_element("projection")
196                for param in projection.params:
197                    self.write_element('parameter value="%s"' % escape(param))
198                self.close_element("projection")
199    
200        def write_layer(self, layer, attrs = None):
201            """Write the layer.
202    
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.classification
208    
209            if attrs is None:
210                attrs = {}
211            attrs["title"] = layer.title
212            attrs["filename"] = relative_filename(self.dir, layer.filename)
213            attrs["stroke_width"] = str(lc.GetDefaultStrokeWidth())
214            fill = lc.GetDefaultFill()
215            if fill is None:
216                attrs["fill"] = "None"
217            else:
218                attrs["fill"] = fill.hex()
219            stroke = lc.GetDefaultStroke()
220            if stroke is None:
221                attrs["stroke"] = "None"
222            else:
223                attrs["stroke"] = stroke.hex()
224    
225            self.open_element("layer", attrs)
226            self.write_classification(layer)
227            self.close_element("layer")
228    
229        def write_classification(self, layer, attrs = None):
230            if attrs is None:
231                attrs = {}
232    
233            lc = layer.classification
234    
235            field = lc.field
236    
237            #
238            # there isn't a classification of anything
239            # so don't do anything
240            #
241            if field is None: return
242    
243            attrs["field"] = field
244            self.open_element("classification", attrs)
245    
246            def write_class_data(data):
247                dict = {'stroke'      : data.GetStroke(),
248                        'stroke_width': data.GetStrokeWidth(),
249                        'fill'        : data.GetFill()}
250                self.write_element("cldata", dict)
251    
252            self.open_element("clnull")
253            write_class_data(lc.GetDefaultData())
254            self.close_element("clnull")
255                
256            if lc.points != {}:
257                for value, data in lc.points.items():
258                    self.open_element('clpoint value="%s"' % (escape(str(value))))
259                    write_class_data(data)
260                    self.close_element('clpoint')
261              
262            if lc.ranges != []:
263                for p in lc.ranges:
264                    self.open_element('clrange min="%s" max="%s"'
265                        % (escape(str(p[0])), escape(str(p[1]))))
266                    write_class_data(p[2])
267                    self.close_element('clrange')
268    
269            self.close_element("classification")
270    
271        def write_label_layer(self, layer):
272            """Write the label layer.
273            """
274            labels = layer.Labels()
275          if labels:          if labels:
276              write('\t\t<labellayer>\n')              self.open_element('labellayer')
277              for label in labels:              for label in labels:
278                  write(('\t\t\t<label x="%g" y="%g" text="%s"'                  self.write_element(('label x="%g" y="%g" text="%s"'
279                         ' halign="%s" valign="%s"/>\n')                                      ' halign="%s" valign="%s"')
280                        % (label.x, label.y, label.text, label.halign,                                  % (label.x, label.y, label.text, label.halign,
281                           label.valign))                                     label.valign))
282              write('\t\t</labellayer>\n')              self.close_element('labellayer')
283          write('\t</map>\n')  
284      write('</session>\n')  
285    
286    def save_session(session, file, saver_class = None):
287        """Save the session session to a file.
288    
289        The file argument may either be a filename or an open file object.
290    
291        The optional argument saver_class is the class to use to serialize
292        the session. By default or if it's None, the saver class will be
293        Saver.
294    
295        If writing the session is successful call the session's
296        UnsetModified method
297        """
298        if saver_class is None:
299            saver_class = Saver
300        saver = saver_class(session)
301        saver.write(file)
302    
303      # after a successful save consider the session unmodified.      # after a successful save consider the session unmodified.
304      session.UnsetModified()      session.UnsetModified()

Legend:
Removed from v.201  
changed lines
  Added in v.391

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26