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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2551 - (hide annotations)
Thu Jan 27 14:19:41 2005 UTC (20 years, 1 month ago) by jonathan
Original Path: trunk/thuban/Thuban/Model/load.py
File MIME type: text/x-python
File size: 27521 byte(s)
Add a new dialog box for raster layers. The dialog box allows
the user to toggle a mask that is generated by ProjectRasterFile
and is used to only draw the real parts of the projected image.

1 bh 2104 # Copyright (C) 2001, 2002, 2003, 2004 by Intevation GmbH
2 bh 6 # Authors:
3     # Jan-Oliver Wagner <[email protected]>
4 bh 267 # Bernhard Herzog <[email protected]>
5 jonathan 413 # Jonathan Coles <[email protected]>
6 frank 2446 # Frank Koormann <[email protected]>
7 bh 6 #
8     # This program is free software under the GPL (>=v2)
9     # Read the file COPYING coming with GRASS for details.
10    
11     """
12     Parser for thuban session files.
13     """
14    
15     __version__ = "$Revision$"
16    
17 bh 723 import string, os
18 bh 267
19     import xml.sax
20     import xml.sax.handler
21 jonathan 526 from xml.sax import make_parser, ErrorHandler, SAXNotRecognizedException
22 bh 267
23 jan 374 from Thuban import _
24 jonathan 413
25 jonathan 473 from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
26     FIELDTYPE_STRING
27    
28 jonathan 1339 from Thuban.Model.color import Color, Transparent
29    
30 bh 6 from Thuban.Model.session import Session
31     from Thuban.Model.map import Map
32 jonathan 930 from Thuban.Model.layer import Layer, RasterLayer
33 bh 6 from Thuban.Model.proj import Projection
34 jonathan 874 from Thuban.Model.range import Range
35 jonathan 413 from Thuban.Model.classification import Classification, \
36 jonathan 439 ClassGroupDefault, ClassGroupSingleton, ClassGroupRange, ClassGroupMap, \
37     ClassGroupProperties
38 bh 1268 from Thuban.Model.data import DerivedShapeStore, ShapefileStore
39     from Thuban.Model.table import DBFTable
40     from Thuban.Model.transientdb import TransientJoinedTable
41 bh 6
42 bh 1646 from Thuban.Model.xmlreader import XMLReader
43     import resource
44    
45     import postgisdb
46    
47 bh 1268 class LoadError(Exception):
48    
49 bh 1646 """Exception raised when the thuban file is corrupted
50 bh 6
51 bh 1646 Not all cases of corrupted thuban files will lead to this exception
52     but those that are found by checks in the loading code itself are.
53     """
54    
55    
56     class LoadCancelled(Exception):
57    
58     """Exception raised to indicate that loading was interrupted by the user"""
59    
60    
61 bh 267 def parse_color(color):
62     """Return the color object for the string color.
63 bh 6
64 bh 267 Color may be either 'None' or of the form '#RRGGBB' in the usual
65     HTML color notation
66 bh 6 """
67     color = string.strip(color)
68     if color == "None":
69 jonathan 1339 result = Transparent
70 bh 6 elif color[0] == '#':
71     if len(color) == 7:
72     r = string.atoi(color[1:3], 16) / 255.0
73     g = string.atoi(color[3:5], 16) / 255.0
74     b = string.atoi(color[5:7], 16) / 255.0
75     result = Color(r, g, b)
76     else:
77 jan 374 raise ValueError(_("Invalid hexadecimal color specification %s")
78 bh 6 % color)
79     else:
80 jan 374 raise ValueError(_("Invalid color specification %s") % color)
81 bh 6 return result
82    
83 bh 1268 class AttrDesc:
84    
85     def __init__(self, name, required = False, default = "",
86     conversion = None):
87     if not isinstance(name, tuple):
88     fullname = (None, name)
89     else:
90     fullname = name
91     name = name[1]
92     self.name = name
93     self.fullname = fullname
94     self.required = required
95     self.default = default
96     self.conversion = conversion
97    
98     # set by the SessionLoader's check_attrs method
99     self.value = None
100    
101    
102 jonathan 706 class SessionLoader(XMLReader):
103 jonathan 694
104 frank 2446 def __init__(self, db_connection_callback = None,
105     shapefile_callback = None):
106 jonathan 694 """Inititialize the Sax handler."""
107 jonathan 706 XMLReader.__init__(self)
108 jonathan 694
109 bh 1646 self.db_connection_callback = db_connection_callback
110 frank 2446 self.shapefile_callback = shapefile_callback
111 jonathan 694 self.theSession = None
112     self.aMap = None
113     self.aLayer = None
114    
115 bh 1268 # Map ids used in the thuban file to the corresponding objects
116     # in the session
117     self.idmap = {}
118 jonathan 706
119 bh 1268 dispatchers = {
120     'session' : ("start_session", "end_session"),
121 bh 1646
122     'dbconnection': ("start_dbconnection", None),
123    
124     'dbshapesource': ("start_dbshapesource", None),
125 bh 1268 'fileshapesource': ("start_fileshapesource", None),
126     'derivedshapesource': ("start_derivedshapesource", None),
127     'filetable': ("start_filetable", None),
128     'jointable': ("start_jointable", None),
129    
130     'map' : ("start_map", "end_map"),
131     'projection' : ("start_projection", "end_projection"),
132     'parameter' : ("start_parameter", None),
133     'layer' : ("start_layer", "end_layer"),
134     'rasterlayer' : ("start_rasterlayer", "end_rasterlayer"),
135     'classification': ("start_classification", "end_classification"),
136     'clnull' : ("start_clnull", "end_clnull"),
137     'clpoint' : ("start_clpoint", "end_clpoint"),
138     'clrange' : ("start_clrange", "end_clrange"),
139     'cldata' : ("start_cldata", "end_cldata"),
140     'table' : ("start_table", "end_table"),
141     'labellayer' : ("start_labellayer", None),
142     'label' : ("start_label", None)}
143    
144 bh 1375 # 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",
146 bh 1664 "http://thuban.intevation.org/dtds/thuban-0.9-dev.dtd",
147 bh 1844 "http://thuban.intevation.org/dtds/thuban-0.9.dtd",
148 bh 2004 "http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd",
149 bh 2036 "http://thuban.intevation.org/dtds/thuban-1.0rc1.dtd",
150 bh 2104 "http://thuban.intevation.org/dtds/thuban-1.0.0.dtd",
151     "http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"):
152 bh 1375 for key, value in dispatchers.items():
153     dispatchers[(xmlns, key)] = value
154 bh 1268
155     XMLReader.AddDispatchers(self, dispatchers)
156    
157 bh 1930 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 bh 267 def start_session(self, name, qname, attrs):
168 bh 1268 self.theSession = Session(self.encode(attrs.get((None, 'title'),
169     None)))
170 bh 6
171 bh 267 def end_session(self, name, qname):
172     pass
173 bh 6
174 bh 1268 def check_attrs(self, element, attrs, descr):
175     """Check and convert some of the attributes of an element
176    
177     Parameters:
178     element -- The element name
179     attrs -- The attrs mapping as passed to the start_* methods
180     descr -- Sequence of attribute descriptions (AttrDesc instances)
181    
182     Return a dictionary containig normalized versions of the
183     attributes described in descr. The keys of that dictionary are
184     the name attributes of the attribute descriptions. The attrs
185     dictionary will not be modified.
186    
187     If the attribute is required, i.e. the 'required' attribute of
188     the descrtiption is true, but it is not in attrs, raise a
189     LoadError.
190    
191     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.
193    
194 bh 1970 The value is converted before putting it into the returned dict.
195     The following conversions are available:
196 bh 1268
197     'filename' -- The attribute is a filename.
198    
199     If the filename is a relative name, interpret
200     it relative to the directory containing the
201     .thuban file and make it an absolute name
202    
203     'shapestore' -- The attribute is the ID of a shapestore
204     defined earlier in the .thuban file. Look it
205     up self.idmap
206    
207     'table' -- The attribute is the ID of a table or shapestore
208     defined earlier in the .thuban file. Look it up
209     self.idmap. If it's the ID of a shapestore the
210     value will be the table of the shapestore.
211 bh 1646
212     'idref' -- The attribute is the id of an object defined
213     earlier in the .thuban file. Look it up self.idmap
214    
215     'ascii' -- The attribute is converted to a bytestring with
216     ascii encoding.
217 bh 1844
218     a callable -- The attribute value is passed to the callable
219 bh 1970 and the return value is used as the converted
220 bh 1844 value
221 bh 1970
222     If no conversion is specified for an attribute it is converted
223     with self.encode.
224 bh 1268 """
225     normalized = {}
226    
227     for d in descr:
228     if d.required and not attrs.has_key(d.fullname):
229 bh 1642 raise LoadError("Element %s requires an attribute %r"
230     % (element, d.name))
231 bh 1268 value = attrs.get(d.fullname, d.default)
232    
233 bh 1646 if d.conversion in ("idref", "shapesource"):
234 bh 1268 if value in self.idmap:
235     value = self.idmap[value]
236     else:
237     raise LoadError("Element %s requires an already defined ID"
238     " in attribute %r"
239     % (element, d.name))
240     elif d.conversion == "table":
241     if value in self.idmap:
242     value = self.idmap[value]
243     if isinstance(value, ShapefileStore):
244     value = value.Table()
245     else:
246     raise LoadError("Element %s requires an already defined ID"
247     " in attribute %r"
248     % (element, d.name))
249     elif d.conversion == "filename":
250     value = os.path.abspath(os.path.join(self.GetDirectory(),
251     value))
252 bh 1646 elif d.conversion == "ascii":
253     value = value.encode("ascii")
254 bh 1844 elif d.conversion:
255     # Assume it's a callable
256     value = d.conversion(value)
257 bh 1970 else:
258     value = self.encode(value)
259 bh 1268
260     normalized[d.name] = value
261     return normalized
262    
263 frank 2446 def open_shapefile(self, filename):
264 frank 2449 """Open shapefile, with alternative path handling.
265    
266     If a shapefile cannot be opened and an IOError is raised, check for
267     an alternative. This alternative can be specified interactively by
268     the user or taken from a list of (potential) locations, depending on
269     the callback implementation.
270    
271     The alternative is rechecked. If taken from a list the user
272     has to confirm the alternative.
273     """
274    
275     # Flag if the alternative path was specified interactively / from list.
276 frank 2446 from_list = 0
277     while 1:
278     try:
279     store = self.theSession.OpenShapefile(filename)
280     if from_list:
281 frank 2449 # A valid path has been guessed from a list
282 frank 2446 # Let the user confirm - or select an alternative.
283     filename, from_list = self.shapefile_callback(
284     filename, "check")
285     if filename is None:
286     # Selection cancelled
287     raise LoadCancelled
288     elif store.FileName() == filename:
289     # Proposed file has been accepted
290     break
291     else:
292     # the filename has been changed, try the new file
293     pass
294     else:
295     break
296     except IOError:
297     if self.shapefile_callback is not None:
298     filename, from_list = self.shapefile_callback(
299     filename,
300     mode = "search",
301     second_try = from_list)
302     if filename is None:
303     raise LoadCancelled
304     else:
305     raise
306     return store
307    
308 bh 1646 def start_dbconnection(self, name, qname, attrs):
309     attrs = self.check_attrs(name, attrs,
310     [AttrDesc("id", True),
311     AttrDesc("dbtype", True),
312     AttrDesc("host", False, ""),
313     AttrDesc("port", False, ""),
314     AttrDesc("user", False, ""),
315     AttrDesc("dbname", True)])
316     ID = attrs["id"]
317     dbtype = attrs["dbtype"]
318     if dbtype != "postgis":
319     raise LoadError("dbtype %r not supported" % filetype)
320    
321     del attrs["id"]
322     del attrs["dbtype"]
323    
324     # Try to open the connection and if it fails ask the user for
325     # the correct parameters repeatedly.
326     # FIXME: it would be better not to insist on getting a
327     # connection here. We should handle this more like the raster
328     # images where the layers etc still are created but are not
329     # drawn in case Thuban can't use the data for various reasons
330     while 1:
331     try:
332     conn = postgisdb.PostGISConnection(**attrs)
333     break
334     except postgisdb.ConnectionError, val:
335     if self.db_connection_callback is not None:
336     attrs = self.db_connection_callback(attrs, str(val))
337     if attrs is None:
338     raise LoadCancelled
339     else:
340     raise
341    
342     self.idmap[ID] = conn
343     self.theSession.AddDBConnection(conn)
344    
345     def start_dbshapesource(self, name, qname, attrs):
346     attrs = self.check_attrs(name, attrs,
347     [AttrDesc("id", True),
348     AttrDesc("dbconn", True,
349     conversion = "idref"),
350     AttrDesc("tablename", True,
351 bh 2104 conversion = "ascii"),
352     # id_column and geometry_column were
353     # newly introduced with thuban-1.1.dtd
354     # where they're required. Since we
355     # support the older formats too we
356     # have them optional here.
357     AttrDesc("id_column", False, "gid",
358     conversion = "ascii"),
359     AttrDesc("geometry_column", False,
360 bh 1646 conversion = "ascii")])
361 bh 2104 # The default value of geometry_column to use when instantiating
362     # the db shapestore is None which we currently can't easily use
363     # in check_attrs
364     geometry_column = attrs["geometry_column"]
365     if not geometry_column:
366     geometry_column = None
367     dbopen = self.theSession.OpenDBShapeStore
368     self.idmap[attrs["id"]] = dbopen(attrs["dbconn"], attrs["tablename"],
369     id_column = attrs["id_column"],
370     geometry_column=geometry_column)
371 bh 1646
372 bh 1268 def start_fileshapesource(self, name, qname, attrs):
373     attrs = self.check_attrs(name, attrs,
374     [AttrDesc("id", True),
375     AttrDesc("filename", True,
376     conversion = "filename"),
377     AttrDesc("filetype", True)])
378     ID = attrs["id"]
379     filename = attrs["filename"]
380     filetype = attrs["filetype"]
381     if filetype != "shapefile":
382     raise LoadError("shapesource filetype %r not supported" % filetype)
383 frank 2446 self.idmap[ID] = self.open_shapefile(filename)
384 bh 1268
385     def start_derivedshapesource(self, name, qname, attrs):
386     attrs = self.check_attrs(name, attrs,
387     [AttrDesc("id", True),
388     AttrDesc("shapesource", True,
389     conversion = "shapesource"),
390     AttrDesc("table", True, conversion="table")])
391 bh 1282 store = DerivedShapeStore(attrs["shapesource"], attrs["table"])
392     self.theSession.AddShapeStore(store)
393     self.idmap[attrs["id"]] = store
394 bh 1268
395     def start_filetable(self, name, qname, attrs):
396     attrs = self.check_attrs(name, attrs,
397     [AttrDesc("id", True),
398     AttrDesc("title", True),
399     AttrDesc("filename", True,
400     conversion = "filename"),
401     AttrDesc("filetype")])
402     filetype = attrs["filetype"]
403     if filetype != "DBF":
404     raise LoadError("shapesource filetype %r not supported" % filetype)
405     table = DBFTable(attrs["filename"])
406     table.SetTitle(attrs["title"])
407     self.idmap[attrs["id"]] = self.theSession.AddTable(table)
408    
409     def start_jointable(self, name, qname, attrs):
410     attrs = self.check_attrs(name, attrs,
411     [AttrDesc("id", True),
412     AttrDesc("title", True),
413     AttrDesc("left", True, conversion="table"),
414     AttrDesc("leftcolumn", True),
415     AttrDesc("right", True, conversion="table"),
416 bh 1375 AttrDesc("rightcolumn", True),
417    
418     # jointype is required for file
419     # version 0.9 but this attribute
420     # wasn't in the 0.8 version because of
421     # an oversight so we assume it's
422     # optional since we want to handle
423     # both file format versions here.
424     AttrDesc("jointype", False,
425     default="INNER")])
426    
427     jointype = attrs["jointype"]
428     if jointype == "LEFT OUTER":
429     outer_join = True
430     elif jointype == "INNER":
431     outer_join = False
432     else:
433     raise LoadError("jointype %r not supported" % jointype )
434 bh 1268 table = TransientJoinedTable(self.theSession.TransientDB(),
435     attrs["left"], attrs["leftcolumn"],
436 bh 1375 attrs["right"], attrs["rightcolumn"],
437     outer_join = outer_join)
438 bh 1268 table.SetTitle(attrs["title"])
439     self.idmap[attrs["id"]] = self.theSession.AddTable(table)
440    
441 bh 267 def start_map(self, name, qname, attrs):
442     """Start a map."""
443 frank 1408 self.aMap = Map(self.encode(attrs.get((None, 'title'), None)))
444 bh 267
445     def end_map(self, name, qname):
446     self.theSession.AddMap(self.aMap)
447 jonathan 874 self.aMap = None
448 bh 267
449     def start_projection(self, name, qname, attrs):
450 bh 1844 attrs = self.check_attrs(name, attrs,
451     [AttrDesc("name", conversion=self.encode),
452     AttrDesc("epsg", default=None,
453     conversion=self.encode)])
454     self.projection_name = attrs["name"]
455     self.projection_epsg = attrs["epsg"]
456     self.projection_params = [ ]
457 bh 267
458     def end_projection(self, name, qname):
459 jonathan 874 if self.aLayer is not None:
460     obj = self.aLayer
461     elif self.aMap is not None:
462     obj = self.aMap
463     else:
464     assert False, "projection tag out of context"
465     pass
466    
467 bh 1844 obj.SetProjection(Projection(self.projection_params,
468     self.projection_name,
469     epsg = self.projection_epsg))
470 bh 267
471     def start_parameter(self, name, qname, attrs):
472     s = attrs.get((None, 'value'))
473     s = str(s) # we can't handle unicode in proj
474 bh 1844 self.projection_params.append(s)
475 bh 267
476     def start_layer(self, name, qname, attrs, layer_class = Layer):
477     """Start a layer
478    
479     Instantiate a layer of class layer_class from the attributes in
480     attrs which may be a dictionary as well as the normal SAX attrs
481     object and bind it to self.aLayer.
482     """
483 jonathan 874 title = self.encode(attrs.get((None, 'title'), ""))
484 bh 267 filename = attrs.get((None, 'filename'), "")
485 jonathan 694 filename = os.path.join(self.GetDirectory(), filename)
486 jonathan 930 filename = self.encode(filename)
487     visible = self.encode(attrs.get((None, 'visible'), "true")) != "false"
488 bh 267 fill = parse_color(attrs.get((None, 'fill'), "None"))
489     stroke = parse_color(attrs.get((None, 'stroke'), "#000000"))
490     stroke_width = int(attrs.get((None, 'stroke_width'), "1"))
491 bh 1268 if attrs.has_key((None, "shapestore")):
492     store = self.idmap[attrs[(None, "shapestore")]]
493     else:
494 frank 2446 store = self.open_shapefile(filename)
495    
496 bh 1268 self.aLayer = layer_class(title, store,
497 bh 723 fill = fill, stroke = stroke,
498 jonathan 772 lineWidth = stroke_width,
499 jonathan 930 visible = visible)
500 bh 267
501     def end_layer(self, name, qname):
502     self.aMap.AddLayer(self.aLayer)
503 jonathan 874 self.aLayer = None
504 bh 267
505 jonathan 930 def start_rasterlayer(self, name, qname, attrs, layer_class = RasterLayer):
506     title = self.encode(attrs.get((None, 'title'), ""))
507     filename = attrs.get((None, 'filename'), "")
508     filename = os.path.join(self.GetDirectory(), filename)
509     filename = self.encode(filename)
510     visible = self.encode(attrs.get((None, 'visible'), "true")) != "false"
511 jonathan 2551 useMask = self.encode(attrs.get((None, 'use_mask'), "false")) != "false"
512 jonathan 930
513     self.aLayer = layer_class(title, filename, visible = visible)
514    
515 jonathan 2551 self.aLayer.SetUseMask(useMask)
516    
517 jonathan 930 def end_rasterlayer(self, name, qname):
518     self.aMap.AddLayer(self.aLayer)
519     self.aLayer = None
520    
521 jonathan 365 def start_classification(self, name, qname, attrs):
522 bh 1970 attrs = self.check_attrs(name, attrs,
523     [AttrDesc("field", True),
524     AttrDesc("field_type", True)])
525     field = attrs["field"]
526     fieldType = attrs["field_type"]
527 jonathan 465
528     dbFieldType = self.aLayer.GetFieldType(field)
529    
530     if fieldType != dbFieldType:
531     raise ValueError(_("xml field type differs from database!"))
532    
533     # setup conversion routines depending on the kind of data
534     # we will be seeing later on
535     if fieldType == FIELDTYPE_STRING:
536     self.conv = str
537     elif fieldType == FIELDTYPE_INT:
538     self.conv = lambda p: int(float(p))
539     elif fieldType == FIELDTYPE_DOUBLE:
540     self.conv = float
541    
542 bh 1452 self.aLayer.SetClassificationColumn(field)
543 jonathan 465
544 jonathan 365 def end_classification(self, name, qname):
545     pass
546    
547     def start_clnull(self, name, qname, attrs):
548 jonathan 439 self.cl_group = ClassGroupDefault()
549 jonathan 874 self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
550 jonathan 439 self.cl_prop = ClassGroupProperties()
551 jonathan 365
552     def end_clnull(self, name, qname):
553 jonathan 439 self.cl_group.SetProperties(self.cl_prop)
554     self.aLayer.GetClassification().SetDefaultGroup(self.cl_group)
555     del self.cl_group, self.cl_prop
556 jonathan 365
557     def start_clpoint(self, name, qname, attrs):
558     attrib_value = attrs.get((None, 'value'), "0")
559    
560 bh 1452 field = self.aLayer.GetClassificationColumn()
561 jonathan 1428 if self.aLayer.GetFieldType(field) == FIELDTYPE_STRING:
562 bh 1417 value = self.encode(attrib_value)
563     else:
564     value = self.conv(attrib_value)
565 jonathan 439 self.cl_group = ClassGroupSingleton(value)
566 jonathan 874 self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
567 jonathan 439 self.cl_prop = ClassGroupProperties()
568 jonathan 413
569 jonathan 365
570     def end_clpoint(self, name, qname):
571 jonathan 439 self.cl_group.SetProperties(self.cl_prop)
572 jonathan 614 self.aLayer.GetClassification().AppendGroup(self.cl_group)
573 jonathan 439 del self.cl_group, self.cl_prop
574 jonathan 365
575     def start_clrange(self, name, qname, attrs):
576    
577 jonathan 874 range = attrs.get((None, 'range'), None)
578     # for backward compatibility (min/max are not saved)
579     min = attrs.get((None, 'min'), None)
580     max = attrs.get((None, 'max'), None)
581    
582 jonathan 365 try:
583 jonathan 874 if range is not None:
584     self.cl_group = ClassGroupRange(Range(range))
585     elif min is not None and max is not None:
586 jonathan 1354 self.cl_group = ClassGroupRange((self.conv(min),
587     self.conv(max)))
588 jonathan 874 else:
589     self.cl_group = ClassGroupRange(Range(None))
590    
591 jonathan 365 except ValueError:
592 jan 374 raise ValueError(_("Classification range is not a number!"))
593 jonathan 365
594 jonathan 439 self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
595     self.cl_prop = ClassGroupProperties()
596 jonathan 413
597 jonathan 365
598     def end_clrange(self, name, qname):
599 jonathan 439 self.cl_group.SetProperties(self.cl_prop)
600 jonathan 614 self.aLayer.GetClassification().AppendGroup(self.cl_group)
601 jonathan 439 del self.cl_group, self.cl_prop
602 jonathan 365
603     def start_cldata(self, name, qname, attrs):
604 jonathan 465 self.cl_prop.SetLineColor(
605     parse_color(attrs.get((None, 'stroke'), "None")))
606     self.cl_prop.SetLineWidth(
607 jonathan 390 int(attrs.get((None, 'stroke_width'), "0")))
608 jan 2375 self.cl_prop.SetSize(int(attrs.get((None, 'size'), "5")))
609 jonathan 439 self.cl_prop.SetFill(parse_color(attrs.get((None, 'fill'), "None")))
610 jonathan 365
611     def end_cldata(self, name, qname):
612     pass
613    
614 bh 267 def start_labellayer(self, name, qname, attrs):
615     self.aLayer = self.aMap.LabelLayer()
616    
617     def start_label(self, name, qname, attrs):
618 bh 2034 attrs = self.check_attrs(name, attrs,
619     [AttrDesc("x", True, conversion = float),
620     AttrDesc("y", True, conversion = float),
621     AttrDesc("text", True),
622     AttrDesc("halign", True,
623     conversion = "ascii"),
624     AttrDesc("valign", True,
625     conversion = "ascii")])
626     x = attrs['x']
627     y = attrs['y']
628     text = attrs['text']
629     halign = attrs['halign']
630     valign = attrs['valign']
631     if halign not in ("left", "center", "right"):
632     raise LoadError("Unsupported halign value %r" % halign)
633     if valign not in ("top", "center", "bottom"):
634     raise LoadError("Unsupported valign value %r" % valign)
635 bh 267 self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign)
636    
637     def characters(self, chars):
638     pass
639    
640    
641 frank 2446 def load_session(filename, db_connection_callback = None,
642     shapefile_callback = None):
643 bh 1646 """Load a Thuban session from the file object file
644 jonathan 694
645 bh 1646 The db_connection_callback, if given should be a callable object
646     that can be called like this:
647     db_connection_callback(params, message)
648    
649     where params is a dictionary containing the known connection
650     parameters and message is a string with a message why the connection
651     failed. db_connection_callback should return a new dictionary with
652     corrected and perhaps additional parameters like a password or None
653     to indicate that the user cancelled.
654     """
655 frank 2446 handler = SessionLoader(db_connection_callback, shapefile_callback)
656 jonathan 706 handler.read(filename)
657 jonathan 694
658 bh 6 session = handler.theSession
659     # Newly loaded session aren't modified
660     session.UnsetModified()
661    
662 bh 1930 handler.Destroy()
663    
664 bh 6 return session
665    

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26