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

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

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

revision 365 by jonathan, Mon Jan 27 11:47:53 2003 UTC revision 1664 by bh, Wed Aug 27 15:20:54 2003 UTC
# Line 1  Line 1 
1  # Copyright (C) 2001, 2002 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 GRASS for details.  # Read the file COPYING coming with GRASS for details.
# Line 12  Parser for thuban session files. Line 13  Parser for thuban session files.
13    
14  __version__ = "$Revision$"  __version__ = "$Revision$"
15    
16  import sys, string, os  import string, os
17    
18  import xml.sax  import xml.sax
19  import xml.sax.handler  import xml.sax.handler
20  from xml.sax import make_parser, ErrorHandler  from xml.sax import make_parser, ErrorHandler, SAXNotRecognizedException
21    
22    from Thuban import _
23    
24    from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
25         FIELDTYPE_STRING
26    
27    from Thuban.Model.color import Color, Transparent
28    
29  from Thuban.Model.session import Session  from Thuban.Model.session import Session
30  from Thuban.Model.map import Map  from Thuban.Model.map import Map
31  from Thuban.Model.layer import Layer  from Thuban.Model.layer import Layer, RasterLayer
 from Thuban.Model.color import Color  
32  from Thuban.Model.proj import Projection  from Thuban.Model.proj import Projection
33  from Thuban.Model.classification import Classification  from Thuban.Model.range import Range
34    from Thuban.Model.classification import Classification, \
35        ClassGroupDefault, ClassGroupSingleton, ClassGroupRange, ClassGroupMap, \
36        ClassGroupProperties
37    from Thuban.Model.data import DerivedShapeStore, ShapefileStore
38    from Thuban.Model.table import DBFTable
39    from Thuban.Model.transientdb import TransientJoinedTable
40    
41    from Thuban.Model.xmlreader import XMLReader
42    import resource
43    
44    import postgisdb
45    
46    class LoadError(Exception):
47    
48        """Exception raised when the thuban file is corrupted
49    
50        Not all cases of corrupted thuban files will lead to this exception
51        but those that are found by checks in the loading code itself are.
52        """
53    
54    
55    class LoadCancelled(Exception):
56    
57        """Exception raised to indicate that loading was interrupted by the user"""
58    
59    
60  def parse_color(color):  def parse_color(color):
# Line 34  def parse_color(color): Line 65  def parse_color(color):
65      """      """
66      color = string.strip(color)      color = string.strip(color)
67      if color == "None":      if color == "None":
68          result = None          result = Transparent
69      elif color[0] == '#':      elif color[0] == '#':
70          if len(color) == 7:          if len(color) == 7:
71              r = string.atoi(color[1:3], 16) / 255.0              r = string.atoi(color[1:3], 16) / 255.0
# Line 42  def parse_color(color): Line 73  def parse_color(color):
73              b = string.atoi(color[5:7], 16) / 255.0              b = string.atoi(color[5:7], 16) / 255.0
74              result = Color(r, g, b)              result = Color(r, g, b)
75          else:          else:
76              raise ValueError("Invalid hexadecimal color specification %s"              raise ValueError(_("Invalid hexadecimal color specification %s")
77                               % color)                               % color)
78      else:      else:
79          raise ValueError("Invalid color specification %s" % color)          raise ValueError(_("Invalid color specification %s") % color)
80      return result      return result
81    
82    class AttrDesc:
83    
84  class ProcessSession(xml.sax.handler.ContentHandler):      def __init__(self, name, required = False, default = "",
85                     conversion = None):
86            if not isinstance(name, tuple):
87                fullname = (None, name)
88            else:
89                fullname = name
90                name = name[1]
91            self.name = name
92            self.fullname = fullname
93            self.required = required
94            self.default = default
95            self.conversion = conversion
96    
97            # set by the SessionLoader's check_attrs method
98            self.value = None
99    
100    
101    class SessionLoader(XMLReader):
102    
103        def __init__(self, db_connection_callback = None):
104            """Inititialize the Sax handler."""
105            XMLReader.__init__(self)
106    
107            self.db_connection_callback = db_connection_callback
108    
     # Dictionary mapping element names (or (URI, element name) pairs for  
     # documents using namespaces) to method names. The methods should  
     # accept the same parameters as the startElement (or startElementNS)  
     # methods. The start_dispatcher is used by the default startElement  
     # and startElementNS methods to call a method for the open tag of an  
     # element.  
     start_dispatcher = {}  
   
     # end_dispatcher works just like start_dispatcher but it's used by  
     # endElement and endElementNS. The method whose names it maps to  
     # should accept the same parameters as endElement and endElementNS.  
     end_dispatcher = {}  
   
   
     def __init__(self, directory):  
         """Inititialize the Sax handler.  
   
         The directory parameter should be the directory containing the  
         session file. It's needed to interpret embedded relative  
         filenames.  
         """  
         self.directory = directory  
         self.chars = ''  
