/[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 2446 - (hide annotations)
Mon Dec 13 11:52:34 2004 UTC (20 years, 2 months ago) by frank
Original Path: trunk/thuban/Thuban/Model/load.py
File MIME type: text/x-python
File size: 26937 byte(s)
Alternative Path feature:
	* test/test_load.py (TestAltPath): New, tests for alternative path feature
	in load_session()
	(Shapefile_CallBack): Helper, implements controllable callback.

	* Thuban/UI/application.py (ThubanApplication.OnInit):
	Added "alt_path" to self.path
	(ThubanApplication.OpenSession): Added shapefile_callback as second
	callback similar to db_connection_callback.
	(ThubanApplication.run_alt_path_dialog): New, implementaion of
	shapefile_callback. In addition to raising the dialog the control of
	self.path('alt_path') is implemented here.

	* Thuban/Model/load.py (SessionLoader.__init__): Added shapefile_callback.
	(SessionLoader.open_shapefile): Open shapefile, eventually with
	alternative path. This wrapps the "theSession.OpenShapefile(filename)"
	formerly used in start_fileshapesource()/start_layer().
	(SessionLoader.start_fileshapesource): Call open_shapefile().
	(SessionLoader.start_layer): Call open_shapefile().
	(load_session): Added shapefile_callback.

	* Thuban/UI/altpathdialog.py: New, implements dialogs for alternative path
	feature (search / check).

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     """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 bh 1646 def start_dbconnection(self, name, qname, attrs):
299     attrs = self.check_attrs(name, attrs,
300     [AttrDesc("id", True),
301     AttrDesc("dbtype", True),
302     AttrDesc("host", False, ""),
303     AttrDesc("port", False, ""),
304     AttrDesc("user", False, ""),
305     AttrDesc("dbname", True)])
306     ID = attrs["id"]
307     dbtype = attrs["dbtype"]
308     if dbtype != "postgis":
309     raise LoadError("dbtype %r not supported" % filetype)
310    
311     del attrs["id"]
312     del attrs["dbtype"]
313    
314     # Try to open the connection and if it fails ask the user for
315     # the correct parameters repeatedly.
316     # FIXME: it would be better not to insist on getting a
317     # connection here. We should handle this more like the raster
318     # images where the layers etc still are created but are not
319     # drawn in case Thuban can't use the data for various reasons
320     while 1:
321     try:
322     conn = postgisdb.PostGISConnection(**attrs)
323     break
324     except postgisdb.ConnectionError, val:
325     if self.db_connection_callback is not None:
326     attrs = self.db_connection_callback(attrs, str(val))
327     if attrs is None:
328     raise LoadCancelled
329     else:
330     raise
331    
332     self.idmap[ID] = conn
333     self.theSession.AddDBConnection(conn)
334    
335     def start_dbshapesource(self, name, qname, attrs):
336     attrs = self.check_attrs(name, attrs,
337     [AttrDesc("id", True),
338     AttrDesc("dbconn", True,
339     conversion = "idref"),
340     AttrDesc("tablename", True,
341 bh 2104 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 bh 1646 conversion = "ascii")])
351 bh 2104 # The default value of geometry_column to use when instantiating
352     # the db shapestore is None which we currently can't easily use
353     # in check_attrs
354     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 bh 1646
362 bh 1268 def start_fileshapesource(self, name, qname, attrs):
363     attrs = self.check_attrs(name, attrs,
364     [AttrDesc("id", True),
365     AttrDesc("filename", True,
366     conversion = "filename"),
367     AttrDesc("filetype", True)])
368     ID = attrs["id"]
369     filename = attrs["filename"]
370     filetype = attrs["filetype"]
371     if filetype != "shapefile":
372     raise LoadError("shapesource filetype %r not supported" % filetype)
373 frank 2446 self.idmap[ID] = self.open_shapefile(filename)
374 bh 1268
375     def start_derivedshapesource(self, name, qname, attrs):
376     attrs = self.check_attrs(name, attrs,
377     [AttrDesc("id", True),
378     AttrDesc("shapesource", True,
379     conversion = "shapesource"),
380     AttrDesc("table", True, conversion="table")])
381 bh 1282 store = DerivedShapeStore(attrs["shapesource"], attrs["table"])
382     self.theSession.AddShapeStore(store)
383     self.idmap[attrs["id"]] = store
384 bh 1268
385     def start_filetable(self, name, qname, attrs):
386     attrs = self.check_attrs(name, attrs,
387     [AttrDesc("id", True),
388     AttrDesc("title", True),
389     AttrDesc("filename", True,
390     conversion = "filename"),
391     AttrDesc("filetype")])
392     filetype = attrs["filetype"]
393     if filetype != "DBF":
394     raise LoadError("shapesource filetype %r not supported" % filetype)
395     table = DBFTable(attrs["filename"])
396     table.SetTitle(attrs["title"])
397     self.idmap[attrs["id"]] = self.theSession.AddTable(table)
398    
399     def start_jointable(self, name, qname, attrs):
400     attrs = self.check_attrs(name, attrs,
401     [AttrDesc("id", True),
402     AttrDesc("title", True),
403     AttrDesc("left", True, conversion="table"),
404     AttrDesc("leftcolumn", True),
405     AttrDesc("right", True, conversion="table"),
406 bh 1375 AttrDesc("rightcolumn", True),
407    
408     # jointype is required for file
409     # version 0.9 but this attribute
410     # wasn't in the 0.8 version because of
411     # an oversight so we assume it's
412     # optional since we want to handle
413     # both file format versions here.
414     AttrDesc("jointype", False,
415     default="INNER")])
416    
417     jointype = attrs["jointype"]
418     if jointype == "LEFT OUTER":
419     outer_join = True
420     elif jointype == "INNER":
421     outer_join = False
422     else:
423     raise LoadError("jointype %r not supported" % jointype )
424 bh 1268 table = TransientJoinedTable(self.theSession.TransientDB(),
425     attrs["left"], attrs["leftcolumn"],
426 bh 1375 attrs["right"], attrs["rightcolumn"],
427     outer_join = outer_join)
428 bh 1268 table.SetTitle(attrs["title"])
429     self.idmap[attrs["id"]] = self.theSession.AddTable(table)
430    
431 bh 267 def start_map(self, name, qname, attrs):
432     """Start a map."""
433 frank 1408 self.aMap = Map(self.encode(attrs.get((None, 'title'), None)))
434 bh 267
435     def end_map(self, name, qname):
436     self.theSession.AddMap(self.aMap)
437 jonathan 874 self.aMap = None
438 bh 267
439     def start_projection(self, name, qname, attrs):
440 bh 1844 attrs = self.check_attrs(name, attrs,
441     [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 bh 267
448     def end_projection(self, name, qname):
449 jonathan 874 if self.aLayer is not None:
450     obj = self.aLayer
451     elif self.aMap is not None:
452     obj = self.aMap
453     else:
454     assert False, "projection tag out of context"
455     pass
456    
457 bh 1844 obj.SetProjection(Projection(self.projection_params,
458     self.projection_name,
459     epsg = self.projection_epsg))
460 bh 267
461     def start_parameter(self, name, qname, attrs):
462     s = attrs.get((None, 'value'))
463     s = str(s) # we can't handle unicode in proj
464 bh 1844 self.projection_params.append(s)
465 bh 267
466     def start_layer(self, name, qname, attrs, layer_class = Layer):
467     """Start a layer
468    
469     Instantiate a layer of class layer_class from the attributes in
470     attrs which may be a dictionary as well as the normal SAX attrs
471     object and bind it to self.aLayer.
472     """
473 jonathan 874 title = self.encode(attrs.get((None, 'title'), ""))
474 bh 267 filename = attrs.get((None, 'filename'), "")
475 jonathan 694 filename = os.path.join(self.GetDirectory(), filename)
476 jonathan 930 filename = self.encode(filename)
477     visible = self.encode(attrs.get((None, 'visible'), "true")) != "false"
478 bh 267 fill = parse_color(attrs.get((None, 'fill'), "None"))
479     stroke = parse_color(attrs.get((None, 'stroke'), "#000000"))
480     stroke_width = int(attrs.get((None, 'stroke_width'), "1"))
481 bh 1268 if attrs.has_key((None, "shapestore")):
482     store = self.idmap[attrs[(None, "shapestore")]]
483     else:
484 frank 2446 store = self.open_shapefile(filename)
485    
486 bh 1268 self.aLayer = layer_class(title, store,
487 bh 723 fill = fill, stroke = stroke,
488 jonathan 772 lineWidth = stroke_width,
489 jonathan 930 visible = visible)
490 bh 267
491     def end_layer(self, name, qname):
492     self.aMap.AddLayer(self.aLayer)
493 jonathan 874 self.aLayer = None
494 bh 267
495 jonathan 930 def start_rasterlayer(self, name, qname, attrs, layer_class = RasterLayer):
496     title = self.encode(attrs.get((None, 'title'), ""))
497     filename = attrs.get((None, 'filename'), "")
498     filename = os.path.join(self.GetDirectory(), filename)
499     filename = self.encode(filename)
500     visible = self.encode(attrs.get((None, 'visible'), "true")) != "false"
501    
502     self.aLayer = layer_class(title, filename, visible = visible)
503    
504     def end_rasterlayer(self, name, qname):
505     self.aMap.AddLayer(self.aLayer)
506     self.aLayer = None
507    
508 jonathan 365 def start_classification(self, name, qname, attrs):
509 bh 1970 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 jonathan 465
515     dbFieldType = self.aLayer.GetFieldType(field)
516    
517     if fieldType != dbFieldType:
518     raise ValueError(_("xml field type differs from database!"))
519    
520     # setup conversion routines depending on the kind of data
521     # we will be seeing later on
522     if fieldType == FIELDTYPE_STRING:
523     self.conv = str
524     elif fieldType == FIELDTYPE_INT:
525     self.conv = lambda p: int(float(p))
526     elif fieldType == FIELDTYPE_DOUBLE:
527     self.conv = float
528    
529 bh 1452 self.aLayer.SetClassificationColumn(field)
530 jonathan 465
531 jonathan 365 def end_classification(self, name, qname):
532     pass
533    
534     def start_clnull(self, name, qname, attrs):
535 jonathan 439 self.cl_group = ClassGroupDefault()
536 jonathan 874 self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
537 jonathan 439 self.cl_prop = ClassGroupProperties()
538 jonathan 365
539     def end_clnull(self, name, qname):
540 jonathan 439 self.cl_group.SetProperties(self.cl_prop)
541     self.aLayer.GetClassification().SetDefaultGroup(self.cl_group)
542     del self.cl_group, self.cl_prop
543 jonathan 365
544     def start_clpoint(self, name, qname, attrs):
545     attrib_value = attrs.get((None, 'value'), "0")
546    
547 bh 1452 field = self.aLayer.GetClassificationColumn()
548 jonathan 1428 if self.aLayer.GetFieldType(field) == FIELDTYPE_STRING:
549 bh 1417 value = self.encode(attrib_value)
550     else:
551     value = self.conv(attrib_value)
552 jonathan 439 self.cl_group = ClassGroupSingleton(value)
553 jonathan 874 self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
554 jonathan 439 self.cl_prop = ClassGroupProperties()
555 jonathan 413
556 jonathan 365
557     def end_clpoint(self, name, qname):
558 jonathan 439 self.cl_group.SetProperties(self.cl_prop)
559 jonathan 614 self.aLayer.GetClassification().AppendGroup(self.cl_group)
560 jonathan 439 del self.cl_group, self.cl_prop
561 jonathan 365
562     def start_clrange(self, name, qname, attrs):
563    
564 jonathan 874 range = attrs.get((None, 'range'), None)
565     # for backward compatibility (min/max are not saved)
566     min = attrs.get((None, 'min'), None)
567     max = attrs.get((None, 'max'), None)
568    
569 jonathan 365 try:
570 jonathan 874 if range is not None:
571     self.cl_group = ClassGroupRange(Range(range))
572     elif min is not None and max is not None:
573 jonathan 1354 self.cl_group = ClassGroupRange((self.conv(min),
574     self.conv(max)))
575 jonathan 874 else:
576     self.cl_group = ClassGroupRange(Range(None))
577    
578 jonathan 365 except ValueError:
579 jan 374 raise ValueError(_("Classification range is not a number!"))
580 jonathan 365
581 jonathan 439 self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
582     self.cl_prop = ClassGroupProperties()
583 jonathan 413
584 jonathan 365
585     def end_clrange(self, name, qname):
586 jonathan 439 self.cl_group.SetProperties(self.cl_prop)
587 jonathan 614 self.aLayer.GetClassification().AppendGroup(self.cl_group)
588 jonathan 439 del self.cl_group, self.cl_prop
589 jonathan 365
590     def start_cldata(self, name, qname, attrs):
591 jonathan 465 self.cl_prop.SetLineColor(
592     parse_color(attrs.get((None, 'stroke'), "None")))
593     self.cl_prop.SetLineWidth(
594 jonathan 390 int(attrs.get((None, 'stroke_width'), "0")))
595 jan 2375 self.cl_prop.SetSize(int(attrs.get((None, 'size'), "5")))
596 jonathan 439 self.cl_prop.SetFill(parse_color(attrs.get((None, 'fill'), "None")))
597 jonathan 365
598     def end_cldata(self, name, qname):
599     pass
600    
601 bh 267 def start_labellayer(self, name, qname, attrs):
602     self.aLayer = self.aMap.LabelLayer()
603    
604     def start_label(self, name, qname, attrs):
605 bh 2034 attrs = self.check_attrs(name, attrs,
606     [AttrDesc("x", True, conversion = float),
607     AttrDesc("y", True, conversion = float),
608     AttrDesc("text", True),
609     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 bh 267 self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign)
623    
624     def characters(self, chars):
625     pass
626    
627    
628 frank 2446 def load_session(filename, db_connection_callback = None,
629     shapefile_callback = None):
630 bh 1646 """Load a Thuban session from the file object file
631 jonathan 694
632 bh 1646 The db_connection_callback, if given should be a callable object
633     that can be called like this:
634     db_connection_callback(params, message)
635    
636     where params is a dictionary containing the known connection
637     parameters and message is a string with a message why the connection
638     failed. db_connection_callback should return a new dictionary with
639     corrected and perhaps additional parameters like a password or None
640     to indicate that the user cancelled.
641     """
642 frank 2446 handler = SessionLoader(db_connection_callback, shapefile_callback)
643 jonathan 706 handler.read(filename)
644 jonathan 694
645 bh 6 session = handler.theSession
646     # Newly loaded session aren't modified
647     session.UnsetModified()
648    
649 bh 1930 handler.Destroy()
650    
651 bh 6 return session
652    

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26