~ubuntu-branches/ubuntu/saucy/merkaartor/saucy

« back to all changes in this revision

Viewing changes to src/Maps/ImportOSM.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Bernd Zeimetz
  • Date: 2009-09-13 00:52:12 UTC
  • mto: (1.2.7 upstream) (0.1.3 upstream) (3.1.7 sid)
  • mto: This revision was merged to the branch mainline in revision 10.
  • Revision ID: james.westby@ubuntu.com-20090913005212-pjecal8zxm07x0fj
ImportĀ upstreamĀ versionĀ 0.14+svnfixes~20090912

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "Maps/ImportOSM.h"
 
2
 
 
3
#include "Command/Command.h"
 
4
#include "Command/DocumentCommands.h"
 
5
#include "Command/FeatureCommands.h"
 
6
#include "Command/RelationCommands.h"
 
7
#include "Command/RoadCommands.h"
 
8
#include "Command/TrackPointCommands.h"
 
9
#include "Maps/DownloadOSM.h"
 
10
#include "Maps/MapDocument.h"
 
11
#include "Maps/MapLayer.h"
 
12
#include "Maps/Relation.h"
 
13
#include "Maps/Road.h"
 
14
#include "Maps/TrackPoint.h"
 
15
#include "Maps/TrackSegment.h"
 
16
 
 
17
#include <QtCore/QBuffer>
 
18
#include <QtCore/QDateTime>
 
19
#include <QtCore/QEventLoop>
 
20
#include <QtCore/QFile>
 
21
#include <QtGui/QMessageBox>
 
22
#include <QtGui/QProgressBar>
 
23
#include <QtGui/QProgressDialog>
 
24
#include <QtXml/QDomDocument>
 
25
#include <QtXml/QXmlAttributes>
 
26
 
 
27
 
 
28
OSMHandler::OSMHandler(MapDocument* aDoc, MapLayer* aLayer, MapLayer* aConflict)
 
29
: theDocument(aDoc), theLayer(aLayer), conflictLayer(aConflict), Current(0)
 
30
{
 
31
}
 
32
 
 
33
void OSMHandler::parseTag(const QXmlAttributes &atts)
 
34
{
 
35
        if (!Current) return;
 
36
 
 
37
        Current->setTag(atts.value("k"),atts.value("v"));
 
38
}
 
39
 
 
40
void parseStandardAttributes(const QXmlAttributes& atts, MapFeature* F)
 
41
{
 
42
        QString ts = atts.value("timestamp"); 
 
43
        QDateTime time = QDateTime::fromString(ts.left(19), Qt::ISODate);
 
44
        QString user = atts.value("user");
 
45
        F->setTime(time);
 
46
        F->setUser(user);
 
47
        QString version = atts.value("version");
 
48
        if (!version.isEmpty())
 
49
                F->setVersionNumber(version.toInt());
 
50
}
 
51
 
 
52
void OSMHandler::parseNode(const QXmlAttributes& atts)
 