109          self.theSession = None          self.theSession = None
110          self.aMap = None          self.aMap = None
111          self.aLayer = None          self.aLayer = None
112    
113      def startElementNS(self, name, qname, attrs):          # Map ids used in the thuban file to the corresponding objects
114          """Call the method given for name in self.start_dispatcher          # in the session
115          """          self.idmap = {}
116          if name[0] is None:  
117              method_name = self.start_dispatcher.get(name[1])          dispatchers = {
118          else:              'session'       : ("start_session",        "end_session"),
119              # Dispatch with namespace  
120              method_name = self.start_dispatcher.get(name)              'dbconnection': ("start_dbconnection", None),
121          if method_name is not None:  
122              getattr(self, method_name)(name, qname, attrs)              'dbshapesource': ("start_dbshapesource", None),
123                'fileshapesource': ("start_fileshapesource", None),
124                'derivedshapesource': ("start_derivedshapesource", None),
125                'filetable': ("start_filetable", None),
126                'jointable': ("start_jointable", None),
127    
128                'map'           : ("start_map",            "end_map"),
129                'projection'    : ("start_projection",     "end_projection"),
130                'parameter'     : ("start_parameter",      None),
131                'layer'         : ("start_layer",          "end_layer"),
132                'rasterlayer'   : ("start_rasterlayer",    "end_rasterlayer"),
133                'classification': ("start_classification", "end_classification"),
134                'clnull'        : ("start_clnull",         "end_clnull"),
135                'clpoint'       : ("start_clpoint",        "end_clpoint"),
136                'clrange'       : ("start_clrange",        "end_clrange"),
137                'cldata'        : ("start_cldata",         "end_cldata"),
138                'table'         : ("start_table",          "end_table"),
139                'labellayer'    : ("start_labellayer",     None),
140                'label'         : ("start_label",          None)}
141    
142            # all dispatchers should be used for the 0.8 and 0.9 namespaces too
143            for xmlns in ("http://thuban.intevation.org/dtds/thuban-0.8.dtd",
144                          "http://thuban.intevation.org/dtds/thuban-0.9-dev.dtd",
145                          "http://thuban.intevation.org/dtds/thuban-0.9.dtd"):
146                for key, value in dispatchers.items():
147                    dispatchers[(xmlns, key)] = value
148    
149      def endElementNS(self, name, qname):          XMLReader.AddDispatchers(self, dispatchers)
         """Call the method given for name in self.end_dispatcher  
         """  
         if name[0] is None:  
             method_name = self.end_dispatcher.get(name[1])  
         else:  
             # Dispatch with namespace  
             method_name = self.end_dispatcher.get(name)  
         if method_name is not None:  
             getattr(self, method_name)(name, qname)  
