1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
|
# Copyright (C) 2003-2005, 2008 by Intevation GmbH
# Authors:
# Jan-Oliver Wagner <jan@intevation.de> (2003, 2004)
#
# This program is free software under the GPL (>=v2)
# Read the file COPYING coming with Thuban for details.
"""
Import a ArcView project file (.apr) and convert it
to Thuban.
"""
__version__ = "$Revision: 2817 $"
# $Source$
# $Id: importAPR.py 2817 2008-01-27 00:01:32Z bernhard $
import os, sys
from types import StringType
import wx
from Thuban.Model.extension import Extension
from Thuban.Model.base import TitledObject, Modifiable
from Thuban.UI import internal_from_wxstring
from Thuban.UI.command import registry, Command
from Thuban.UI.mainwindow import main_menu
from Thuban import _
from Thuban.Model.layer import Layer
from Thuban.Model.classification import ClassGroupRange, ClassGroupSingleton
from odb import ODBBaseObject
from apr import APR_LClass, APR_TClr, APR_BLnSym, APR_BMkSym, APR_BShSym
class ODBExtension(Extension):
def TreeInfo(self):
return (_("Extension: %s") % self.title,
[ object.TreeInfo() for object in self.objects ])
class APR_FTheme(ODBBaseObject):
_obj_refs = [ 'Source', 'Legend' ]
class APR_Legend(ODBBaseObject):
"""Legend object.
There could one or more Class objects. Each class corresponds to a
Child in the Symbols.
"""
_obj_refs = [ 'FieldNames', 'Symbols', 'Class', 'NullSym',
'NullValues', 'StatValues' ]
class APR_VShSym(ODBBaseObject):
"""Pattern Object(Symbol).
"""
_obj_refs = [ 'Color', 'OutlineColor', 'BgColor' ]
_values = [ 'Outline', 'Outlinewidth', 'Angle', 'YSeparation',
'PenSize' ]
class APR_Project(ODBBaseObject):
_obj_refs = [ 'Doc' ]
class APR_ShpSrc(ODBBaseObject):
_obj_refs = [ 'Name' ]
class APR_SrcName(ODBBaseObject):
_obj_refs = [ 'FileName' ]
class APR_SymList(ODBBaseObject):
_obj_refs = [ 'Child' ]
class APR_View(ODBBaseObject):
_obj_refs = [ 'Theme', 'ITheme' ]
class ODB(TitledObject, Modifiable):
def __init__(self):
TitledObject.__init__(self, 'ODB Object')
self._objects = {}
self._version = None
self._filename = None
self.name = None # required for Thuban.model.extension.Extension
def SetFileName(self, fname):
self._filename = fname
self.name = fname
def AddObject(self, object):
self._objects[object.number] = object
def GetObjects(self):
return self._objects
def GetProject(self):
"""Return the main Root if it is a Project, else None."""
# it is assumed that the first object is the ODB object
if self._objects[1].type != 'ODB':
return None
if self._objects[1].FirstRootClassName != 'Project':
return None
# it is assumed that the second object is the first root
o = self._objects[2]
if o.type != 'Project':
return None
return o
def TreeInfo(self):
items = []
items.append(_('Format version: %s') % self._version)
p = self.GetProject()
items.append(_('Project Name: %s') % p.Name)
for doc in p.Get('Doc'):
items.append(doc.TreeInfo())
return [_("ODB File '%s'" % self._filename), items]
def parse_apr(fname):
"""Load a ArcView project file.
fname -- Filename of the .apr file
Return: the ODB class object.
"""
odb = ODB()
odb.SetFileName(fname)
apr = open(fname, 'r').readlines()
# get the version from the first line (eg. from "/3.1")
odb._version = apr.pop(0)[1:]
i = 0
in_object = False
for line in apr:
i += 1
if line[0] == '(':
line = line[1:]
type, number = line.split('.')
number = int(number)
class_name = 'APR_' + type
try:
clazz = eval(class_name)
object = clazz(odb, type, number)
except:
object = ODBBaseObject(odb, type, number)
in_object = True
continue
if line[0] == ')':
in_object = False
odb.AddObject(object)
if in_object:
line = line.strip()
if len(line) == 0: continue
try:
property, value = line.split(':', 1)
property = property.strip()
value = value.strip()
except:
print "Error in line %d:" % i, line
continue
if value[0] == '"':
value = value[1:-1]
setattr(object, property, value)
return odb
def import_apr_dialog(context):
"""Request filename from user and run importing of apr file.
context -- The Thuban context.
"""
dlg = wx.FileDialog(context.mainwindow,
_("Select APR file"), ".", "",
_("ArcView Project Files (*.apr)|*.apr|") +
_("All Files (*.*)|*.*"),
wx.OPEN|wx.OVERWRITE_PROMPT)
if dlg.ShowModal() == wx.ID_OK:
filename = internal_from_wxstring(dlg.GetPath())
dlg.Destroy()
else:
return
odb = parse_apr(filename)
if odb is None:
context.mainwindow.RunMessageBox(_("Import APR"), _("Loading failed"))
return
else:
context.mainwindow.RunMessageBox(_("Import APR"),
_("%d objects loaded" %
len(odb.GetObjects().keys())))
# find the views of the APR file
views = {}
p = odb.GetProject()
for doc in p.Get('Doc'):
if doc.type != 'View':
continue
views[doc.Name] = doc
# it is possible that a APR file has no view at all
if len(views) == 0:
context.mainwindow.RunMessageBox(_("Import APR"),
_("No view found in APR file"))
return
# let the user select one of the views
if len(views) > 1:
titles = views.keys()
dlg = wx.SingleChoiceDialog(context.mainwindow,
_('Pick a View to import:'),
_('Import APR'), titles,
style = wx.DEFAULT_DIALOG_STYLE |
wx.RESIZE_BORDER)
if dlg.ShowModal() == wx.ID_OK:
view = views[views.keys()[dlg.GetSelection()]]
else:
return
else:
view = views[views.keys()[0]]
# load the themes of the View as layers into Thuban
count_theme = 0
count_theme_fail = 0
for theme in view.Get('Theme'):
if theme.type != 'FTheme':
continue
count_theme += 1
filename = theme.Get('Source').Get('Name').Get('FileName').Path
try:
store = context.application.Session().OpenShapefile(filename)
except IOError:
# the layer couldn't be opened
context.mainwindow.RunMessageBox(_('Add Layer'),
_("Can't open the file '%s'.") % filename)
count_theme_fail += 1
else:
title = theme.Name
apr_legend = theme.Get('Legend')
map = context.mainwindow.canvas.Map()
# create layer
layer = Layer(title, store)
# set the field for classification (if there is one in the apr)
if hasattr(apr_legend, 'FieldNames'):
apr_fieldname = apr_legend.Get('FieldNames').S
# unfortunately, the APR file does not store the actual
# Name of the column, but always makes the first character
# a capital letter, the rest lower case.
# Therefore, we have to search through the table of the
# layer to find out the correct spelling.
table_columns = layer.ShapeStore().Table().Columns()
for column in table_columns:
if apr_fieldname.lower() == column.name.lower():
layer.SetClassificationColumn(column.name)
break
clazz = layer.GetClassification()
apr_classes = apr_legend.Get('Class')
if not isinstance(apr_classes, list):
apr_classes = [ apr_classes ]
apr_symbols = apr_legend.Get('Symbols').Get('Child')
if not isinstance(apr_symbols, list):
apr_symbols = [ apr_symbols ]
i = -1
for symbol in apr_symbols:
i += 1
if hasattr(apr_classes[i], 'IsNoData'):
group = clazz.GetDefaultGroup()
group.SetLabel(apr_classes[i].Label)
continue
# create a new group property from the symbol
prop = symbol.GetThubanProp()
# build range
range = apr_classes[i].GetThubanRange()
if isinstance(range, StringType):
new_group = ClassGroupSingleton(value = range,
props = prop,
label = apr_classes[i].GetLabel())
else:
new_group = ClassGroupRange(_range = range,
props = prop,
label = apr_classes[i].GetLabel())
clazz.AppendGroup(new_group)
map.AddLayer(layer)
map.SetTitle(view.Name)
# fit the new map to the window
context.mainwindow.canvas.FitMapToWindow()
context.mainwindow.RunMessageBox(_('Import APR'),
_('Imported %d out of %d themes of view "%s" ...') % \
(count_theme - count_theme_fail, count_theme, view.Name))
# import_apr as an extension to Thuban
if context.session.HasExtensions():
for ext in context.session.Extensions():
if ext.Title() == apr_import_extension.Title():
ext.AddObject(odb)
return
# no extension found, so lets make a new
context.session.AddExtension(apr_import_extension)
apr_import_extension.AddObject(odb)
if __name__ == "__main__": # import_apr executed as a command line tool
if len(sys.argv) == 2:
odb = parse_apr(sys.argv[1])
print "%d objects loaded" % len(odb.GetObjects().keys())
def print_structured_list(lst, indent = ''):
for item in lst:
if isinstance(item, StringType):
print indent + item
elif isinstance(item, list):
print_structured_list(item, indent + ' ')
print_structured_list(odb.TreeInfo())
sys.exit(0)
else:
print 'usage: %s apr-file' % sys.argv[0]
sys.exit(1)
apr_import_extension = ODBExtension('APR Import')
# register the new command
registry.Add(Command('import-apr', _("(experimental) ")+_('Import apr-file...'), import_apr_dialog,
helptext = _('Import a ArcView project file')))
# find the extension menu (create it anew if not found)
extensions_menu = main_menu.FindOrInsertMenu('extensions',
_('E&xtensions'))
# finally add the new entry to the menu
extensions_menu.InsertItem('import-apr')
|