/[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 1646 by bh, Mon Aug 25 13:43:56 2003 UTC revision 2446 by frank, Mon Dec 13 11:52:34 2004 UTC
# Line 1  Line 1 
1  # Copyright (C) 2001, 2002, 2003 by Intevation GmbH  # Copyright (C) 2001, 2002, 2003, 2004 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]>  # Jonathan Coles <[email protected]>
6    # Frank Koormann <[email protected]>
7  #  #
8  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
9  # Read the file COPYING coming with GRASS for details.  # Read the file COPYING coming with GRASS for details.
# Line 100  class AttrDesc: Line 101  class AttrDesc:
101    
102  class SessionLoader(XMLReader):  class SessionLoader(XMLReader):
103    
104      def __init__(self, db_connection_callback = None):      def __init__(self, db_connection_callback = None,
105                           shapefile_callback = None):
106          """Inititialize the Sax handler."""          """Inititialize the Sax handler."""
107          XMLReader.__init__(self)          XMLReader.__init__(self)
108    
109          self.db_connection_callback = db_connection_callback          self.db_connection_callback = db_connection_callback
110            self.shapefile_callback = shapefile_callback
111          self.theSession = None          self.theSession = None
112          self.aMap = None          self.aMap = None
113          self.aLayer = None          self.aLayer = None
# Line 141  class SessionLoader(XMLReader): Line 143  class SessionLoader(XMLReader):
143    
144          # all dispatchers should be used for the 0.8 and 0.9 namespaces too          # all dispatchers should be used for the 0.8 and 0.9 namespaces too
145          for xmlns in ("http://thuban.intevation.org/dtds/thuban-0.8.dtd",          for xmlns in ("http://thuban.intevation.org/dtds/thuban-0.8.dtd",
146                        "http://thuban.intevation.org/dtds/thuban-0.9-dev.dtd"):                        "http://thuban.intevation.org/dtds/thuban-0.9-dev.dtd",
147                          "http://thuban.intevation.org/dtds/thuban-0.9.dtd",
148                          "http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd",
149                          "http://thuban.intevation.org/dtds/thuban-1.0rc1.dtd",
150                          "http://thuban.intevation.org/dtds/thuban-1.0.0.dtd",
151                          "http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"):
152              for key, value in dispatchers.items():              for key, value in dispatchers.items():
153                  dispatchers[(xmlns, key)] = value                  dispatchers[(xmlns, key)] = value
154    
155          XMLReader.AddDispatchers(self, dispatchers)          XMLReader.AddDispatchers(self, dispatchers)
156    
157        def Destroy(self):
158            """Clear all instance variables to cut cyclic references.
159    
160            The GC would have collected the loader eventually but it can
161            happen that it doesn't run at all until Thuban is closed (2.3
162            but not 2.2 tries a bit harder and forces a collection when the
163            interpreter terminates)
164            """
165            self.__dict__.clear()
166    
167      def start_session(self, name, qname, attrs):      def start_session(self, name, qname, attrs):
168          self.theSession = Session(self.encode(attrs.get((None, 'title'),          self.theSession = Session(self.encode(attrs.get((None, 'title'),
169                                                          None)))                                                          None)))
# Line 174  class SessionLoader(XMLReader): Line 191  class SessionLoader(XMLReader):
191          If the attribute has a default value and it is not present in          If the attribute has a default value and it is not present in
192          attrs, use that default value as the value in the returned dict.          attrs, use that default value as the value in the returned dict.
193    
194          If a conversion is specified, convert the value before putting          The value is converted before putting it into the returned dict.
195          it into the returned dict. The following conversions are          The following conversions are available:
         available:  
196    
197             'filename' -- The attribute is a filename.             'filename' -- The attribute is a filename.
198    
# Line 198  class SessionLoader(XMLReader): Line 214  class SessionLoader(XMLReader):
214    
215             'ascii' -- The attribute is converted to a bytestring with             'ascii' -- The attribute is converted to a bytestring with
216                        ascii encoding.                        ascii encoding.
217    
218               a callable -- The attribute value is passed to the callable
219                             and the return value is used as the converted
220                             value
221    
222            If no conversion is specified for an attribute it is converted
223            with self.encode.
224          """          """
225          normalized = {}          normalized = {}
226    
# Line 228  class SessionLoader(XMLReader): Line 251  class SessionLoader(XMLReader):
251                                                       value))                                                       value))
252              elif d.conversion == "ascii":              elif d.conversion == "ascii":
253                  value = value.encode("ascii")                  value = value.encode("ascii")
254                elif d.conversion:
255                    # Assume it's a callable
256                    value = d.conversion(value)
257              else:              else:
258                  if d.conversion:                 value = self.encode(value)
                     raise ValueError("Unknown attribute conversion %r"  
                                      % d.conversion)  
