/[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 706 by jonathan, Wed Apr 23 08:44:21 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]>
# Line 13  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, SAXNotRecognizedException  from xml.sax import make_parser, ErrorHandler, SAXNotRecognizedException
21    
22  from Thuban import _  from Thuban import _
 from Thuban.common import *  
23    
24  from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \  from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
25       FIELDTYPE_STRING       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.range import Range
34  from Thuban.Model.classification import Classification, \  from Thuban.Model.classification import Classification, \
35      ClassGroupDefault, ClassGroupSingleton, ClassGroupRange, ClassGroupMap, \      ClassGroupDefault, ClassGroupSingleton, ClassGroupRange, ClassGroupMap, \
36      ClassGroupProperties      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 43  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 = Color.Transparent          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 57  def parse_color(color): Line 79  def parse_color(color):
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 XMLReader(xml.sax.handler.ContentHandler):      def __init__(self, name, required = False, default = "",
85                     conversion = None):
86      # Dictionary mapping element names (or (URI, element name) pairs for          if not isinstance(name, tuple):
87      # documents using namespaces) to method names. The methods should              fullname = (None, name)
     # 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):  
         self.chars = ''  
         self.__parser = None  
         self.__directory = ""  
         self.__dispatchers = {}  
   
     def read(self, file_or_filename):  
   
         if hasattr(file_or_filename, "write"):  
             # it's a file object  
             self.__directory = ""  
             self.__file = file_or_filename  
88          else:          else:
89              filename = file_or_filename              fullname = name
90              self.__directory = os.path.dirname(filename)              name = name[1]
91              self.__file = open(filename)          self.name = name
92            self.fullname = fullname
93          if self.__parser is None:          self.required = required
94              self.__parser = make_parser()          self.default = default
95              self.__parser.setContentHandler(self)          self.conversion = conversion
             self.__parser.setErrorHandler(ErrorHandler())  
             self.__parser.setFeature(xml.sax.handler.feature_namespaces, 1)  
   
             #  
             # Well, this isn't pretty, but it appears that if you  
             # use Python 2.2 without the site-package _xmlplus then  
             # the following will fail, and without them it will work.  
             # However, if you do have the site-package and you don't  
             # call these functions, the reader raises an exception  
             #  
             # The reason we set these to 0 in the first place is  
             # because there is an unresolved issue with external  
             # entities causing an exception in the reader  
             #  
             try:  
                 self.__parser.setFeature(xml.sax.handler.feature_validation,0)  
                 self.__parser.setFeature(xml.sax.handler.feature_external_ges,0)  
                 self.__parser.setFeature(xml.sax.handler.feature_external_pes,0)  
             except SAXNotRecognizedException:  
                 pass  
   
         self.__parser.parse(self.__file)  
   
         self.close()  
   
     def close(self):  
         self.__file.close()  
           
     def GetFileName(self):  
         if hasattr(self.__file, "name"):  
             return self.__file.name  
96    
97          return ""          # set by the SessionLoader's check_attrs method
98            self.value = None
99    
     def GetDirectory(self):  
         return self.__directory  
   
   
     def AddDispatchers(self, dict):  
         self.__dispatchers.update(dict)  
   
         #for key, (start, end) in dict.iteritems():  
             #if start is not None: self.start_dispatcher[key] = start  
             #if end   is not None: self.end_dispatcher[key]   = end  
   
     def startElementNS(self, name, qname, attrs):  
         """Call the method given for name in self.start_dispatcher  
         """  
         if name[0] is None:  
             method_name = self.__dispatchers.get(name[1])  
             #method_name = self.start_dispatcher.get(name[1])  
         else:  
             # Dispatch with namespace  
             method_name = self.__dispatchers.get(name)  
         if method_name is not None \  
             and method_name[0] is not None:  
             getattr(self, method_name[0])(name, qname, attrs)  
   
     def endElementNS(self, name, qname):  
         """Call the method given for name in self.end_dispatcher  
         """  
         if name[0] is None:  
             method_name = self.__dispatchers.get(name[1])  
             #method_name = self.end_dispatcher.get(name[1])  
         else:  
             # Dispatch with namespace  
             method_name = self.__dispatchers.get(name)  
         if method_name is not None \  
             and method_name[1] is not None:  
             getattr(self, method_name[1])(name, qname)  