150    
151      def start_session(self, name, qname, attrs):      def start_session(self, name, qname, attrs):
152          self.theSession = Session(attrs.get((None, 'title'), None))          self.theSession = Session(self.encode(attrs.get((None, 'title'),
153      start_dispatcher['session'] = "start_session"                                                          None)))
154    
155      def end_session(self, name, qname):      def end_session(self, name, qname):
156          pass          pass
157      end_dispatcher['session'] = "end_session"  
158        def check_attrs(self, element, attrs, descr):
159            """Check and convert some of the attributes of an element
160    
161            Parameters:
162               element -- The element name
163               attrs -- The attrs mapping as passed to the start_* methods
164               descr -- Sequence of attribute descriptions (AttrDesc instances)
165    
166            Return a dictionary containig normalized versions of the
167            attributes described in descr. The keys of that dictionary are
168            the name attributes of the attribute descriptions. The attrs
169            dictionary will not be modified.
170    
171            If the attribute is required, i.e. the 'required' attribute of
172            the descrtiption is true, but it is not in attrs, raise a
173            LoadError.
174    
175            If the attribute has a default value and it is not present in
176            attrs, use that default value as the value in the returned dict.
177    
178            If a conversion is specified, convert the value before putting
179            it into the returned dict. The following conversions are
180            available:
181    
182               'filename' -- The attribute is a filename.
183    
184                             If the filename is a relative name, interpret
185                             it relative to the directory containing the
186                             .thuban file and make it an absolute name
187    
188               'shapestore' -- The attribute is the ID of a shapestore
189                               defined earlier in the .thuban file. Look it
190                               up self.idmap
191    
192               'table' -- The attribute is the ID of a table or shapestore
193                          defined earlier in the .thuban file. Look it up
194                          self.idmap. If it's the ID of a shapestore the
195                          value will be the table of the shapestore.
196    
197               'idref' -- The attribute is the id of an object defined
198                          earlier in the .thuban file. Look it up self.idmap
199    
200               'ascii' -- The attribute is converted to a bytestring with
201                          ascii encoding.
202            """
203            normalized = {}
204    
205            for d in descr:
206                if d.required and not attrs.has_key(d.fullname):
207                    raise LoadError("Element %s requires an attribute %r"
208                                    % (element, d.name))
209                value = attrs.get(d.fullname, d.default)
210    
211                if d.conversion in ("idref", "shapesource"):
212                    if value in self.idmap:
213                        value = self.idmap[value]
214                    else:
215                        raise LoadError("Element %s requires an already defined ID"
216                                        " in attribute %r"
217                                        % (element, d.name))
218                elif d.conversion == "table":
219                    if value in self.idmap:
220                        value = self.idmap[value]
221                        if isinstance(value, ShapefileStore):
222                            value = value.Table()
223                    else:
224                        raise LoadError("Element %s requires an already defined ID"
225                                        " in attribute %r"
226                                        % (element, d.name))
227                elif d.conversion == "filename":
228                    value = os.path.abspath(os.path.join(self.GetDirectory(),
229                                                         value))
230                elif d.conversion == "ascii":
231                    value = value.encode("ascii")
232                else:
233                    if d.conversion:
234                        raise ValueError("Unknown attribute conversion %r"
235                                         % d.conversion)
236    
237                normalized[d.name] = value
238            return normalized
239    
240        def start_dbconnection(self, name, qname, attrs):
241            attrs = self.check_attrs(name, attrs,
242                                     [AttrDesc("id", True),
243                                      AttrDesc("dbtype", True),
244                                      AttrDesc("host", False, ""),
245                                      AttrDesc("port", False, ""),
246                                      AttrDesc("user", False, ""),
247                                      AttrDesc("dbname", True)])
248            ID = attrs["id"]
249            dbtype = attrs["dbtype"]
250            if dbtype != "postgis":
251                raise LoadError("dbtype %r not supported" % filetype)
252    
253            del attrs["id"]
254            del attrs["dbtype"]
255    
256            # Try to open the connection and if it fails ask the user for
257            # the correct parameters repeatedly.
258            # FIXME: it would be better not to insist on getting a
259            # connection here. We should handle this more like the raster
260            # images where the layers etc still are created but are not
261            # drawn in case Thuban can't use the data for various reasons
262            while 1:
263                try:
264                    conn = postgisdb.PostGISConnection(**attrs)
265                    break
266                except postgisdb.ConnectionError, val:
267                    if self.db_connection_callback is not None:
268                        attrs = self.db_connection_callback(attrs, str(val))
269                        if attrs is None:
270                            raise LoadCancelled
271                    else:
272                        raise
273    
274            self.idmap[ID] = conn
275            self.theSession.AddDBConnection(conn)
276    
277        def start_dbshapesource(self, name, qname, attrs):
278            attrs = self.check_attrs(name, attrs,
279                                     [AttrDesc("id", True),
280                                      AttrDesc("dbconn", True,
281                                               conversion = "idref"),
282                                      AttrDesc("tablename", True,
283                                               conversion = "ascii")])
284            ID = attrs["id"]
285            db = attrs["dbconn"]
286            tablename = attrs["tablename"]
287            self.idmap[ID] = self.theSession.OpenDBShapeStore(db, tablename)
288    
289        def start_fileshapesource(self, name, qname, attrs):
290            attrs = self.check_attrs(name, attrs,
291                                      [AttrDesc("id", True),
292                                       AttrDesc("filename", True,
293                                                conversion = "filename"),
294                                       AttrDesc("filetype", True)])
295            ID = attrs["id"]
296            filename = attrs["filename"]
297            filetype = attrs["filetype"]
298            if filetype != "shapefile":
299                raise LoadError("shapesource filetype %r not supported" % filetype)
300            self.idmap[ID] = self.theSession.OpenShapefile(filename)
301    
302        def start_derivedshapesource(self, name, qname, attrs):
303            attrs = self.check_attrs(name, attrs,
304                                     [AttrDesc("id", True),
305                                      AttrDesc("shapesource", True,
306                                               conversion = "shapesource"),
307                                      AttrDesc("table", True, conversion="table")])
308            store = DerivedShapeStore(attrs["shapesource"], attrs["table"])
309            self.theSession.AddShapeStore(store)
310            self.idmap[attrs["id"]] = store
311    
312        def start_filetable(self, name, qname, attrs):
313            attrs = self.check_attrs(name, attrs,
314                                     [AttrDesc("id", True),
315                                      AttrDesc("title", True),
316                                      AttrDesc("filename", True,
317                                               conversion = "filename"),
318                                      AttrDesc("filetype")])
319            filetype = attrs["filetype"]
320            if filetype != "DBF":
321                raise LoadError("shapesource filetype %r not supported" % filetype)
322            table = DBFTable(attrs["filename"])
323            table.SetTitle(attrs["title"])
324            self.idmap[attrs["id"]] = self.theSession.AddTable(table)
325    
326        def start_jointable(self, name, qname, attrs):
327            attrs = self.check_attrs(name, attrs,
328                                     [AttrDesc("id", True),
329                                      AttrDesc("title", True),
330                                      AttrDesc("left", True, conversion="table"),
331                                      AttrDesc("leftcolumn", True),
332                                      AttrDesc("right", True, conversion="table"),
333                                      AttrDesc("rightcolumn", True),
334    
335                                      # jointype is required for file
336                                      # version 0.9 but this attribute
337                                      # wasn't in the 0.8 version because of
338                                      # an oversight so we assume it's
339                                      # optional since we want to handle
340                                      # both file format versions here.
341                                      AttrDesc("jointype", False,
342                                               default="INNER")])
343    
344            jointype = attrs["jointype"]
345            if jointype == "LEFT OUTER":
346                outer_join = True
347            elif jointype == "INNER":
348                outer_join = False
349            else:
350                raise LoadError("jointype %r not supported" % jointype )
351            table = TransientJoinedTable(self.theSession.TransientDB(),
352                                         attrs["left"], attrs["leftcolumn"],
353                                         attrs["right"], attrs["rightcolumn"],
354                                         outer_join = outer_join)
355            table.SetTitle(attrs["title"])
356            self.idmap[attrs["id"]] = self.theSession.AddTable(table)
357    
358      def start_map(self, name, qname, attrs):      def start_map(self, name, qname, attrs):
359          """Start a map."""          """Start a map."""
360          self.aMap = Map(attrs.get((None, 'title'), None))          self.aMap = Map(self.encode(attrs.get((None, 'title'), None)))
     start_dispatcher['map'] = "start_map"  