259    
260              normalized[d.name] = value              normalized[d.name] = value
261          return normalized          return normalized
262    
263        def open_shapefile(self, filename):
264            """Open shapefile, eventually with alternative path."""
265            from_list = 0
266            while 1:
267                try:
268                    store = self.theSession.OpenShapefile(filename)
269                    if from_list:
270                        # The correct? path has been guessed from a list
271                        # Let the user confirm - or select an alternative.
272                        filename, from_list = self.shapefile_callback(
273                                                filename, "check")
274                        if filename is None:
275                            # Selection cancelled
276                            raise LoadCancelled
277                        elif store.FileName() == filename:
278                            # Proposed file has been accepted
279                            break
280                        else:
281                            # the filename has been changed, try the new file
282                            pass
283                    else:
284                        break
285                except IOError:
286                    if self.shapefile_callback is not None:
287                        filename, from_list = self.shapefile_callback(
288                                                filename,
289                                                mode = "search",
290                                                second_try = from_list)
291                        if filename is None:
292                            raise LoadCancelled
293                        print filename
294                    else:
295                        raise
296            return store
297    
298      def start_dbconnection(self, name, qname, attrs):      def start_dbconnection(self, name, qname, attrs):
299          attrs = self.check_attrs(name, attrs,          attrs = self.check_attrs(name, attrs,
300                                   [AttrDesc("id", True),                                   [AttrDesc("id", True),
# Line 279  class SessionLoader(XMLReader): Line 338  class SessionLoader(XMLReader):
338                                    AttrDesc("dbconn", True,                                    AttrDesc("dbconn", True,
339                                             conversion = "idref"),                                             conversion = "idref"),
340                                    AttrDesc("tablename", True,                                    AttrDesc("tablename", True,
341                                               conversion = "ascii"),
342                                      # id_column and geometry_column were
343                                      # newly introduced with thuban-1.1.dtd
344                                      # where they're required.  Since we
345                                      # support the older formats too we
346                                      # have them optional here.
347                                      AttrDesc("id_column", False, "gid",
348                                               conversion = "ascii"),
349                                      AttrDesc("geometry_column", False,
350                                             conversion = "ascii")])                                             conversion = "ascii")])
351          ID = attrs["id"]          # The default value of geometry_column to use when instantiating
352          db = attrs["dbconn"]          # the db shapestore is None which we currently can't easily use
353          tablename = attrs["tablename"]          # in check_attrs
354          self.idmap[ID] = self.theSession.OpenDBShapeStore(db, tablename)          geometry_column = attrs["geometry_column"]
355            if not geometry_column:
356                geometry_column = None
357            dbopen = self.theSession.OpenDBShapeStore
358            self.idmap[attrs["id"]] = dbopen(attrs["dbconn"], attrs["tablename"],
359                                             id_column = attrs["id_column"],
360                                             geometry_column=geometry_column)
361    
362      def start_fileshapesource(self, name, qname, attrs):      def start_fileshapesource(self, name, qname, attrs):
363          attrs = self.check_attrs(name, attrs,          attrs = self.check_attrs(name, attrs,
# Line 296  class SessionLoader(XMLReader): Line 370  class SessionLoader(XMLReader):
370          filetype = attrs["filetype"]          filetype = attrs["filetype"]
371          if filetype != "shapefile":          if filetype != "shapefile":
372              raise LoadError("shapesource filetype %r not supported" % filetype)              raise LoadError("shapesource filetype %r not supported" % filetype)
373          self.idmap[ID] = self.theSession.OpenShapefile(filename)          self.idmap[ID] = self.open_shapefile(filename)
374    
375      def start_derivedshapesource(self, name, qname, attrs):      def start_derivedshapesource(self, name, qname, attrs):
376          attrs = self.check_attrs(name, attrs,          attrs = self.check_attrs(name, attrs,
# Line 363  class SessionLoader(XMLReader): Line 437  class SessionLoader(XMLReader):
437          self.aMap = None          self.aMap = None
438    
439      def start_projection(self, name, qname, attrs):      def start_projection(self, name, qname, attrs):
440          self.ProjectionName = self.encode(attrs.get((None, 'name'), None))          attrs = self.check_attrs(name, attrs,
441          self.ProjectionParams = [ ]                                   [AttrDesc("name", conversion=self.encode),
442                                      AttrDesc("epsg", default=None,
443                                               conversion=self.encode)])
444            self.projection_name = attrs["name"]
445            self.projection_epsg = attrs["epsg"]
446            self.projection_params = [ ]
447    
448      def end_projection(self, name, qname):      def end_projection(self, name, qname):
449          if self.aLayer is not None:          if self.aLayer is not None:
# Line 375  class SessionLoader(XMLReader): Line 454  class SessionLoader(XMLReader):
454              assert False, "projection tag out of context"              assert False, "projection tag out of context"
455              pass              pass
456    
457          obj.SetProjection(          obj.SetProjection(Projection(self.projection_params,
458              Projection(self.ProjectionParams, self.ProjectionName))                                       self.projection_name,
459                                         epsg = self.projection_epsg))
460    
461      def start_parameter(self, name, qname, attrs):      def start_parameter(self, name, qname, attrs):
462          s = attrs.get((None, 'value'))          s = attrs.get((None, 'value'))
463          s = str(s) # we can't handle unicode in proj          s = str(s) # we can't handle unicode in proj
464          self.ProjectionParams.append(s)          self.projection_params.append(s)
465    
466      def start_layer(self, name, qname, attrs, layer_class = Layer):      def start_layer(self, name, qname, attrs, layer_class = Layer):
467          """Start a layer          """Start a layer
# Line 401  class SessionLoader(XMLReader): Line 481  class SessionLoader(XMLReader):
481          if attrs.has_key((None, "shapestore")):          if attrs.has_key((None, "shapestore")):
482              store = self.idmap[attrs[(None, "shapestore")]]              store = self.idmap[attrs[(None, "shapestore")]]
483          else:          else:
484              store = self.theSession.OpenShapefile(filename)              store = self.open_shapefile(filename)
485    
486          self.aLayer = layer_class(title, store,          self.aLayer = layer_class(title, store,
487                                    fill = fill, stroke = stroke,                                    fill = fill, stroke = stroke,
488                                    lineWidth = stroke_width,                                    lineWidth = stroke_width,
# Line 425  class SessionLoader(XMLReader): Line 506  class SessionLoader(XMLReader):
506          self.aLayer = None          self.aLayer = None
507    
508      def start_classification(self, name, qname, attrs):      def start_classification(self, name, qname, attrs):
509          field = attrs.get((None, 'field'), None)          attrs = self.check_attrs(name, attrs,
510                                     [AttrDesc("field", True),
511                                      AttrDesc("field_type", True)])
512            field = attrs["field"]
513            fieldType = attrs["field_type"]
514    
         fieldType = attrs.get((None, 'field_type'), None)  
515          dbFieldType = self.aLayer.GetFieldType(field)          dbFieldType = self.aLayer.GetFieldType(field)
516    
517          if fieldType != dbFieldType:          if fieldType != dbFieldType:
# Line 508  class SessionLoader(XMLReader): Line 592  class SessionLoader(XMLReader):
592              parse_color(attrs.get((None, 'stroke'), "None")))              parse_color(attrs.get((None, 'stroke'), "None")))
593          self.cl_prop.SetLineWidth(          self.cl_prop.SetLineWidth(
594              int(attrs.get((None, 'stroke_width'), "0")))              int(attrs.get((None, 'stroke_width'), "0")))
595            self.cl_prop.SetSize(int(attrs.get((None, 'size'), "5")))
596          self.cl_prop.SetFill(parse_color(attrs.get((None, 'fill'), "None")))          self.cl_prop.SetFill(parse_color(attrs.get((None, 'fill'), "None")))
597    
598      def end_cldata(self, name, qname):      def end_cldata(self, name, qname):
# Line 517  class SessionLoader(XMLReader): Line 602  class SessionLoader(XMLReader):
602          self.aLayer = self.aMap.LabelLayer()          self.aLayer = self.aMap.LabelLayer()
603    
604      def start_label(self, name, qname, attrs):      def start_label(self, name, qname, attrs):
605          x = float(attrs[(None, 'x')])          attrs = self.check_attrs(name, attrs,
606          y = float(attrs[(None, 'y')])                                   [AttrDesc("x", True, conversion = float),
607          text = self.encode(attrs[(None, 'text')])                                    AttrDesc("y", True, conversion = float),
608          halign = attrs[(None, 'halign')]                                    AttrDesc("text", True),
609          valign = attrs[(None, 'valign')]                                    AttrDesc("halign", True,
610                                               conversion = "ascii"),
611                                      AttrDesc("valign", True,
612                                               conversion = "ascii")])
613            x = attrs['x']
614            y = attrs['y']
615            text = attrs['text']
616            halign = attrs['halign']
617            valign = attrs['valign']
618            if halign not in ("left", "center", "right"):
619                raise LoadError("Unsupported halign value %r" % halign)
620            if valign not in ("top", "center", "bottom"):
621                raise LoadError("Unsupported valign value %r" % valign)
622          self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign)          self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign)
623    
624      def characters(self, chars):      def characters(self, chars):
625          pass          pass
626    
627    
628  def load_session(filename, db_connection_callback = None):  def load_session(filename, db_connection_callback = None,
629                               shapefile_callback = None):
630      """Load a Thuban session from the file object file      """Load a Thuban session from the file object file
631    
632      The db_connection_callback, if given should be a callable object      The db_connection_callback, if given should be a callable object
# Line 541  def load_session(filename, db_connection Line 639  def load_session(filename, db_connection
639      corrected and perhaps additional parameters like a password or None      corrected and perhaps additional parameters like a password or None
640      to indicate that the user cancelled.      to indicate that the user cancelled.
641      """      """
642      handler = SessionLoader(db_connection_callback)      handler = SessionLoader(db_connection_callback, shapefile_callback)
643      handler.read(filename)      handler.read(filename)
644    
645      session = handler.theSession      session = handler.theSession
646      # Newly loaded session aren't modified      # Newly loaded session aren't modified
647      session.UnsetModified()      session.UnsetModified()
648    
649        handler.Destroy()
650    
651      return session      return session
652    

Legend:
Removed from v.1646  
changed lines
  Added in v.2446

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26