1
#include "Maps/ImportOSM.h"
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"
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>
28
OSMHandler::OSMHandler(MapDocument* aDoc, MapLayer* aLayer, MapLayer* aConflict)
29
: theDocument(aDoc), theLayer(aLayer), conflictLayer(aConflict), Current(0)
33
void OSMHandler::parseTag(const QXmlAttributes &atts)
37
Current->setTag(atts.value("k"),atts.value("v"));
40
void parseStandardAttributes(const QXmlAttributes& atts, MapFeature* F)
42
QString ts = atts.value("timestamp");
43
QDateTime time = QDateTime::fromString(ts.left(19), Qt::ISODate);
44
QString user = atts.value("user");
47
QString version = atts.value("version");
48
if (!version.isEmpty())
49
F->setVersionNumber(version.toInt());
52
void OSMHandler::parseNode(const QXmlAttributes& atts)
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] != '{')
59
TrackPoint* Pt = dynamic_cast<TrackPoint*>(theDocument->getFeature(id));
62
if (Pt->lastUpdated() == MapFeature::User)
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()) {
73
conflictLayer->add(Pt);
81
else if (Pt->lastUpdated() != MapFeature::UserResolved)
83
Pt->layer()->remove(Pt);
85
Pt->setPosition(Coord(angToInt(Lat),angToInt(Lon)));
87
if (Pt->lastUpdated() == MapFeature::NotYetDownloaded)
88
Pt->setLastUpdated(MapFeature::OSMServer);
93
Pt = new TrackPoint(Coord(angToInt(Lat),angToInt(Lon)));
97
Pt->setLastUpdated(MapFeature::OSMServer);
100
parseStandardAttributes(atts,Pt);
106
void OSMHandler::parseNd(const QXmlAttributes& atts)
108
Road* R = dynamic_cast<Road*>(Current);
110
TrackPoint *Part = MapFeature::getTrackPointOrCreatePlaceHolder(theDocument, theLayer, atts.value("ref"));
115
void OSMHandler::parseWay(const QXmlAttributes& atts)
117
QString id = atts.value("id");
118
if (id[0] != '-' && id[0] != '{')
120
QString ts = atts.value("timestamp"); ts.truncate(19);
121
Road* R = dynamic_cast<Road*>(theDocument->getFeature(id));
124
if (R->lastUpdated() == MapFeature::User)
126
R->setLastUpdated(MapFeature::UserResolved);
131
R->setId("conflict_"+id);
132
R->setLastUpdated(MapFeature::OSMServerConflict);
133
parseStandardAttributes(atts,R);
134
if (R->time() > userRd->time()) {
136
conflictLayer->add(R);
144
else if (R->lastUpdated() != MapFeature::UserResolved)
146
R->layer()->remove(R);
151
if (R->lastUpdated() == MapFeature::NotYetDownloaded)
152
R->setLastUpdated(MapFeature::OSMServer);
161
R->setLastUpdated(MapFeature::OSMServer);
164
parseStandardAttributes(atts,R);
170
void OSMHandler::parseMember(const QXmlAttributes& atts)
172
Relation* R = dynamic_cast<Relation*>(Current);
175
QString Type = atts.value("type");
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"));
185
R->add(atts.value("role"),F);
188
void OSMHandler::parseRelation(const QXmlAttributes& atts)
190
QString id = atts.value("id");
191
if (id[0] != '-' && id[0] != '{')
193
QString ts = atts.value("timestamp"); ts.truncate(19);
194
Relation* R = dynamic_cast<Relation*>(theDocument->getFeature(id));
197
if (R->lastUpdated() == MapFeature::User)
199
R->setLastUpdated(MapFeature::UserResolved);
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); */
212
else if (R->lastUpdated() != MapFeature::UserResolved)
214
R->layer()->remove(R);
219
if (R->lastUpdated() == MapFeature::NotYetDownloaded)
220
R->setLastUpdated(MapFeature::OSMServer);
229
R->setLastUpdated(MapFeature::OSMServer);
232
parseStandardAttributes(atts,R);
238
bool OSMHandler::startElement ( const QString &, const QString & /* localName */, const QString & qName, const QXmlAttributes & atts )
242
else if (qName == "node")
244
else if (qName == "nd")
246
else if (qName == "way")
248
else if (qName == "member")
250
else if (qName == "relation")
255
bool OSMHandler::endElement ( const QString &, const QString & /* localName */, const QString & qName )
262
static bool downloadToResolve(const QList<MapFeature*>& Resolution, QWidget* aParent, MapDocument* theDocument, MapLayer* theLayer, Downloader* theDownloader)
264
IProgressWindow* aProgressWindow = dynamic_cast<IProgressWindow*>(aParent);
265
if (!aProgressWindow)
268
QProgressDialog* dlg = aProgressWindow->getProgressDialog();
269
dlg->setWindowTitle(QApplication::translate("Downloader", "Downloading unresolved..."));
270
QProgressBar* Bar = aProgressWindow->getProgressBar();
271
QLabel* Lbl = aProgressWindow->getProgressLabel();
273
for (int i=0; i<Resolution.size(); i++ )
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))
279
if (theDownloader->resultCode() == 410) {
280
theLayer->remove(Resolution[i]);
281
delete Resolution[i];
285
Lbl->setText(QApplication::translate("Downloader","Parsing unresolved %1 of %2").arg(i+1).arg(Resolution.size()));
287
QByteArray ba(theDownloader->content());
289
File.open(QIODevice::ReadOnly);
291
OSMHandler theHandler(theDocument,theLayer,NULL);
293
QXmlSimpleReader xmlReader;
294
xmlReader.setContentHandler(&theHandler);
295
QXmlInputSource source;
296
QByteArray buf(File.read(10240));
298
xmlReader.parse(&source,true);
299
while (!File.atEnd())
301
QByteArray buf(File.read(20480));
303
xmlReader.parseContinue();
304
qApp->processEvents();
305
if (dlg && dlg->wasCanceled())
309
Resolution[i]->setLastUpdated(MapFeature::OSMServer);
318
static void recurseDelete (MapFeature* F, QList<MapFeature*>& MustDelete)
320
for (int i=0; i<F->sizeParents(); i++) {
321
recurseDelete(F->getParent(i), MustDelete);
323
if (!MustDelete.contains(F))
324
MustDelete.push_back(F);
327
static bool resolveNotYetDownloaded(QWidget* aParent, MapDocument* theDocument, MapLayer* theLayer, Downloader* theDownloader)
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
333
IProgressWindow* aProgressWindow = dynamic_cast<IProgressWindow*>(aParent);
334
if (!aProgressWindow)
337
QProgressBar* Bar = aProgressWindow->getProgressBar();
338
//QLabel* Lbl = aProgressWindow->getProgressLabel();
340
QList<MapFeature*> MustResolve;
342
for (FeatureIterator it(theDocument); !it.isEnd(); ++it)
344
Relation* RR = CAST_RELATION(it.get());
345
if (RR && RR->notEverythingDownloaded())
346
MustResolve.push_back(RR);
348
if (MustResolve.size())
350
Bar->setMaximum(MustResolve.size());
352
if (!downloadToResolve(MustResolve,aParent,theDocument,theLayer, theDownloader))
359
static bool deleteIncompleteRelations(QWidget* /*aParent*/, MapDocument* /*theDocument*/, MapLayer* theLayer, Downloader* /*theDownloader*/)
361
QList<MapFeature*> MustDelete;
362
for (int i=0; i<theLayer->size(); i++)
364
if (theLayer->get(i)->notEverythingDownloaded()) {
365
recurseDelete(theLayer->get(i), MustDelete);
368
for (int i=0; i<MustDelete.size(); i++) {
369
MustDelete[i]->layer()->remove(MustDelete[i]);
370
delete MustDelete[i];
375
bool importOSM(QWidget* aParent, QIODevice& File, MapDocument* theDocument, MapLayer* theLayer, Downloader* theDownloader)
380
/* int ErrorColumn; */
382
IProgressWindow* aProgressWindow = dynamic_cast<IProgressWindow*>(aParent);
383
if (!aProgressWindow)
386
QProgressDialog* dlg = aProgressWindow->getProgressDialog();
388
dlg->setWindowTitle(QApplication::translate("Downloader", "Parsing..."));
390
QProgressBar* Bar = aProgressWindow->getProgressBar();
391
Bar->setTextVisible(false);
393
QLabel* Lbl = aProgressWindow->getProgressLabel();
394
Lbl->setText(QApplication::translate("Downloader","Parsing XML"));
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);
404
OSMHandler theHandler(theDocument,theLayer,conflictLayer);
406
QXmlSimpleReader xmlReader;
407
xmlReader.setContentHandler(&theHandler);
408
QXmlInputSource source;
409
QByteArray buf(File.read(10240));
411
xmlReader.parse(&source,true);
412
Bar->setMaximum(File.size());
413
Bar->setValue(Bar->value()+buf.size());
414
while (!File.atEnd())
416
QByteArray buf(File.read(20480));
418
xmlReader.parseContinue();
419
Bar->setValue(Bar->value()+buf.size());
420
qApp->processEvents();
421
if (dlg && dlg->wasCanceled())
425
bool WasCanceled = false;
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);
435
theDocument->remove(conflictLayer);
436
delete conflictLayer;
441
if (!conflictLayer->size()) {
442
theDocument->remove(conflictLayer);
443
delete conflictLayer;
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."
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));
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,
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);
483
bool importOSM(QWidget* aParent, const QString& aFilename, MapDocument* theDocument, MapLayer* theLayer)
485
QFile File(aFilename);
486
if (!File.open(QIODevice::ReadOnly))
488
return importOSM(aParent, File, theDocument, theLayer, 0 );
491
bool importOSM(QWidget* aParent, QByteArray& Content, MapDocument* theDocument, MapLayer* theLayer, Downloader* theDownloader)
493
QBuffer File(&Content);
494
File.open(QIODevice::ReadOnly);
495
return importOSM(aParent, File, theDocument, theLayer, theDownloader);