361    
362      def end_map(self, name, qname):      def end_map(self, name, qname):
363          self.theSession.AddMap(self.aMap)          self.theSession.AddMap(self.aMap)
364      end_dispatcher['map'] = "end_map"          self.aMap = None
365    
366      def start_projection(self, name, qname, attrs):      def start_projection(self, name, qname, attrs):
367            self.ProjectionName = self.encode(attrs.get((None, 'name'), None))
368          self.ProjectionParams = [ ]          self.ProjectionParams = [ ]
     start_dispatcher['projection'] = "start_projection"  
369    
370      def end_projection(self, name, qname):      def end_projection(self, name, qname):
371          self.aMap.SetProjection(Projection(self.ProjectionParams))          if self.aLayer is not None:
372      end_dispatcher['projection'] = "end_projection"              obj = self.aLayer
373            elif self.aMap is not None:
374                obj = self.aMap
375            else:
376                assert False, "projection tag out of context"
377                pass
378    
379            obj.SetProjection(
380                Projection(self.ProjectionParams, self.ProjectionName))
381    
382      def start_parameter(self, name, qname, attrs):      def start_parameter(self, name, qname, attrs):
383          s = attrs.get((None, 'value'))          s = attrs.get((None, 'value'))
384          s = str(s) # we can't handle unicode in proj          s = str(s) # we can't handle unicode in proj
385          self.ProjectionParams.append(s)          self.ProjectionParams.append(s)
     start_dispatcher['parameter'] = "start_parameter"  