53
{
 
54
        double Lat = atts.value("lat").toDouble();
 
55
        double Lon = atts.value("lon").toDouble();
 
56
        QString id = atts.value("id");
 
57
        if (id[0] != '-' && id[0] != '{')
 
58
                id = "node_"+id;
 
59
        TrackPoint* Pt = dynamic_cast<TrackPoint*>(theDocument->getFeature(id));
 
60
        if (Pt)
 
61
        {
 
62
                if (Pt->lastUpdated() == MapFeature::User)
 
63
                {
 
64
                        // conflict
 
65
                        Pt->setLastUpdated(MapFeature::UserResolved);
 
66
                        TrackPoint* userPt = Pt;
 
67
                        Pt = new TrackPoint(Coord(angToInt(Lat),angToInt(Lon)));
 
68
                        Pt->setId("conflict_"+id);
 
69
                        Pt->setLastUpdated(MapFeature::OSMServerConflict);
 
70
                        parseStandardAttributes(atts,Pt);
 
71
                        if (Pt->time() > userPt->time()) {
 
72
                                if (conflictLayer)
 
73
                                        conflictLayer->add(Pt);
 
74
                                NewFeature = true;
 
75
                        } else {
 
76
                                delete Pt;
 
77
                                Pt = userPt;
 
78
                                NewFeature = false;
 
79
                        }
 
80
                }
 
81
                else if (Pt->lastUpdated() != MapFeature::UserResolved)
 
82
                {
 
83
                        Pt->layer()->remove(Pt);
 
84
                        theLayer->add(Pt);
 
85
                        Pt->setPosition(Coord(angToInt(Lat),angToInt(Lon)));
 
86
                        NewFeature = true;
 
87
                        if (Pt->lastUpdated() == MapFeature::NotYetDownloaded)
 
88
                                Pt->setLastUpdated(MapFeature::OSMServer);
 
89
                }
 
90
        }
 
91
        else
 
92
        {
 
93
                Pt = new TrackPoint(Coord(angToInt(Lat),angToInt(Lon)));
 
94
                theLayer->add(Pt);
 
95
                NewFeature = true;
 
96
                Pt->setId(id);
 
97
                Pt->setLastUpdated(MapFeature::OSMServer);
 
98
        }
 
99
        if (NewFeature) {
 
100
                parseStandardAttributes(atts,Pt);
 
101
                Current = Pt;
 
102
        } else
 
103
                Current = NULL;
 
104
}
 
105
 
 
106
void OSMHandler::parseNd(const QXmlAttributes& atts)
 
107
{
 
108
        Road* R = dynamic_cast<Road*>(Current);
 
109
        if (!R) return;
 
110
        TrackPoint *Part = MapFeature::getTrackPointOrCreatePlaceHolder(theDocument, theLayer, atts.value("ref"));
 
111
        if (NewFeature)
 
112
                R->add(Part);
 
113
}
 
114
 
 
115
void OSMHandler::parseWay(const QXmlAttributes& atts)
 
116
{
 
117
        QString id = atts.value("id");
 
118
        if (id[0] != '-' && id[0] != '{')
 
119
                id = "way_"+id;
 
120
        QString ts = atts.value("timestamp"); ts.truncate(19);
 
121
        Road* R = dynamic_cast<Road*>(theDocument->getFeature(id));
 
122
        if (R)
 
123
        {
 
124
                if (R->lastUpdated() == MapFeature::User)
 
125
                {
 
126
                        R->setLastUpdated(MapFeature::UserResolved);
 
127
                        NewFeature = false;
 
128
                        // conflict
 
129
                        Road* userRd = R;
 
130
                        R = new Road();
 
131
                        R->setId("conflict_"+id);
 
132
                        R->setLastUpdated(MapFeature::OSMServerConflict);
 
133
                        parseStandardAttributes(atts,R);
 
134
                        if (R->time() > userRd->time()) {
 
135
                                if (conflictLayer)
 
136
                                        conflictLayer->add(R);
 
137
                                NewFeature = true;
 
138
                        } else {
 
139
                                delete R;
 
140
                                R = userRd;
 
141
                                NewFeature = false;
 
142
                        }
 
143
                }
 
144
                else if (R->lastUpdated() != MapFeature::UserResolved)
 
145
                {
 
146
                        R->layer()->remove(R);
 
147
                        theLayer->add(R);
 
148
                        while (R->size())
 
149
                                R->remove((int)0);
 
150
                        NewFeature = true;
 
151
                        if (R->lastUpdated() == MapFeature::NotYetDownloaded)
 
152
                                R->setLastUpdated(MapFeature::OSMServer);
 
153
                }
 
154
        }
 
155
        else
 
156
        {
 
157
                R = new Road;
 
158
                theLayer->add(R);
 
159
                NewFeature = true;
 
160
                R->setId(id);
 
161
                R->setLastUpdated(MapFeature::OSMServer);
 
162
        }
 
163
        if (NewFeature) {
 
164
                parseStandardAttributes(atts,R);
 
165
                Current = R;
 
166
        } else
 
167
                Current = NULL;
 
168
}
 