100    
101  class SessionLoader(XMLReader):  class SessionLoader(XMLReader):
102    
103      def __init__(self):      def __init__(self, db_connection_callback = None):
104          """Inititialize the Sax handler."""          """Inititialize the Sax handler."""
105          XMLReader.__init__(self)          XMLReader.__init__(self)
106    
107            self.db_connection_callback = db_connection_callback
108    
109          self.theSession = None          self.theSession = None
110          self.aMap = None          self.aMap = None
111          self.aLayer = None          self.aLayer = None
112    
113          XMLReader.AddDispatchers(self,          # Map ids used in the thuban file to the corresponding objects
114              {'session'       : ("start_session",        "end_session"),          # in the session
115               'map'           : ("start_map",            "end_map"),          self.idmap = {}
116               'projection'    : ("start_projection",     "end_projection"),  
117               'parameter'     : ("start_parameter",      None),          dispatchers = {
118               'layer'         : ("start_layer",          "end_layer"),              'session'       : ("start_session",        "end_session"),
119               'classification': ("start_classification", "end_classification"),  
120               'clnull'        : ("start_clnull",         "end_clnull"),              'dbconnection': ("start_dbconnection", None),
121               'clpoint'       : ("start_clpoint",        "end_clpoint"),  
122               'clrange'       : ("start_clrange",        "end_clrange"),              'dbshapesource': ("start_dbshapesource", None),
123               'cldata'        : ("start_cldata",         "end_cldata"),              'fileshapesource': ("start_fileshapesource", None),
124               'table'         : ("start_table",          "end_table"),              'derivedshapesource': ("start_derivedshapesource", None),
125               'labellayer'    : ("start_labellayer",     None),              'filetable': ("start_filetable", None),
126               'label'         : ("start_label",          None)})              '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            XMLReader.AddDispatchers(self, dispatchers)
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                                                            None)))
154    
155      def end_session(self, name, qname):      def end_session(self, name, qname):
156          pass          pass
157    
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)))
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            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 = [ ]
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                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'))
# Line 221  class SessionLoader(XMLReader): Line 391  class SessionLoader(XMLReader):
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.GetDirectory(), 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, lineWidth = stroke_width)              store = self.idmap[attrs[(None, "shapestore")]]
404            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            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          field = attrs.get((None, 'field'), None)          field = attrs.get((None, 'field'), None)
# Line 251  class SessionLoader(XMLReader): Line 443  class SessionLoader(XMLReader):
443          elif fieldType == FIELDTYPE_DOUBLE:          elif fieldType == FIELDTYPE_DOUBLE:
444              self.conv = float              self.conv = float
445    
446          self.aLayer.GetClassification().SetField(field)          self.aLayer.SetClassificationColumn(field)
   
447    
448      def end_classification(self, name, qname):      def end_classification(self, name, qname):
449          pass          pass
450    
451      def start_clnull(self, name, qname, attrs):      def start_clnull(self, name, qname, attrs):
452          self.cl_group = ClassGroupDefault()          self.cl_group = ClassGroupDefault()
453          self.cl_group.SetLabel(attrs.get((None, 'label'), ""))          self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
454          self.cl_prop = ClassGroupProperties()          self.cl_prop = ClassGroupProperties()
455    
456      def end_clnull(self, name, qname):      def end_clnull(self, name, qname):
# Line 270  class SessionLoader(XMLReader): Line 461  class SessionLoader(XMLReader):
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              #value  = Str2Num(attrib_value)          if self.aLayer.GetFieldType(field) == FIELDTYPE_STRING:
466          #except:              value = self.encode(attrib_value)
467              #value  = attrib_value          else:
468                value = self.conv(attrib_value)
         value = self.conv(attrib_value)  
   
469          self.cl_group = ClassGroupSingleton(value)          self.cl_group = ClassGroupSingleton(value)
470          self.cl_group.SetLabel(attrs.get((None, 'label'), ""))          self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
471          self.cl_prop = ClassGroupProperties()          self.cl_prop = ClassGroupProperties()
472    
473    
# Line 289  class SessionLoader(XMLReader): Line 478  class SessionLoader(XMLReader):
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              min = self.conv(attrs.get((None, 'min'), "0"))              if range is not None:
488              max = self.conv(attrs.get((None, 'max'), "0"))                  self.cl_group = ClassGroupRange(Range(range))
489              #min = Str2Num(attrs.get((None, 'min'), "0"))              elif min is not None and max is not None:
490              #max = Str2Num(attrs.get((None, 'max'), "0"))                  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    
         self.cl_group = ClassGroupRange(min, max)  
498          self.cl_group.SetLabel(attrs.get((None, 'label'), ""))          self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
499          self.cl_prop = ClassGroupProperties()          self.cl_prop = ClassGroupProperties()
500    
# Line 317  class SessionLoader(XMLReader): Line 514  class SessionLoader(XMLReader):
514      def end_cldata(self, name, qname):      def end_cldata(self, name, qname):
515          pass          pass
516    
     def start_table(self, name, qname, attrs):  
         #print "table title: %s" % attrs.get('title', None)  
         pass  
   
     def end_table(self, name, qname):  
         pass  
   
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()
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)
# Line 339  class SessionLoader(XMLReader): Line 529  class SessionLoader(XMLReader):
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    
535      handler = SessionLoader()      The db_connection_callback, if given should be a callable object
536        that can be called like this:
537           db_connection_callback(params, message)
538    
539        where params is a dictionary containing the known connection
540        parameters and message is a string with a message why the connection
541        failed. db_connection_callback should return a new dictionary with
542        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)      handler.read(filename)
547    
548      session = handler.theSession      session = handler.theSession

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26