386    
387      def start_layer(self, name, qname, attrs, layer_class = Layer):      def start_layer(self, name, qname, attrs, layer_class = Layer):
388          """Start a layer          """Start a layer
# Line 138  class ProcessSession(xml.sax.handler.Con Line 391  class ProcessSession(xml.sax.handler.Con
391          attrs which may be a dictionary as well as the normal SAX attrs          attrs which may be a dictionary as well as the normal SAX attrs
392          object and bind it to self.aLayer.          object and bind it to self.aLayer.
393          """          """
394          title = attrs.get((None, 'title'), "")          title = self.encode(attrs.get((None, 'title'), ""))
395          filename = attrs.get((None, 'filename'), "")          filename = attrs.get((None, 'filename'), "")
396          filename = os.path.join(self.directory, filename)          filename = os.path.join(self.GetDirectory(), filename)
397            filename = self.encode(filename)
398            visible  = self.encode(attrs.get((None, 'visible'), "true")) != "false"
399          fill = parse_color(attrs.get((None, 'fill'), "None"))          fill = parse_color(attrs.get((None, 'fill'), "None"))
400          stroke = parse_color(attrs.get((None, 'stroke'), "#000000"))          stroke = parse_color(attrs.get((None, 'stroke'), "#000000"))
401          stroke_width = int(attrs.get((None, 'stroke_width'), "1"))          stroke_width = int(attrs.get((None, 'stroke_width'), "1"))
402          self.aLayer = layer_class(title, filename, fill = fill,          if attrs.has_key((None, "shapestore")):
403                                    stroke = stroke, stroke_width = stroke_width)              store = self.idmap[attrs[(None, "shapestore")]]
404      start_dispatcher['layer'] = "start_layer"          else:
405                store = self.theSession.OpenShapefile(filename)
406            self.aLayer = layer_class(title, store,
407                                      fill = fill, stroke = stroke,
408                                      lineWidth = stroke_width,
409                                      visible = visible)
410    
411      def end_layer(self, name, qname):      def end_layer(self, name, qname):
412          self.aMap.AddLayer(self.aLayer)          self.aMap.AddLayer(self.aLayer)
413      end_dispatcher['layer'] = "end_layer"          self.aLayer = None
414    
415        def start_rasterlayer(self, name, qname, attrs, layer_class = RasterLayer):
416            title = self.encode(attrs.get((None, 'title'), ""))
417            filename = attrs.get((None, 'filename'), "")
418            filename = os.path.join(self.GetDirectory(), filename)
419            filename = self.encode(filename)
420            visible  = self.encode(attrs.get((None, 'visible'), "true")) != "false"
421    
422            self.aLayer = layer_class(title, filename, visible = visible)
423    
424        def end_rasterlayer(self, name, qname):
425            self.aMap.AddLayer(self.aLayer)
426            self.aLayer = None
427    
428      def start_classification(self, name, qname, attrs):      def start_classification(self, name, qname, attrs):
429          self.aLayer.classification.setField(attrs.get((None, 'field'), None))          field = attrs.get((None, 'field'), None)
430      start_dispatcher['classification'] = "start_classification"  
431            fieldType = attrs.get((None, 'field_type'), None)
432            dbFieldType = self.aLayer.GetFieldType(field)
433    
434            if fieldType != dbFieldType:
435                raise ValueError(_("xml field type differs from database!"))
436    
437            # setup conversion routines depending on the kind of data
438            # we will be seeing later on
439            if fieldType == FIELDTYPE_STRING:
440                self.conv = str
441            elif fieldType == FIELDTYPE_INT:
442                self.conv = lambda p: int(float(p))
443            elif fieldType == FIELDTYPE_DOUBLE:
444                self.conv = float
445    
446            self.aLayer.SetClassificationColumn(field)
447    
448      def end_classification(self, name, qname):      def end_classification(self, name, qname):
449          pass          pass
     end_dispatcher['classification'] = "end_classification"  