169
 
 
170
void OSMHandler::parseMember(const QXmlAttributes& atts)
 
171
{
 
172
        Relation* R = dynamic_cast<Relation*>(Current);
 
173
        if (!R)
 
174
                return;
 
175
        QString Type = atts.value("type");
 
176
        MapFeature* F = 0;
 
177
        if (Type == "node")
 
178
                F = MapFeature::getTrackPointOrCreatePlaceHolder(theDocument, theLayer, atts.value("ref"));
 
179
        else if (Type == "way")
 
180
                F = MapFeature::getWayOrCreatePlaceHolder(theDocument, theLayer, atts.value("ref"));
 
181
        else if (Type == "relation")
 
182
                F = MapFeature::getRelationOrCreatePlaceHolder(theDocument, theLayer, atts.value("ref"));
 
183
 
 
184
        if (F && F != R)
 
185
                R->add(atts.value("role"),F);
 
186
}
 
187
 
 
188
void OSMHandler::parseRelation(const QXmlAttributes& atts)
 
189
{
 
190
        QString id = atts.value("id");
 
191
        if (id[0] != '-' && id[0] != '{')
 
192
                id = "rel_"+id;
 
193
        QString ts = atts.value("timestamp"); ts.truncate(19);
 
194
        Relation* R = dynamic_cast<Relation*>(theDocument->getFeature(id));
 
195
        if (R)
 
196
        {
 
197
                if (R->lastUpdated() == MapFeature::User)
 
198
                {
 
199
                        R->setLastUpdated(MapFeature::UserResolved);
 
200
                        NewFeature = false;
 
201
                        // conflict
 
202
/*                              TrackPoint* Conflict = dynamic_cast<TrackPoint*>(theDocument->get("conflict_node_"+Root.attribute("from")));
 
203
                        if (Conflict) From = Conflict;
 
204
                        Conflict = dynamic_cast<TrackPoint*>(theDocument->get("conflict_node_"+Root.attribute("to")));
 
205
                        if (Conflict) To = Conflict;
 
206
                        Way* W = new Way(From,To);
 
207
                        W->setId("conflict_"+id);
 
208
                        loadSegmentTags(Root,W);
 
209
                        theList->add(new AddFeatureCommand(conflictLayer,W, false));
 
210
                        W->setLastUpdated(MapFeature::OSMServerConflict); */
 
211
                }
 
212
                else if (R->lastUpdated() != MapFeature::UserResolved)
 
213
                {
 
214
                        R->layer()->remove(R);
 
215
                        theLayer->add(R);
 
216
                        while (R->size())
 
217
                                R->remove((int)0);
 
218
                        NewFeature = true;
 
219
                        if (R->lastUpdated() == MapFeature::NotYetDownloaded)
 
220
                                R->setLastUpdated(MapFeature::OSMServer);
 
221
                }
 
222
        }
 
223
        else
 
224
        {
 
225
                R = new Relation;
 
226
                NewFeature = true;
 
227
                R->setId(id);
 
228
                theLayer->add(R);
 
229
                R->setLastUpdated(MapFeature::OSMServer);
 
230
        }
 
231
        if (NewFeature) {
 
232
                parseStandardAttributes(atts,R);
 
233
                Current = R;
 
234
        } else
 
235
                Current = NULL;
 
236
}
 
237
 
 
238
bool OSMHandler::startElement ( const QString &, const QString & /* localName */, const QString & qName, const QXmlAttributes & atts )
 
239
{
 
240
        if (qName == "tag")
 
241
                parseTag(atts);
 
242
        else if (qName == "node")
 
243
                parseNode(atts);
 
244
        else if (qName == "nd")
 
245
                parseNd(atts);
 
246
        else if (qName == "way")
 
247
                parseWay(atts);
 
248
        else if (qName == "member")
 
249
                parseMember(atts);
 
250
        else if (qName == "relation")
 
251
                parseRelation(atts);
 
252
        return true;
 
253
}
 
254
 
 
255
bool OSMHandler::endElement ( const QString &, const QString & /* localName */, const QString & qName )
 
