File: importAPR.py

package info (click to toggle)
thuban 1.2.2-2
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 7,596 kB
  • ctags: 5,301
  • sloc: python: 30,411; ansic: 6,181; xml: 4,127; cpp: 1,595; makefile: 166; sh: 101
file content (339 lines) | stat: -rw-r--r-- 11,341 bytes parent folder | download | duplicates (5)
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')