450    
451      def start_clnull(self, name, qname, attrs):      def start_clnull(self, name, qname, attrs):
452          self.cl_data = {}          self.cl_group = ClassGroupDefault()
453      start_dispatcher['clnull'] = "start_clnull"          self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
454            self.cl_prop = ClassGroupProperties()
455    
456      def end_clnull(self, name, qname):      def end_clnull(self, name, qname):
457          self.aLayer.classification.setNull(self.cl_data)          self.cl_group.SetProperties(self.cl_prop)
458          del self.cl_data          self.aLayer.GetClassification().SetDefaultGroup(self.cl_group)
459      end_dispatcher['clnull'] = "end_clnull"          del self.cl_group, self.cl_prop
460    
461      def start_clpoint(self, name, qname, attrs):      def start_clpoint(self, name, qname, attrs):
462          attrib_value = attrs.get((None, 'value'), "0")          attrib_value = attrs.get((None, 'value'), "0")
463    
464          try:          field = self.aLayer.GetClassificationColumn()
465              self.cl_value  = int(attrib_value)          if self.aLayer.GetFieldType(field) == FIELDTYPE_STRING:
466          except:              value = self.encode(attrib_value)
467              self.cl_value  = attrib_value          else:
468                value = self.conv(attrib_value)
469            self.cl_group = ClassGroupSingleton(value)
470            self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
471            self.cl_prop = ClassGroupProperties()
472    
         self.cl_data = {}  
     start_dispatcher['clpoint'] = "start_clpoint"  
473    
474      def end_clpoint(self, name, qname):      def end_clpoint(self, name, qname):
475          self.aLayer.classification.addPoint(self.cl_value, self.cl_data)          self.cl_group.SetProperties(self.cl_prop)
476          del self.cl_value, self.cl_data          self.aLayer.GetClassification().AppendGroup(self.cl_group)
477      end_dispatcher['clpoint'] = "end_clpoint"          del self.cl_group, self.cl_prop
478    
479      def start_clrange(self, name, qname, attrs):      def start_clrange(self, name, qname, attrs):
480    
481            range = attrs.get((None, 'range'), None)
482            # for backward compatibility (min/max are not saved)
483            min   = attrs.get((None, 'min'), None)
484            max   = attrs.get((None, 'max'), None)
485    
486          try:          try:
487              self.cl_low = int(attrs.get((None, 'low'), "0"))              if range is not None:
488              self.cl_high = int(attrs.get((None, 'high'), "0"))                  self.cl_group = ClassGroupRange(Range(range))
489                elif min is not None and max is not None:
490                    self.cl_group = ClassGroupRange((self.conv(min),
491                                                     self.conv(max)))
492                else:
493                    self.cl_group = ClassGroupRange(Range(None))
494    
495          except ValueError:          except ValueError:
496              raise ValueError("Classification range is not a number!")              raise ValueError(_("Classification range is not a number!"))
497    
498            self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
499            self.cl_prop = ClassGroupProperties()
500    
         self.cl_data = {}  
     start_dispatcher['clrange'] = "start_clrange"  
