1 #include "DownloadOSM.h"
2 
3 #include "MainWindow.h"
4 #include "MapView.h"
5 #include "Coord.h"
6 #include "ImportGPX.h"
7 #include "ImportExportGdal.h"
8 #include "ImportOSM.h"
9 #include "Document.h"
10 #include "Layer.h"
11 #include "Feature.h"
12 #include "TrackSegment.h"
13 #include "SlippyMapWidget.h"
14 #include "MerkaartorPreferences.h"
15 #include "OsmLink.h"
16 
17 #include "IProgressWindow.h"
18 
19 #include <ui_DownloadMapDialog.h>
20 
21 #include <QBuffer>
22 #include <QTimer>
23 #include <QComboBox>
24 #include <QMessageBox>
25 #include <QProgressBar>
26 #include <QLabel>
27 #include <QProgressDialog>
28 #include <QStatusBar>
29 #include <QInputDialog>
30 
31 /* DOWNLOADER */
32 
Downloader(const QString & aUser,const QString & aPwd)33 Downloader::Downloader(const QString& aUser, const QString& aPwd)
34 : User(aUser), Password(aPwd),
35   currentReply(0),Error(false), AnimatorLabel(0), AnimatorBar(0), AnimationTimer(0)
36 {
37     //IdAuth = Request.setUser(User.toUtf8(), Password.toUtf8());
38     connect(&netManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(on_requestFinished(QNetworkReply*)));
39     connect(&netManager,SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), this,SLOT(on_authenticationRequired(QNetworkReply*,QAuthenticator*)));
40 }
41 
42 
animate()43 void Downloader::animate()
44 {
45     if (AnimatorBar && AnimationTimer)
46         AnimatorBar->setValue((AnimatorBar->value()+1) % AnimatorBar->maximum());
47 }
48 
setAnimator(QProgressDialog * anAnimator,QLabel * anAnimatorLabel,QProgressBar * anAnimatorBar,bool anAnimate)49 void Downloader::setAnimator(QProgressDialog *anAnimator, QLabel* anAnimatorLabel, QProgressBar* anAnimatorBar, bool anAnimate)
50 {
51     delete AnimationTimer;
52 
53     AnimatorLabel = anAnimatorLabel;
54     AnimatorBar = anAnimatorBar;
55     if (AnimatorBar && anAnimate)
56     {
57         AnimationTimer = new QTimer(this);
58         connect(AnimationTimer,SIGNAL(timeout()),this,SLOT(animate()));
59     }
60     if (AnimatorBar)
61     {
62         AnimatorBar->setValue(0);
63         if (anAnimator)
64             connect(anAnimator,SIGNAL(canceled()),this,SLOT(on_Cancel_clicked()));
65         qApp->processEvents();
66     }
67 }
68 
on_Cancel_clicked()69 void Downloader::on_Cancel_clicked()
70 {
71     Error = true;
72     if (Loop.isRunning())
73         Loop.exit(QDialog::Rejected);
74 }
75 
76 #include "QTextBrowser"
77 
go(const QUrl & url)78 bool Downloader::go(const QUrl& url) {
79     return request("GET", url, QString());
80 }
81 
request(const QString & theMethod,const QUrl & url,const QString & theData)82 bool Downloader::request(const QString& theMethod, const QUrl& url, const QString& theData) {
83     if (Error) return false;
84 
85     qDebug() << "Downloader::request:" << url;
86 
87     netManager.setProxy(M_PREFS->getProxy(url));
88     QNetworkRequest req(url);
89 
90     req.setRawHeader(QByteArray("Content-Type"), QByteArray("text/xml"));
91     req.setRawHeader(QByteArray("User-Agent"), USER_AGENT.toLatin1());
92 
93     QByteArray dataArray(theData.toUtf8());
94     QBuffer dataBuffer(&dataArray);
95     currentReply = netManager.sendCustomRequest(req, theMethod.toLatin1(), &dataBuffer);
96 
97     if (AnimationTimer) {
98         AnimationTimer->start(200);
99         connect(currentReply,SIGNAL(downloadProgress(qint64, qint64)), this,SLOT(progress(qint64, qint64)));
100     }
101 
102     if (Loop.exec() == QDialog::Rejected)
103         return false;
104 
105     if (AnimationTimer)
106         SAFE_DELETE(AnimationTimer);
107 
108     /* Test for redirections */
109     QVariant redir = currentReply->attribute(QNetworkRequest::RedirectionTargetAttribute);
110     if (redir.isValid()) {
111         LocationText = redir.toString();
112         if (!LocationText.isEmpty()) {
113             QUrl newUrl(LocationText);
114             return request(theMethod, newUrl, theData);
115         }
116     }
117 
118     /* We will log the error, but reporting shall be done at the call site. */
119     if (currentReply->error()) {
120         qDebug() << "Downloader::request: received response with code"
121             << currentReply->error() << ", message" << currentReply->errorString();
122     }
123 
124 
125     /* Read the data */
126     Content = currentReply->readAll();
127     Result = currentReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
128     ResultText = currentReply->errorString();
129     ErrorText = currentReply->rawHeader("Error");
130     return !Error;
131 }
132 
on_authenticationRequired(QNetworkReply * reply,QAuthenticator * auth)133 void Downloader::on_authenticationRequired( QNetworkReply *reply, QAuthenticator *auth) {
134     static QNetworkReply *lastReply = NULL;
135 
136     /* Only provide authentication the first time we see this reply, to avoid
137      * infinite loop providing the same credentials. */
138     if (lastReply != reply) {
139         lastReply = reply;
140         qDebug() << "Downloader authentication required and provided.";
141         auth->setUser(User);
142         auth->setPassword(Password);
143     }
144 }
145 
content()146 QByteArray& Downloader::content()
147 {
148     return Content;
149 }
150 
on_requestFinished(QNetworkReply * reply)151 void Downloader::on_requestFinished( QNetworkReply *reply)
152 {
153     if (reply->error())
154         Error = true;
155     if ( (reply == currentReply) && Loop.isRunning() )
156         Loop.exit(QDialog::Accepted);
157 }
158 
progress(qint64 done,qint64 total)159 void Downloader::progress(qint64 done, qint64 total)
160 {
161     if (AnimatorLabel && AnimatorBar)
162     {
163         if (done < 10240)
164             AnimatorLabel->setText(tr("Downloading from OSM (%n bytes)", "", done));
165         else
166             AnimatorLabel->setText(tr("Downloading from OSM (%n kBytes)", "", (done/1024)));
167         if (AnimationTimer && total != 0)
168         {
169             SAFE_DELETE(AnimationTimer);
170             AnimatorBar->setMaximum(total);
171         }
172         if (!AnimationTimer && AnimatorBar)
173             AnimatorBar->setValue(done);
174     }
175 }
176 
resultCode()177 int Downloader::resultCode()
178 {
179     return Result;
180 }
181 
resultText()182 const QString &Downloader::resultText()
183 {
184     return ResultText;
185 }
186 
errorText()187 const QString &Downloader::errorText()
188 {
189     return ErrorText;
190 }
191 
locationText()192 const QString &Downloader::locationText()
193 {
194     return LocationText;
195 }
196 
getURLToOpenChangeSet()197 QString Downloader::getURLToOpenChangeSet()
198 {
199     return QString("/changeset/create");
200 }
201 
getURLToCloseChangeSet(const QString & Id)202 QString Downloader::getURLToCloseChangeSet(const QString& Id)
203 {
204     return QString("/changeset/%1/close").arg(Id);
205 }
206 
getURLToUploadDiff(QString changesetId)207 QString Downloader::getURLToUploadDiff(QString changesetId)
208 {
209     return QString("/changeset/%1/upload").arg(changesetId);
210 }
211 
getURLToFetch(const QString & What)212 QString Downloader::getURLToFetch(const QString &What)
213 {
214     QString URL = QString("/%1?%2=");
215     return URL.arg(What).arg(What);
216 }
217 
getURLToFetchFull(IFeature::FId id)218 QString Downloader::getURLToFetchFull(IFeature::FId id)
219 {
220     QString type;
221 	QString URL;
222     if (id.type & IFeature::Point) {
223         type = "node";
224 		URL = QString("/%1/%2");
225 	} else {
226 		if (id.type & IFeature::LineString)
227 			type = "way";
228 		if (id.type & IFeature::OsmRelation)
229 			type = "relation";
230 		URL = QString("/%1/%2/full");
231 	}
232 
233     return URL.arg(type).arg(id.numId);
234 }
235 
getURLToFetchFull(Feature * aFeature)236 QString Downloader::getURLToFetchFull(Feature* aFeature)
237 {
238     return getURLToFetchFull(aFeature->id());
239 }
240 
getURLToFetch(const QString & What,const QString & Id)241 QString Downloader::getURLToFetch(const QString &What, const QString& Id)
242 {
243     QString URL = QString("/%1/%2");
244     return URL.arg(What).arg(Id);
245 }
246 
getURLToCreate(const QString & What)247 QString Downloader::getURLToCreate(const QString &What)
248 {
249     QString URL = QString("/%1/create");
250     return URL.arg(What);
251 }
252 
getURLToUpdate(const QString & What,const QString & Id)253 QString Downloader::getURLToUpdate(const QString &What, const QString& Id)
254 {
255     QString URL = QString("/%1/%2");
256     return URL.arg(What).arg(Id);
257 }
258 
getURLToDelete(const QString & What,const QString & Id)259 QString Downloader::getURLToDelete(const QString &What, const QString& Id)
260 {
261     QString URL = QString("/%1/%2");
262     return URL.arg(What).arg(Id);
263 }
264 
getURLToMap()265 QString Downloader::getURLToMap()
266 {
267     QString URL("/map?bbox=%1,%2,%3,%4");
268     return URL;
269 }
270 
getURLToTrackPoints()271 QString Downloader::getURLToTrackPoints()
272 {
273     QString URL = QString("/trackpoints?bbox=%1,%2,%3,%4&page=%5");
274     return URL;
275 }
276 
downloadOSM(QWidget * aParent,const QUrl & theUrl,const QString & aUser,const QString & aPassword,Document * theDocument,Layer * theLayer)277 bool downloadOSM(QWidget* aParent, const QUrl& theUrl, const QString& aUser, const QString& aPassword, Document* theDocument, Layer* theLayer)
278 {
279     Downloader Rcv(aUser, aPassword);
280 
281     IProgressWindow* aProgressWindow = dynamic_cast<IProgressWindow*>(aParent);
282     if (aProgressWindow) {
283 
284         QProgressDialog* dlg = aProgressWindow->getProgressDialog();
285         if (dlg) {
286             dlg->setWindowTitle(QApplication::translate("Downloader","Downloading..."));
287             dlg->setWindowFlags(dlg->windowFlags() & ~Qt::WindowContextHelpButtonHint);
288             dlg->setWindowFlags(dlg->windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
289         }
290 
291         QProgressBar* Bar = aProgressWindow->getProgressBar();
292         Bar->setTextVisible(false);
293         Bar->setMaximum(11);
294 
295         QLabel* Lbl = aProgressWindow->getProgressLabel();
296         Lbl->setText(QApplication::translate("Downloader","Downloading from OSM (connecting)"));
297 
298         if (dlg)
299             dlg->show();
300 
301         Rcv.setAnimator(dlg, Lbl, Bar, true);
302     }
303     if (!Rcv.go(theUrl))
304     {
305 #ifndef _MOBILE
306         /** TODO: Let the caller set the cursor. */
307         aParent->setCursor(QCursor(Qt::ArrowCursor));
308 #endif
309     }
310     int x = Rcv.resultCode();
311     qDebug() << "DownloadOSM: Received OSM API response code:" << x << ", processing.";
312 
313     /** We will parse the error codes and display the appropriate messages. */
314     switch (x)
315     {
316     case 200:
317         qDebug() << "DownloadOSM: Response OK, processing.";
318         break;
319     case 301:
320     case 302:
321     case 307: {
322         QString aWeb = Rcv.locationText();
323         if (!aWeb.isEmpty()) {
324             QUrl aURL(aWeb);
325             return downloadOSM(aParent, aURL, aUser, aPassword, theDocument, theLayer);
326         } else {
327             QString msg = QApplication::translate("Downloader","Unexpected http status code (%1)\nServer message is '%2'").arg(x).arg(Rcv.resultText());
328             if (!Rcv.errorText().isEmpty())
329                 msg += QApplication::translate("Downloader", "\nAPI message is '%1'").arg(Rcv.errorText());
330             QMessageBox::warning(aParent,QApplication::translate("Downloader","Download failed"), msg);
331             return false;
332         }
333         break;
334     }
335     case 401:
336         QMessageBox::warning(aParent,QApplication::translate("Downloader","Download failed"),QApplication::translate("Downloader","Username/password invalid"));
337         return false;
338     default:
339         QString msg = QApplication::translate("Downloader","Unexpected http status code (%1)\nServer message is '%2'").arg(x).arg(Rcv.resultText());
340         if (!Rcv.errorText().isEmpty())
341             msg += QApplication::translate("Downloader", "\nAPI message is '%1'").arg(Rcv.errorText());
342         QMessageBox::warning(aParent,QApplication::translate("Downloader","Download failed"), msg);
343         return false;
344     }
345     Downloader Down(aUser, aPassword);
346     bool OK = importOSM(aParent, Rcv.content(), theDocument, theLayer, &Down);
347     return OK;
348 }
349 
downloadOSM(QWidget * aParent,const QString & aWeb,const QString & aUser,const QString & aPassword,const CoordBox & aBox,Document * theDocument,Layer * theLayer)350 bool downloadOSM(QWidget* aParent, const QString& aWeb, const QString& aUser, const QString& aPassword, const CoordBox& aBox , Document* theDocument, Layer* theLayer)
351 {
352     if (checkForConflicts(theDocument))
353     {
354         QMessageBox::warning(aParent,QApplication::translate("Downloader","Unresolved conflicts"), QApplication::translate("Downloader","Please resolve existing conflicts first"));
355         return false;
356     }
357     Downloader Rcv(aUser, aPassword);
358     QString URL = Rcv.getURLToMap();
359 
360     if ((fabs(aBox.bottomLeft().x()) < 180.0 && fabs(aBox.topRight().x()) > 180.0)
361      || (fabs(aBox.bottomLeft().x()) > 180.0 && fabs(aBox.topRight().x()) < 180.0)) {
362         /* Check for +-180 meridian, and split query in two if necessary */
363         int sign = (aBox.bottomLeft().x() > 0) ? 1 : -1;
364         CoordBox q1 = aBox, q2 = aBox;
365         if (aBox.bottomLeft().x() > 0) {
366             q1.setRight(180*sign);
367             q2.setLeft(-180*sign);
368             q2.setRight(q2.right()-360);
369         } else {
370             q1.setLeft(180*sign);
371             q2.setRight(-180*sign);
372             q2.setLeft(q2.left()+360);
373         }
374         return downloadOSM(aParent, aWeb, aUser, aPassword, q1, theDocument, theLayer)
375             && downloadOSM(aParent, aWeb, aUser, aPassword, q2, theDocument, theLayer);
376 
377     } else {
378         /* Normal code path */
379         URL = URL.arg(aBox.bottomLeft().x(), 0, 'f').arg(aBox.bottomLeft().y(), 0, 'f').arg(aBox.topRight().x(), 0, 'f').arg(aBox.topRight().y(), 0, 'f');
380         QUrl theUrl(aWeb+URL);
381         return downloadOSM(aParent, theUrl, aUser, aPassword, theDocument, theLayer);
382     }
383 }
384 
downloadTracksFromOSM(QWidget * Main,const QString & aWeb,const QString & aUser,const QString & aPassword,const CoordBox & aBox,Document * theDocument)385 bool downloadTracksFromOSM(QWidget* Main, const QString& aWeb, const QString& aUser, const QString& aPassword, const CoordBox& aBox , Document* theDocument)
386 {
387     Downloader theDownloader(aUser, aPassword);
388     QList<TrackLayer*> theTracklayers;
389     //TrackMapLayer* trackLayer = new TrackMapLayer(QApplication::translate("Downloader","Downloaded tracks"));
390     //theDocument->add(trackLayer);
391 
392     IProgressWindow* aProgressWindow = dynamic_cast<IProgressWindow*>(Main);
393     if (!aProgressWindow)
394         return false;
395 
396     QProgressDialog* dlg = aProgressWindow->getProgressDialog();
397     dlg->setWindowTitle(QApplication::translate("Downloader","Parsing..."));
398 
399     QProgressBar* Bar = aProgressWindow->getProgressBar();
400     Bar->setTextVisible(false);
401     Bar->setMaximum(11);
402 
403     QLabel* Lbl = aProgressWindow->getProgressLabel();
404     Lbl->setText(QApplication::translate("Downloader","Parsing XML"));
405 
406     if (dlg)
407         dlg->show();
408 
409     theDownloader.setAnimator(dlg,Lbl,Bar,true);
410     for (int Page=0; ;++Page)
411     {
412         Lbl->setText(QApplication::translate("Downloader","Downloading trackpoints %1-%2").arg(Page*5000+1).arg(Page*5000+5000));
413         QString URL = theDownloader.getURLToTrackPoints();
414         URL = URL.arg(aBox.bottomLeft().x()).
415                 arg(aBox.bottomLeft().y()).
416                 arg(aBox.topRight().x()).
417                 arg(aBox.topRight().y()).
418                 arg(Page);
419         QUrl theUrl(aWeb+URL);
420         if (!theDownloader.go(theUrl))
421             return false;
422         if (theDownloader.resultCode() != 200)
423             return false;
424         int Before = theTracklayers.size();
425         QByteArray Ar(theDownloader.content());
426         bool OK = ImportGPX::import(Main, Ar, theDocument, theTracklayers, ImportGPX::Option::MakeSegmented | ImportGPX::Option::DetectAnonymizedSegments);
427         if (!OK)
428             return false;
429         if (Before == theTracklayers.size())
430             break;
431     }
432     return true;
433 }
434 
435 
checkForConflicts(Document * theDocument)436 bool checkForConflicts(Document* theDocument)
437 {
438     for (FeatureIterator it(theDocument); !it.isEnd(); ++it) {
439         if (it.get()->lastUpdated() == Feature::OSMServerConflict)
440             return true;
441     }
442     return false;
443 }
444 
downloadFeatures(MainWindow * Main,const QList<Feature * > & aDownloadList,Document * theDocument)445 bool downloadFeatures(MainWindow* Main, const QList<Feature*>& aDownloadList , Document* theDocument)
446 {
447     QList<IFeature::FId> list;
448     foreach (Feature* F, aDownloadList) {
449         list << F->id();
450     }
451 
452     bool ok = downloadFeatures(Main, list, theDocument, NULL);
453 
454     return ok;
455 }
456 
downloadFeature(MainWindow * Main,const IFeature::FId & id,Document * theDocument,Layer * theLayer)457 bool downloadFeature(MainWindow* Main, const IFeature::FId& id, Document* theDocument, Layer* theLayer)
458 {
459     QList<IFeature::FId> list;
460     list << id;
461     bool ok = downloadFeatures(Main, list, theDocument, theLayer);
462 
463     return ok;
464 }
465 
downloadFeatures(MainWindow * Main,const QList<IFeature::FId> & idList,Document * theDocument,Layer * theLayer)466 bool downloadFeatures(MainWindow* Main, const QList<IFeature::FId>& idList , Document* theDocument, Layer* theLayer)
467 {
468     if (!theLayer) {
469         if (!theDocument->getLastDownloadLayer()) {
470             theLayer = new DrawingLayer(QApplication::translate("Downloader","%1 download").arg(QDateTime::currentDateTime().toString(Qt::ISODate)));
471             theDocument->add(theLayer);
472         } else
473             theLayer = (Layer*)theDocument->getLastDownloadLayer();
474     }
475 
476     QString osmWebsite, osmUser, osmPwd;
477 
478     osmWebsite = M_PREFS->getOsmApiUrl();
479     osmUser = M_PREFS->getOsmUser();
480     osmPwd = M_PREFS->getOsmPassword();
481 
482     if (Main)
483         Main->view()->setUpdatesEnabled(false);
484 
485     bool OK = true;
486     Downloader Rcv(osmUser, osmPwd);
487 
488     for (int i=0; i<idList.size(); ++i) {
489         QString URL = Rcv.getURLToFetchFull(idList[i]);
490         QUrl theUrl(osmWebsite+URL);
491 
492         downloadOSM(Main, theUrl, osmUser, osmPwd, theDocument, theLayer);
493     }
494 
495     if (Main)
496         Main->view()->setUpdatesEnabled(true);
497     if (OK)
498     {
499         if (Main)
500             Main->invalidateView();
501     } else
502     {
503         if (theLayer != theDocument->getLastDownloadLayer()) {
504             theDocument->remove(theLayer);
505             delete theLayer;
506         }
507     }
508     return OK;
509 }
510 
downloadMapdust(MainWindow * Main,const CoordBox & aBox,Document * theDocument,SpecialLayer * theLayer)511 bool downloadMapdust(MainWindow* Main, const CoordBox& aBox, Document* theDocument, SpecialLayer* theLayer)
512 {
513     QUrl url;
514 
515     url.setUrl(M_PREFS->getMapdustUrl());
516 
517     if (Main)
518         Main->view()->setUpdatesEnabled(false);
519 
520     Downloader theDownloader("", "");
521 
522     SpecialLayer* trackLayer = theLayer;
523     if (!trackLayer) {
524         trackLayer = new SpecialLayer(QApplication::translate("Downloader","MapDust"), Layer::MapDustLayer);
525         trackLayer->setUploadable(false);
526         theDocument->add(trackLayer);
527     }
528 
529     IProgressWindow* aProgressWindow = dynamic_cast<IProgressWindow*>(Main);
530     if (!aProgressWindow)
531         return false;
532 
533     QProgressDialog* dlg = aProgressWindow->getProgressDialog();
534     dlg->setWindowTitle(QApplication::translate("Downloader","Parsing..."));
535 
536     QProgressBar* Bar = aProgressWindow->getProgressBar();
537     Bar->setTextVisible(false);
538     Bar->setMaximum(11);
539 
540     QLabel* Lbl = aProgressWindow->getProgressLabel();
541     Lbl->setText(QApplication::translate("Downloader","Parsing XML"));
542 
543     if (dlg)
544         dlg->show();
545 
546     theDownloader.setAnimator(dlg,Lbl,Bar,true);
547     Lbl->setText(QApplication::translate("Downloader","Downloading points"));
548 
549 #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
550     QUrlQuery theQuery(url);
551 #define theQuery theQuery
552 #else
553 #define theQuery url
554 #endif
555     theQuery.addQueryItem("t", COORD2STRING(aBox.topRight().y()));
556     theQuery.addQueryItem("l", COORD2STRING(aBox.bottomLeft().x()));
557     theQuery.addQueryItem("b", COORD2STRING(aBox.bottomLeft().y()));
558     theQuery.addQueryItem("r", COORD2STRING(aBox.topRight().x()));
559 #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
560     url.setQuery(theQuery);
561 #endif
562 #undef theQuery
563 
564     if (!theDownloader.go(url))
565         return false;
566     if (theDownloader.resultCode() != 200)
567         return false;
568     QByteArray Ar(theDownloader.content());
569     ImportExportGdal gdal(theDocument);
570     bool OK = gdal.import(trackLayer, Ar, false);
571 
572     if (Main)
573         Main->view()->setUpdatesEnabled(true);
574     if (OK) {
575         if (Main)
576             Main->invalidateView();
577     }
578     return OK;
579 }
580 
downloadMoreOSM(MainWindow * Main,const CoordBox & aBox,Document * theDocument)581 bool downloadMoreOSM(MainWindow* Main, const CoordBox& aBox , Document* theDocument)
582 {
583     Layer* theLayer;
584     if (!theDocument->getLastDownloadLayer()) {
585         theLayer = new DrawingLayer(QApplication::translate("Downloader","%1 download").arg(QDateTime::currentDateTime().toString(Qt::ISODate)));
586         theDocument->add(theLayer);
587     } else
588         theLayer = (Layer*)theDocument->getLastDownloadLayer();
589 
590     QString osmWebsite, osmUser, osmPwd;
591 
592     osmWebsite = M_PREFS->getOsmApiUrl();
593     osmUser = M_PREFS->getOsmUser();
594     osmPwd = M_PREFS->getOsmPassword();
595     qDebug() << "Requesting more from " << osmWebsite;
596 
597     Main->view()->setUpdatesEnabled(false);
598 
599     bool OK = true;
600     OK = downloadOSM(Main,osmWebsite,osmUser,osmPwd,aBox,theDocument,theLayer);
601     Main->view()->setUpdatesEnabled(true);
602     if (OK)
603     {
604         theDocument->setLastDownloadLayer(theLayer);
605         theDocument->addDownloadBox(theLayer, aBox);
606         // Don't jump around on Download More
607         // aParent->view()->projection().setViewport(aBox,aParent->view()->rect());
608         Main->invalidateView();
609     } else
610     {
611         if (theLayer != theDocument->getLastDownloadLayer()) {
612             theDocument->remove(theLayer);
613             delete theLayer;
614         }
615     }
616     return OK;
617 }
618 
downloadOSM(MainWindow * Main,const CoordBox & aBox,Document * theDocument)619 bool downloadOSM(MainWindow* Main, const CoordBox& aBox , Document* theDocument)
620 {
621     QString osmWebsite, osmUser, osmPwd;
622     static bool DownloadRaw = false;
623 
624     QDialog * dlg = new QDialog(Main);
625 
626     osmWebsite = M_PREFS->getOsmApiUrl();
627     osmUser = M_PREFS->getOsmUser();
628     osmPwd = M_PREFS->getOsmPassword();
629 
630     Ui::DownloadMapDialog ui;
631     ui.setupUi(dlg);
632     SlippyMapWidget* SlippyMap = new SlippyMapWidget(ui.groupBox);
633 #ifndef _MOBILE
634     SlippyMap->setMinimumHeight(256);
635 #endif
636     CoordBox Clip(aBox);
637     SlippyMap->setViewportArea(Clip);
638     ui.verticalLayout->addWidget(SlippyMap);
639     QObject::connect(SlippyMap, SIGNAL(redraw()), ui.FromMap, SLOT(toggle()));
640     BookmarkListIterator i(*(M_PREFS->getBookmarks()));
641     while (i.hasNext()) {
642         i.next();
643         if (i.value().deleted == false)
644             ui.Bookmarks->addItem(i.key());
645     }
646     ui.edXapiUrl->setText(QString("*[bbox=%1,%2,%3,%4]").arg(aBox.bottomLeft().x(), 0, 'f').arg(aBox.bottomLeft().y(), 0, 'f').arg(aBox.topRight().x(), 0, 'f').arg(aBox.topRight().y(), 0, 'f'));
647     ui.IncludeTracks->setChecked(DownloadRaw);
648     ui.ResolveRelations->setChecked(M_PREFS->getResolveRelations());
649     bool OK = true, retry = true, directAPI = false;
650     QString directUrl;
651     while (retry) {
652         retry = false;
653 #ifdef _MOBILE
654         dlg->setWindowState(Qt::WindowMaximized);
655 #endif
656         if (dlg->exec() == QDialog::Accepted)
657         {
658             DownloadRaw = false;
659             if (ui.FromBookmark->isChecked())
660             {
661                 Clip = M_PREFS->getBookmarks()->value(ui.Bookmarks->currentText()).Coordinates;
662             }
663             else if (ui.FromView->isChecked())
664             {
665                 Clip = aBox;
666             }
667             else if (ui.FromLink->isChecked()) {
668                 QString link = ui.Link->text();
669 
670                 if (link.contains("/api/")) {
671                     directAPI=true;
672                     directUrl = link;
673                 } else if (link.contains("/browse/")) {
674                     QString tag("/browse/");
675                     int ix = link.lastIndexOf(tag) + tag.length();
676                     directUrl = M_PREFS->getOsmApiUrl();
677                     if (!directUrl.endsWith("/")) directUrl += "/";
678                     directUrl += link.right(link.length() - ix);
679                     if (!directUrl.endsWith("/")) directUrl += "/";
680                     directUrl += "full";
681                     directAPI=true;
682                 } else if (link.startsWith("way") || link.startsWith("node") || link.startsWith("relation")) {
683                     directUrl = M_PREFS->getOsmApiUrl();
684                     if (!directUrl.endsWith("/")) directUrl += "/";
685                     directUrl += link;
686                     directAPI=true;
687                 } else {
688                     OsmLink ol(link);
689                     Clip = ol.getCoordBox();
690                     if (Clip.isNull() || Clip.isEmpty())
691                         retry = true;
692                 }
693             }
694             else if (ui.FromXapi->isChecked())
695             {
696                 directAPI = true;
697                 directUrl = M_PREFS->getXapiUrl();
698                 //if (!directUrl.endsWith("/")) directUrl += "/";
699                 directUrl += ui.edXapiUrl->text();
700             }
701             else if (ui.FromMap->isChecked())
702             {
703                 QRectF R(SlippyMap->selectedArea());
704                 Clip = CoordBox(Coord(R.x(), R.y()), Coord(R.x()+R.width(), R.y()+R.height()));
705             }
706             if (retry) continue;
707             Main->view()->setUpdatesEnabled(false);
708             Layer* theLayer = new DrawingLayer(QApplication::translate("Downloader","%1 download").arg(QDateTime::currentDateTime().toString(Qt::ISODate)));
709             theDocument->add(theLayer);
710             M_PREFS->setResolveRelations(ui.ResolveRelations->isChecked());
711             if (directAPI) {
712                 if (ui.FromXapi->isChecked())
713                     theLayer->setUploadable(false);
714                 OK = downloadOSM(Main,QUrl(QUrl::fromEncoded(directUrl.toLatin1())),osmUser,osmPwd,theDocument,theLayer);
715             }
716             else
717                 OK = downloadOSM(Main,osmWebsite,osmUser,osmPwd,Clip,theDocument,theLayer);
718             if (OK && ui.IncludeTracks->isChecked())
719                 OK = downloadTracksFromOSM(Main,osmWebsite,osmUser,osmPwd, Clip,theDocument);
720             Main->view()->setUpdatesEnabled(true);
721             if (OK)
722             {
723                 theDocument->setLastDownloadLayer(theLayer);
724                 theDocument->addDownloadBox(theLayer, Clip);
725 #ifndef _MOBILE
726                 if (directAPI)
727                     Main->on_viewZoomAllAction_triggered();
728                 else
729 #endif
730                     Main->view()->setViewport(Clip,Main->view()->rect());
731                 Main->invalidateView();
732             } else {
733                 retry = true;
734                 theDocument->remove(theLayer);
735                 SAFE_DELETE(theLayer);
736             }
737         }
738     }
739     delete dlg;
740     return OK;
741 }
742 
743