256
{
 
257
        if (qName == "node")
 
258
                Current = 0;
 
259
        return true;
 
260
}
 
261
 
 
262
static bool downloadToResolve(const QList<MapFeature*>& Resolution, QWidget* aParent, MapDocument* theDocument, MapLayer* theLayer, Downloader* theDownloader)
 
263
{
 
264
        IProgressWindow* aProgressWindow = dynamic_cast<IProgressWindow*>(aParent);
 
265
        if (!aProgressWindow)
 
266
                return false;
 
267
 
 
268
        QProgressDialog* dlg = aProgressWindow->getProgressDialog();
 
269
        dlg->setWindowTitle(QApplication::translate("Downloader", "Downloading unresolved..."));
 
270
        QProgressBar* Bar = aProgressWindow->getProgressBar();
 
271
        QLabel* Lbl = aProgressWindow->getProgressLabel();
 
272
 
 
273
        for (int i=0; i<Resolution.size(); i++ )
 
274
        {
 
275
                QString URL = theDownloader->getURLToFetchFull(Resolution[i]);
 
276
                Lbl->setText(QApplication::translate("Downloader","Downloading unresolved %1 of %2").arg(i+1).arg(Resolution.size()));
 
277
                if (theDownloader->go(URL))
 
278
                {
 
279
                        if (theDownloader->resultCode() == 410) {
 
280
                                theLayer->remove(Resolution[i]);
 
281
                                delete Resolution[i];
 
282
                        }
 
283
                        else
 
284
                        {
 
285
                                Lbl->setText(QApplication::translate("Downloader","Parsing unresolved %1 of %2").arg(i+1).arg(Resolution.size()));
 
286
 
 
287
                                QByteArray ba(theDownloader->content());
 
288
                                QBuffer  File(&ba);
 
289
                                File.open(QIODevice::ReadOnly);
 
290
 
 
291
                                OSMHandler theHandler(theDocument,theLayer,NULL);
 
292
 
 
293
                                QXmlSimpleReader xmlReader;
 
294
                                xmlReader.setContentHandler(&theHandler);
 
295
                                QXmlInputSource source;
 
296
                                QByteArray buf(File.read(10240));
 
297
                                source.setData(buf);
 
298
                                xmlReader.parse(&source,true);
 
299
                                while (!File.atEnd())
 
300
                                {
 
301
                                        QByteArray buf(File.read(20480));
 
302
                                        source.setData(buf);
 
303
                                        xmlReader.parseContinue();
 
304
                                        qApp->processEvents();
 
305
                                        if (dlg && dlg->wasCanceled())
 
306
                                                break;
 
307
                                }
 
308
                        }
 
309
                        Resolution[i]->setLastUpdated(MapFeature::OSMServer);
 
310
                }
 
311
                else
 
312
                        return false;
 
313
                Bar->setValue(i);
 
314
        }
 
315
        return true;
 
316
}
 
317
 
 
318
static void recurseDelete (MapFeature* F, QList<MapFeature*>& MustDelete)
 
319
{
 
320
        for (int i=0; i<F->sizeParents(); i++) {
 
321
                recurseDelete(F->getParent(i), MustDelete);
 
322
        }
 
323
        if (!MustDelete.contains(F))
 
324
                MustDelete.push_back(F);
 
325
}
 
326
 
 
327
static bool resolveNotYetDownloaded(QWidget* aParent, MapDocument* theDocument, MapLayer* theLayer, Downloader* theDownloader)
 