501    
502      def end_clrange(self, name, qname):      def end_clrange(self, name, qname):
503          self.aLayer.classification.addRange(          self.cl_group.SetProperties(self.cl_prop)
504              self.cl_low, self.cl_high, self.cl_data)          self.aLayer.GetClassification().AppendGroup(self.cl_group)
505          del self.cl_low, self.cl_high, self.cl_data          del self.cl_group, self.cl_prop
     end_dispatcher['clrange'] = "end_clrange"  
506    
507      def start_cldata(self, name, qname, attrs):      def start_cldata(self, name, qname, attrs):
508          self.cl_data['stroke'] = parse_color(          self.cl_prop.SetLineColor(
509                                   attrs.get((None, 'stroke'), "None"))              parse_color(attrs.get((None, 'stroke'), "None")))
510          self.cl_data['stroke_width'] = int(          self.cl_prop.SetLineWidth(
511                                   attrs.get((None, 'stroke_width'), "0"))              int(attrs.get((None, 'stroke_width'), "0")))
512          self.cl_data['fill'] = parse_color(          self.cl_prop.SetFill(parse_color(attrs.get((None, 'fill'), "None")))
                                  attrs.get((None, 'fill'), "None"))  
     start_dispatcher['cldata'] = "start_cldata"  
513    
514      def end_cldata(self, name, qname):      def end_cldata(self, name, qname):
515          pass          pass
     end_dispatcher['cldata'] = "end_cldata"  
   
     def start_table(self, name, qname, attrs):  
         print "table title: %s" % attrs.get('title', None)  
     start_dispatcher['table'] = "start_table"  
   
     def end_table(self, name, qname):  
         pass  
     end_dispatcher['table'] = "end_table"  
516    
517      def start_labellayer(self, name, qname, attrs):      def start_labellayer(self, name, qname, attrs):
518          self.aLayer = self.aMap.LabelLayer()          self.aLayer = self.aMap.LabelLayer()
     start_dispatcher['labellayer'] = "start_labellayer"  
519    
520      def start_label(self, name, qname, attrs):      def start_label(self, name, qname, attrs):
521          x = float(attrs[(None, 'x')])          x = float(attrs[(None, 'x')])
522          y = float(attrs[(None, 'y')])          y = float(attrs[(None, 'y')])
523          text = attrs[(None, 'text')]          text = self.encode(attrs[(None, 'text')])
524          halign = attrs[(None, 'halign')]          halign = attrs[(None, 'halign')]
525          valign = attrs[(None, 'valign')]          valign = attrs[(None, 'valign')]
526          self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign)          self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign)
     start_dispatcher['label'] = "start_label"  
527    
528      def characters(self, chars):      def characters(self, chars):
529          pass          pass
530    
531    
532  def load_session(filename):  def load_session(filename, db_connection_callback = None):
533      """Load a Thuban session from the file object file"""      """Load a Thuban session from the file object file
534      dir = os.path.dirname(filename)  
535      file = open(filename)      The db_connection_callback, if given should be a callable object
536      handler = ProcessSession(dir)      that can be called like this:
537           db_connection_callback(params, message)
538      parser = make_parser()  
539      parser.setContentHandler(handler)      where params is a dictionary containing the known connection
540      parser.setErrorHandler(ErrorHandler())      parameters and message is a string with a message why the connection
541      parser.setFeature(xml.sax.handler.feature_namespaces, 1)      failed. db_connection_callback should return a new dictionary with
542      parser.parse(file)      corrected and perhaps additional parameters like a password or None
543        to indicate that the user cancelled.
544        """
545        handler = SessionLoader(db_connection_callback)
546        handler.read(filename)
547    
548      session = handler.theSession      session = handler.theSession
549      # Newly loaded session aren't modified      # Newly loaded session aren't modified

Legend:
Removed from v.365  
changed lines
  Added in v.1664

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26