328
{
 
329
        // resolving nodes and roads makes no sense since the OSM api guarantees that they will be all downloaded,
 
330
        //  so only resolve for relations if the ResolveRelations pref is set
 
331
        if (theDownloader)
 
332
        {
 
333
                IProgressWindow* aProgressWindow = dynamic_cast<IProgressWindow*>(aParent);
 
334
                if (!aProgressWindow)
 
335
                        return false;
 
336
 
 
337
                QProgressBar* Bar = aProgressWindow->getProgressBar();
 
338
                //QLabel* Lbl = aProgressWindow->getProgressLabel();
 
339
 
 
340
                QList<MapFeature*> MustResolve;
 
341
                MustResolve.clear();
 
342
                for (FeatureIterator it(theDocument); !it.isEnd(); ++it)
 
343
                {
 
344
                        Relation* RR = CAST_RELATION(it.get());
 
345
                        if (RR && RR->notEverythingDownloaded())
 
346
                                MustResolve.push_back(RR);
 
347
                }
 
348
                if (MustResolve.size())
 
349
                {
 
350
                        Bar->setMaximum(MustResolve.size());
 
351
                        Bar->setValue(0);
 
352
                        if (!downloadToResolve(MustResolve,aParent,theDocument,theLayer, theDownloader))
 
353
                                return false;
 
354
                }
 
355
        }
 
356
        return true;
 
357
}
 
358
 
 
359
static bool deleteIncompleteRelations(QWidget* /*aParent*/, MapDocument* /*theDocument*/, MapLayer* theLayer, Downloader* /*theDownloader*/)
 
360
{
 
361
        QList<MapFeature*> MustDelete;
 
362
        for (int i=0; i<theLayer->size(); i++)
 
363
        {
 
364
                if (theLayer->get(i)->notEverythingDownloaded()) {
 
365
                        recurseDelete(theLayer->get(i), MustDelete);
 
366
                }
 
367
        }
 
368
        for (int i=0; i<MustDelete.size(); i++) {
 
369
                MustDelete[i]->layer()->remove(MustDelete[i]);
 
370
                delete MustDelete[i];
 
371
        }
 
372
        return true;
 
373
}
 
374
 
 
375
bool importOSM(QWidget* aParent, QIODevice& File, MapDocument* theDocument, MapLayer* theLayer, Downloader* theDownloader)
 
376
{
 
377
        QDomDocument DomDoc;
 
378
        QString ErrorStr;
 
379
        /* int ErrorLine; */
 
380
        /* int ErrorColumn; */
 
381
 
 
382
        IProgressWindow* aProgressWindow = dynamic_cast<IProgressWindow*>(aParent);
 
383
        if (!aProgressWindow)
 
384
                return false;
 
385
 
 
386
        QProgressDialog* dlg = aProgressWindow->getProgressDialog();
 
387
        if (dlg)
 
388
                dlg->setWindowTitle(QApplication::translate("Downloader", "Parsing..."));
 
389
 
 
390
        QProgressBar* Bar = aProgressWindow->getProgressBar();
 
391
        Bar->setTextVisible(false);
 
392
 
 
393
        QLabel* Lbl = aProgressWindow->getProgressLabel();
 
394
        Lbl->setText(QApplication::translate("Downloader","Parsing XML"));
 
395
 
 
396
        if (dlg)
 
397
                dlg->show();
 
398
 
 
399
        if (theDownloader)
 
400
                theDownloader->setAnimator(dlg,Lbl,Bar,false);
 
401
        MapLayer* conflictLayer = new DrawingMapLayer(QApplication::translate("Downloader","Conflicts from %1").arg(theLayer->name()));
 
402
        theDocument->add(conflictLayer);
 
403
 
 
404
        OSMHandler theHandler(theDocument,theLayer,conflictLayer);
 
405
 
 
406
        QXmlSimpleReader xmlReader;
 
407
        xmlReader.setContentHandler(&theHandler);
 
408
        QXmlInputSource source;
 
409
        QByteArray buf(File.read(10240));
 
410
        source.setData(buf);
 
411
        xmlReader.parse(&source,true);
 
412
        Bar->setMaximum(File.size());
 
413
        Bar->setValue(Bar->value()+buf.size());
 
414
        while (!File.atEnd())
 
415
        {
 
416
                QByteArray buf(File.read(20480));
 
417
                source.setData(buf);
 
418
                xmlReader.parseContinue();
 
419
                Bar->setValue(Bar->value()+buf.size());
 
420
                qApp->processEvents();
 
421
                if (dlg && dlg->wasCanceled())
 
422
                        break;
 
423
        }
 
424
 
 
425
        bool WasCanceled = false;
 
426
        if (dlg)
 
427
                WasCanceled = dlg->wasCanceled();
 
428
        if (!WasCanceled && M_PREFS->getResolveRelations())
 
429
                WasCanceled = !resolveNotYetDownloaded(aParent,theDocument,theLayer,theDownloader);
 
430
        if (!WasCanceled && M_PREFS->getDeleteIncompleteRelations())
 
431
                WasCanceled = !deleteIncompleteRelations(aParent,theDocument,theLayer,theDownloader);
 
432
 
 
433
        if (WasCanceled)
 
434
        {
 
435
                theDocument->remove(conflictLayer);
 
436
                delete conflictLayer;
 
437
                return false;
 
438
        }
 
439
        else
 
440
        {
 
441
                if (!conflictLayer->size()) {
 
442
                        theDocument->remove(conflictLayer);
 
443
                        delete conflictLayer;
 
444
                } else {
 
445
                        QMessageBox::warning(aParent,QApplication::translate("Downloader","Conflicts have been detected"), 
 
446
                                QApplication::translate("Downloader",
 
447
                                "This means that some of the feature you modified"
 
448
                                " since your last download have since been modified by someone else on the server.\n"
 
449
                                "The features have been duplicated as \"conflict_...\" on the \"Conflicts...\" layer.\n"
 
450
                                "Before being able to upload your changes, you will have to manually merge the two versions"
 
451
                                " and remove the one from the \"Conflicts...\" layer."
 
452
                                ));
 
453
                }
 
454
 
 
455
                // Check for empty Roads/Relations
 
456
                QList<MapFeature*> EmptyFeature;
 
457
                for (int i=0; i<theLayer->size(); ++i) {
 
458
                        if (!theLayer->get(i)->size() && !theLayer->get(i)->notEverythingDownloaded() && !CAST_NODE(theLayer->get(i)))
 
459
                                        EmptyFeature.push_back(theLayer->get(i));
 
460
                }
 
461
                if (EmptyFeature.size()) {
 
462
                        if (QMessageBox::warning(aParent,QApplication::translate("Downloader","Empty roads/relations detected"), 
 
463
                                        QApplication::translate("Downloader",
 
464
                                        "Empty roads/relations are probably errors.\n"
 
465
                                        "Do you want to mark them for deletion?"),
 
466
                                        QMessageBox::Ok | QMessageBox::Cancel,
 
467
                                        QMessageBox::Cancel
 
468
                                        ) == QMessageBox::Ok) {
 
469
                                for (int i=0; i<EmptyFeature.size(); i++ ) {
 
470
                                        CommandList* emptyFeatureList = new CommandList();
 
471
                                        emptyFeatureList->setDescription(QApplication::translate("Downloader","Remove empty feature %1").arg(EmptyFeature[i]->description()));
 
472
                                        emptyFeatureList->setFeature(EmptyFeature[i]);
 
473
                                        emptyFeatureList->add(new RemoveFeatureCommand(theDocument, EmptyFeature[i]));
 
474
                                        theDocument->addHistory(emptyFeatureList);
 
475
                                }
 
476
                        }
 
477
                }
 
478
 
 
479
        }
 
480
        return true;
 
481
}
 
482
 
 
483
bool importOSM(QWidget* aParent, const QString& aFilename, MapDocument* theDocument, MapLayer* theLayer)
 
484
{
 
485
        QFile File(aFilename);
 
486
        if (!File.open(QIODevice::ReadOnly))
 
487
                 return false;
 
488
        return importOSM(aParent, File, theDocument, theLayer, 0 );
 
489
}
 
490
 
 
491
bool importOSM(QWidget* aParent, QByteArray& Content, MapDocument* theDocument, MapLayer* theLayer, Downloader* theDownloader)
 
492
{
 
493
        QBuffer File(&Content);
 
494
        File.open(QIODevice::ReadOnly);
 
495
        return importOSM(aParent, File, theDocument, theLayer, theDownloader);
 
496
}
 
497
 
 
498
 
 
499