From 0808f6679e3baac389b13e587687f99673e75407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Fri, 21 Apr 2017 21:15:58 +0200 Subject: [PATCH] Added "runtime" offline map loading Offline map loading & error handling cleanup --- gpxsee.pro | 10 +-- src/atlas.cpp | 69 ++++++++++------ src/atlas.h | 8 +- src/gui.cpp | 157 ++++++++++++++++++++++++------------ src/gui.h | 12 ++- src/mapdir.cpp | 40 ---------- src/mapdir.h | 16 ---- src/maplist.cpp | 101 +++++++++++++++++++----- src/maplist.h | 24 ++++-- src/offlinemap.cpp | 193 ++++++++++++++++++++------------------------- src/offlinemap.h | 17 ++-- 11 files changed, 361 insertions(+), 286 deletions(-) delete mode 100644 src/mapdir.cpp delete mode 100644 src/mapdir.h diff --git a/gpxsee.pro b/gpxsee.pro index 87cb05a5..770b1818 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -23,7 +23,6 @@ HEADERS += src/config.h \ src/filebrowser.h \ src/map.h \ src/onlinemap.h \ - src/maplist.h \ src/downloader.h \ src/units.h \ src/scaleitem.h \ @@ -81,7 +80,6 @@ HEADERS += src/config.h \ src/timetype.h \ src/emptymap.h \ src/offlinemap.h \ - src/mapdir.h \ src/matrix.h \ src/tar.h \ src/atlas.h \ @@ -93,7 +91,8 @@ HEADERS += src/config.h \ src/lambertconic.h \ src/ellipsoid.h \ src/ozf.h \ - src/datum.h + src/datum.h \ + src/maplist.h SOURCES += src/main.cpp \ src/gui.cpp \ src/poi.cpp \ @@ -106,7 +105,6 @@ SOURCES += src/main.cpp \ src/sliderinfoitem.cpp \ src/filebrowser.cpp \ src/onlinemap.cpp \ - src/maplist.cpp \ src/downloader.cpp \ src/scaleitem.cpp \ src/track.cpp \ @@ -150,7 +148,6 @@ SOURCES += src/main.cpp \ src/stylecombobox.cpp \ src/emptymap.cpp \ src/offlinemap.cpp \ - src/mapdir.cpp \ src/matrix.cpp \ src/tar.cpp \ src/atlas.cpp \ @@ -160,7 +157,8 @@ SOURCES += src/main.cpp \ src/lambertconic.cpp \ src/ellipsoid.cpp \ src/ozf.cpp \ - src/datum.cpp + src/datum.cpp \ + src/maplist.cpp RESOURCES += gpxsee.qrc TRANSLATIONS = lang/gpxsee_cs.ts \ lang/gpxsee_sv.ts \ diff --git a/src/atlas.cpp b/src/atlas.cpp index 6a3d44c8..80883171 100644 --- a/src/atlas.cpp +++ b/src/atlas.cpp @@ -30,25 +30,35 @@ static bool yCmp(const OfflineMap *m1, const OfflineMap *m2) return TL(m1).y() > TL(m2).y(); } -bool Atlas::isAtlas(Tar &tar, const QFileInfoList &files) +bool Atlas::isAtlas(Tar &tar, const QString &path) { - for (int i = 0; i < files.count(); i++) { - const QString &fileName = files.at(i).fileName(); - if (fileName.endsWith(".tar")) { - if (!tar.load(files.at(i).absoluteFilePath())) { - qWarning("%s: %s: error loading tar file", qPrintable(_name), - qPrintable(fileName)); - return false; - } - QStringList tarFiles = tar.files(); - for (int j = 0; j < tarFiles.size(); j++) - if (tarFiles.at(j).endsWith(".tba")) - return true; - } else if (fileName.endsWith(".tba")) - return true; + QFileInfo fi(path); + QByteArray ba; + + + if (fi.suffix() == "tar") { + if (!tar.load(path)) { + _errorString = "Error reading tar file"; + return false; + } + QString tbaFileName = fi.completeBaseName() + ".tba"; + ba = tar.file(tbaFileName); + } else if (fi.suffix() == "tba") { + QFile tbaFile(path); + if (!tbaFile.open(QIODevice::ReadOnly)) { + _errorString = QString("Error opening tba file: %1") + .arg(tbaFile.errorString()); + return false; + } + ba = tbaFile.readAll(); } - return false; + if (ba.startsWith("Atlas 1.0")) + return true; + else { + _errorString = "Missing or invalid tba file"; + return false; + } } void Atlas::computeZooms() @@ -100,38 +110,45 @@ void Atlas::computeBounds() BR(_maps.at(i))), QRectF(offsets.at(i), _maps.at(i)->bounds().size()))); } -Atlas::Atlas(const QString &path, QObject *parent) : Map(parent) +Atlas::Atlas(const QString &fileName, QObject *parent) : Map(parent) { Tar tar; + QFileInfo fi(fileName); _valid = false; _zoom = 0; + _name = fi.dir().dirName(); - QFileInfo fi(path); - _name = fi.fileName(); - - QDir dir(path); - QFileInfoList files = dir.entryInfoList(QDir::Files); - if (!isAtlas(tar, files)) + if (!isAtlas(tar, fileName)) return; + QDir dir(fi.absolutePath()); QFileInfoList layers = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); for (int n = 0; n < layers.count(); n++) { QDir zdir(layers.at(n).absoluteFilePath()); QFileInfoList maps = zdir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); for (int i = 0; i < maps.count(); i++) { + QString mapFile = maps.at(i).absoluteFilePath() + "/" + + maps.at(i).fileName() + ".map"; + OfflineMap *map; if (tar.isOpen()) - map = new OfflineMap(tar, maps.at(i).absoluteFilePath(), this); + map = new OfflineMap(mapFile, tar, this); else - map = new OfflineMap(maps.at(i).absoluteFilePath(), this); + map = new OfflineMap(mapFile, this); + if (map->isValid()) _maps.append(map); + else { + _errorString = QString("Error loading map: %1: %2") + .arg(mapFile, map->errorString()); + return; + } } } if (_maps.isEmpty()) { - qWarning("%s: No usable maps available", qPrintable(_name)); + _errorString = "No maps found in atlas"; return; } diff --git a/src/atlas.h b/src/atlas.h index c3882d46..0383f877 100644 --- a/src/atlas.h +++ b/src/atlas.h @@ -11,7 +11,7 @@ class Atlas : public Map Q_OBJECT public: - Atlas(const QString &path, QObject *parent = 0); + Atlas(const QString &fileName, QObject *parent = 0); ~Atlas(); const QString &name() const {return _name;} @@ -29,16 +29,18 @@ public: void draw(QPainter *painter, const QRectF &rect); - bool isValid() {return _valid;} + bool isValid() const {return _valid;} + const QString &errorString() const {return _errorString;} private: void draw(QPainter *painter, const QRectF &rect, int mapIndex); - bool isAtlas(Tar &tar, const QFileInfoList &files); + bool isAtlas(Tar &tar, const QString &path); void computeZooms(); void computeBounds(); QString _name; bool _valid; + QString _errorString; QList _maps; QVector > _zooms; diff --git a/src/gui.cpp b/src/gui.cpp index 4f3eb3a6..2611e930 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -30,7 +30,6 @@ #include "datum.h" #include "map.h" #include "maplist.h" -#include "mapdir.h" #include "emptymap.h" #include "elevationgraph.h" #include "speedgraph.h" @@ -166,21 +165,48 @@ void GUI::loadDatums() void GUI::loadMaps() { - QList online, offline; + _ml = new MapList(this); + + QString offline, online; if (QFile::exists(USER_MAP_FILE)) - online = MapList::load(USER_MAP_FILE, this); - else - online = MapList::load(GLOBAL_MAP_FILE, this); + online = USER_MAP_FILE; + else if (QFile::exists(GLOBAL_MAP_FILE)) + online = GLOBAL_MAP_FILE; + + if (!online.isNull() && !_ml->loadList(online)) + qWarning("%s: %s", qPrintable(online), qPrintable(_ml->errorString())); + if (QFile::exists(USER_MAP_DIR)) - offline = MapDir::load(USER_MAP_DIR, this); - else - offline = MapDir::load(GLOBAL_MAP_DIR, this); + offline = USER_MAP_DIR; + else if (QFile::exists(GLOBAL_MAP_DIR)) + offline = GLOBAL_MAP_DIR; - _maps = online + offline; + if (!offline.isNull()) { + QDir md(offline); + QFileInfoList ml = md.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + QStringList filters; + filters << "*.map" << "*.tba" << "*.tar"; - _map = _maps.isEmpty() ? new EmptyMap(this) : _maps.first(); + for (int i = 0; i < ml.size(); i++) { + QDir dir(ml.at(i).absoluteFilePath()); + QFileInfoList fl = dir.entryInfoList(filters, QDir::Files); + + if (fl.isEmpty()) + qWarning("%s: no map/atlas file found", + qPrintable(ml.at(i).absoluteFilePath())); + else if (fl.size() > 1) + qWarning("%s: ambiguous directory content", + qPrintable(ml.at(i).absoluteFilePath())); + else + if (!_ml->loadMap(fl.first().absoluteFilePath())) + qWarning("%s: %s", qPrintable(fl.first().absoluteFilePath()), + qPrintable(_ml->errorString())); + } + } + + _map = _ml->maps().isEmpty() ? new EmptyMap(this) : _ml->maps().first(); } void GUI::loadPOIs() @@ -209,33 +235,33 @@ void GUI::loadPOIs() void GUI::createMapActions() { - QActionGroup *ag = new QActionGroup(this); - ag->setExclusive(true); + _mapsSignalMapper = new QSignalMapper(this); + _mapsActionGroup = new QActionGroup(this); + _mapsActionGroup->setExclusive(true); - QSignalMapper *sm = new QSignalMapper(this); - - for (int i = 0; i < _maps.count(); i++) { - QAction *a = new QAction(_maps.at(i)->name(), this); + for (int i = 0; i < _ml->maps().count(); i++) { + QAction *a = new QAction(_ml->maps().at(i)->name(), this); a->setCheckable(true); - a->setActionGroup(ag); + a->setActionGroup(_mapsActionGroup); - sm->setMapping(a, i); - connect(a, SIGNAL(triggered()), sm, SLOT(map())); + _mapsSignalMapper->setMapping(a, i); + connect(a, SIGNAL(triggered()), _mapsSignalMapper, SLOT(map())); _mapActions.append(a); } - connect(sm, SIGNAL(mapped(int)), this, SLOT(mapChanged(int))); + connect(_mapsSignalMapper, SIGNAL(mapped(int)), this, + SLOT(mapChanged(int))); } void GUI::createPOIFilesActions() { - _poiFilesSM = new QSignalMapper(this); + _poiFilesSignalMapper = new QSignalMapper(this); for (int i = 0; i < _poi->files().count(); i++) createPOIFileAction(i); - connect(_poiFilesSM, SIGNAL(mapped(int)), this, SLOT(poiFileChecked(int))); + connect(_poiFilesSignalMapper, SIGNAL(mapped(int)), this, SLOT(poiFileChecked(int))); } QAction *GUI::createPOIFileAction(int index) @@ -244,8 +270,8 @@ QAction *GUI::createPOIFileAction(int index) this); a->setCheckable(true); - _poiFilesSM->setMapping(a, index); - connect(a, SIGNAL(triggered()), _poiFilesSM, SLOT(map())); + _poiFilesSignalMapper->setMapping(a, index); + connect(a, SIGNAL(triggered()), _poiFilesSignalMapper, SLOT(map())); _poiFilesActions.append(a); @@ -341,23 +367,24 @@ void GUI::createActions() connect(_showMapAction, SIGNAL(triggered(bool)), _pathView, SLOT(showMap(bool))); addAction(_showMapAction); + _loadMapAction = new QAction(QIcon(QPixmap(OPEN_FILE_ICON)), tr("Load map"), + this); + connect(_loadMapAction, SIGNAL(triggered()), this, SLOT(loadMap())); _clearMapCacheAction = new QAction(tr("Clear tile cache"), this); connect(_clearMapCacheAction, SIGNAL(triggered()), this, SLOT(clearMapCache())); - if (_maps.empty()) { + createMapActions(); + _nextMapAction = new QAction(tr("Next map"), this); + _nextMapAction->setShortcut(NEXT_MAP_SHORTCUT); + connect(_nextMapAction, SIGNAL(triggered()), this, SLOT(nextMap())); + addAction(_nextMapAction); + _prevMapAction = new QAction(tr("Next map"), this); + _prevMapAction->setShortcut(PREV_MAP_SHORTCUT); + connect(_prevMapAction, SIGNAL(triggered()), this, SLOT(prevMap())); + addAction(_prevMapAction); + if (_ml->maps().isEmpty()) { _showMapAction->setEnabled(false); _clearMapCacheAction->setEnabled(false); - } else { - createMapActions(); - - _nextMapAction = new QAction(tr("Next map"), this); - _nextMapAction->setShortcut(NEXT_MAP_SHORTCUT); - connect(_nextMapAction, SIGNAL(triggered()), this, SLOT(nextMap())); - addAction(_nextMapAction); - _prevMapAction = new QAction(tr("Next map"), this); - _prevMapAction->setShortcut(PREV_MAP_SHORTCUT); - connect(_prevMapAction, SIGNAL(triggered()), this, SLOT(prevMap())); - addAction(_prevMapAction); } // Data actions @@ -484,12 +511,13 @@ void GUI::createMenus() fileMenu->addAction(_exitAction); #endif // Q_OS_MAC - QMenu *mapMenu = menuBar()->addMenu(tr("Map")); - mapMenu->addActions(_mapActions); - mapMenu->addSeparator(); - mapMenu->addAction(_clearMapCacheAction); - mapMenu->addSeparator(); - mapMenu->addAction(_showMapAction); + _mapMenu = menuBar()->addMenu(tr("Map")); + _mapMenu->addActions(_mapActions); + _mapsEnd = _mapMenu->addSeparator(); + _mapMenu->addAction(_loadMapAction); + _mapMenu->addAction(_clearMapCacheAction); + _mapMenu->addSeparator(); + _mapMenu->addAction(_showMapAction); QMenu *graphMenu = menuBar()->addMenu(tr("Graph")); graphMenu->addAction(_distanceGraphAction); @@ -1132,6 +1160,32 @@ void GUI::showGraphGrids(bool show) _tabs.at(i)->showGrid(show); } +void GUI::loadMap() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Load Map/Atlas"), + QString(), tr("Map/Atlas files (*.map *.tba *.tar)")); + + if (fileName.isEmpty()) + return; + + if (_ml->loadMap(fileName)) { + QAction *a = new QAction(_ml->maps().last()->name(), this); + a->setCheckable(true); + a->setActionGroup(_mapsActionGroup); + _mapsSignalMapper->setMapping(a, _ml->maps().size() - 1); + connect(a, SIGNAL(triggered()), _mapsSignalMapper, SLOT(map())); + _mapActions.append(a); + _mapMenu->insertAction(_mapsEnd, a); + _showMapAction->setEnabled(true); + _clearMapCacheAction->setEnabled(true); + a->activate(QAction::Trigger); + } else { + QString error = tr("Error loading map/atlas:") + "\n\n" + + fileName + "\n\n" + _ml->errorString(); + QMessageBox::critical(this, APP_NAME, error); + } +} + void GUI::clearMapCache() { _map->clearCache(); @@ -1178,26 +1232,27 @@ void GUI::updateWindowTitle() void GUI::mapChanged(int index) { - _map = _maps.at(index); + _map = _ml->maps().at(index); _pathView->setMap(_map); } void GUI::nextMap() { - if (_maps.count() < 2) + if (_ml->maps().count() < 2) return; - int next = (_maps.indexOf(_map) + 1) % _maps.count(); + int next = (_ml->maps().indexOf(_map) + 1) % _ml->maps().count(); _mapActions.at(next)->setChecked(true); mapChanged(next); } void GUI::prevMap() { - if (_maps.count() < 2) + if (_ml->maps().count() < 2) return; - int prev = (_maps.indexOf(_map) + _maps.count() - 1) % _maps.count(); + int prev = (_ml->maps().indexOf(_map) + _ml->maps().count() - 1) + % _ml->maps().count(); _mapActions.at(prev)->setChecked(true); mapChanged(prev); } @@ -1578,10 +1633,10 @@ void GUI::readSettings() settings.beginGroup(MAP_SETTINGS_GROUP); if (settings.value(SHOW_MAP_SETTING, SHOW_MAP_DEFAULT).toBool()) _showMapAction->setChecked(true); - if (_maps.count()) { + if (_ml->maps().count()) { int index = mapIndex(settings.value(CURRENT_MAP_SETTING).toString()); _mapActions.at(index)->setChecked(true); - _map = _maps.at(index); + _map = _ml->maps().at(index); _pathView->setMap(_map); } settings.endGroup(); @@ -1743,8 +1798,8 @@ void GUI::readSettings() int GUI::mapIndex(const QString &name) { - for (int i = 0; i < _maps.count(); i++) - if (_maps.at(i)->name() == name) + for (int i = 0; i < _ml->maps().count(); i++) + if (_ml->maps().at(i)->name() == name) return i; return 0; diff --git a/src/gui.h b/src/gui.h index 0898d51f..0b513ff5 100644 --- a/src/gui.h +++ b/src/gui.h @@ -13,6 +13,7 @@ #include "exportdialog.h" #include "optionsdialog.h" + class QMenu; class QToolBar; class QTabWidget; @@ -25,6 +26,7 @@ class FileBrowser; class GraphTab; class PathView; class Map; +class MapList; class GUI : public QMainWindow { @@ -53,6 +55,7 @@ private slots: void showFullscreen(bool show); void showTracks(bool show); void showRoutes(bool show); + void loadMap(); void clearMapCache(); void nextMap(); void prevMap(); @@ -129,9 +132,11 @@ private: QToolBar *_showToolBar; QToolBar *_navigationToolBar; QMenu *_poiFilesMenu; + QMenu *_mapMenu; QActionGroup *_fileActionGroup; QActionGroup *_navigationActionGroup; + QActionGroup *_mapsActionGroup; QAction *_exitAction; QAction *_keysAction; QAction *_dataSourcesAction; @@ -149,6 +154,7 @@ private: QAction *_showPOILabelsAction; QAction *_showMapAction; QAction *_fullscreenAction; + QAction *_loadMapAction; QAction *_clearMapCacheAction; QAction *_showGraphsAction; QAction *_showGraphGridAction; @@ -171,10 +177,12 @@ private: QAction *_showWaypointLabelsAction; QAction *_showRouteWaypointsAction; QAction *_openOptionsAction; + QAction *_mapsEnd; QList _mapActions; QList _poiFilesActions; - QSignalMapper *_poiFilesSM; + QSignalMapper *_poiFilesSignalMapper; + QSignalMapper *_mapsSignalMapper; QLabel *_fileNameLabel; QLabel *_distanceLabel; @@ -185,7 +193,7 @@ private: QList _tabs; POI *_poi; - QList _maps; + MapList *_ml; FileBrowser *_browser; QList _files; diff --git a/src/mapdir.cpp b/src/mapdir.cpp deleted file mode 100644 index 11efdc39..00000000 --- a/src/mapdir.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include "atlas.h" -#include "offlinemap.h" -#include "mapdir.h" - -QList MapDir::load(const QString &path, QObject *parent) -{ - QList maps; - QDir dir(path); - - - if (!dir.exists()) - return maps; - - if (!dir.isReadable()) { - qWarning("Map directory not readable: %s\n", qPrintable(path)); - return maps; - } - - QFileInfoList list = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); - for (int i = 0; i < list.size(); i++) { - QFileInfo fileInfo = list.at(i); - - Atlas *atlas = new Atlas(fileInfo.absoluteFilePath(), parent); - if (atlas->isValid()) - maps.append(atlas); - else { - delete atlas; - - OfflineMap *map = new OfflineMap(fileInfo.absoluteFilePath(), - parent); - if (map->isValid()) - maps.append(map); - else - delete map; - } - } - - return maps; -} diff --git a/src/mapdir.h b/src/mapdir.h deleted file mode 100644 index c36516e3..00000000 --- a/src/mapdir.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef MAPDIR_H -#define MAPDIR_H - -#include -#include - -class QObject; -class Map; - -class MapDir -{ -public: - static QList load(const QString &path, QObject *parent = 0); -}; - -#endif // MAPDIR_H diff --git a/src/maplist.cpp b/src/maplist.cpp index a2e4091b..6d305a9f 100644 --- a/src/maplist.cpp +++ b/src/maplist.cpp @@ -1,41 +1,100 @@ -#include #include +#include +#include "atlas.h" +#include "offlinemap.h" #include "onlinemap.h" #include "maplist.h" -QList MapList::load(const QString &fileName, QObject *parent) +bool MapList::loadListEntry(const QByteArray &line) { - QList maps; - QFileInfo fi(fileName); + QList list = line.split('\t'); + if (list.size() != 2) + return false; - if (!fi.exists()) - return maps; + QByteArray ba1 = list[0].trimmed(); + QByteArray ba2 = list[1].trimmed(); + if (ba1.isEmpty() || ba2.isEmpty()) + return false; - QFile file(fileName); + _maps.append(new OnlineMap(QString::fromUtf8(ba1.data(), ba1.size()), + QString::fromLatin1(ba2.data(), ba2.size()), this)); + + return true; +} + +bool MapList::loadList(const QString &path) +{ + QFile file(path); if (!file.open(QFile::ReadOnly | QFile::Text)) { - qWarning("Error opening map list file: %s: %s\n", - qPrintable(fileName), qPrintable(file.errorString())); - return maps; + _errorString = file.errorString(); + return false; } int ln = 0; while (!file.atEnd()) { ln++; QByteArray line = file.readLine(); - QList list = line.split('\t'); - if (list.size() != 2) { - qWarning("Invalid map list entry on line %d\n", ln); - continue; + + if (!loadListEntry(line)) { + _errorString = QString("Invalid map list entry on line %1.") + .arg(QString::number(ln)); + return false; } - - QByteArray ba1 = list[0].trimmed(); - QByteArray ba2 = list[1].trimmed(); - - maps.append(new OnlineMap(QString::fromUtf8(ba1.data(), ba1.size()), - QString::fromLatin1(ba2.data(), ba2.size()), parent)); } - return maps; + return true; +} + +bool MapList::loadMap(const QString &path) +{ + QFileInfo fi(path); + QString suffix = fi.suffix().toLower(); + + if (suffix == "map") { + OfflineMap *om = new OfflineMap(path, this); + if (om->isValid()) { + _maps.append(om); + return true; + } else { + _errorString = om->errorString(); + delete om; + return false; + } + } else if (suffix == "tba") { + Atlas *atlas = new Atlas(path, this); + if (atlas->isValid()) { + _maps.append(atlas); + return true; + } else { + _errorString = atlas->errorString(); + delete atlas; + return false; + } + } else if (suffix == "tar") { + Atlas *atlas = new Atlas(path, this); + if (atlas->isValid()) { + _maps.append(atlas); + return true; + } else { + _errorString = atlas->errorString(); + delete atlas; + OfflineMap *om = new OfflineMap(path, this); + if (om->isValid()) { + _maps.append(om); + return true; + } else { + qWarning("%s: %s", qPrintable(path), qPrintable(_errorString)); + qWarning("%s: %s", qPrintable(path), + qPrintable(om->errorString())); + _errorString = "Not a map/atlas file"; + delete om; + return false; + } + } + } else { + _errorString = "Not a map/atlas file"; + return false; + } } diff --git a/src/maplist.h b/src/maplist.h index e89df6cd..8960fdf2 100644 --- a/src/maplist.h +++ b/src/maplist.h @@ -1,16 +1,28 @@ #ifndef MAPLIST_H #define MAPLIST_H -#include +#include #include +#include "map.h" -class QObject; -class Map; - -class MapList +class MapList : public QObject { + Q_OBJECT + public: - static QList load(const QString &fileName, QObject *parent = 0); + MapList(QObject *parent = 0) : QObject(parent) {} + + bool loadMap(const QString &path); + bool loadList(const QString &path); + + QList &maps() {return _maps;} + const QString &errorString() const {return _errorString;} + +private: + bool loadListEntry(const QByteArray &line); + + QList _maps; + QString _errorString; }; #endif // MAPLIST_H diff --git a/src/offlinemap.cpp b/src/offlinemap.cpp index eebb3b8b..148d3382 100644 --- a/src/offlinemap.cpp +++ b/src/offlinemap.cpp @@ -46,7 +46,7 @@ static Coordinates toWGS84(Coordinates c, const Datum &datum) double adb = 1.0 / (1.0 - from_f); double rn = from_a / sqrt(1 - from_esq * ssqlat); double rm = from_a * (1 - from_esq) / pow((1 - from_esq * ssqlat), 1.5); - double from_h = 0.0; // we're flat! + double from_h = 0.0; double dlat = (-dX * slat * clon - dY * slat * slon + dZ * clat + da * rn * from_esq * slat * clat / from_a + +df * (rm * adb + rn / adb) * slat @@ -56,23 +56,22 @@ static Coordinates toWGS84(Coordinates c, const Datum &datum) return Coordinates(c.lon() + rad2deg(dlon), c.lat() + rad2deg(dlat)); } -int OfflineMap::parseMapFile(QIODevice &device, QList &points, + +int OfflineMap::parse(QIODevice &device, QList &points, QString &projection, ProjectionSetup &setup, QString &datum) { bool res; int ln = 1; - - if (!device.open(QIODevice::ReadOnly)) - return -1; - while (!device.atEnd()) { QByteArray line = device.readLine(); if (ln == 1) { if (!line.trimmed().startsWith("OziExplorer Map Data File")) return ln; - } else if (ln == 3) + } else if (ln == 2) + _name = line.trimmed(); + else if (ln == 3) _imgPath = line.trimmed(); else if (ln == 5) datum = line.split(',').at(0).trimmed(); @@ -173,19 +172,37 @@ int OfflineMap::parseMapFile(QIODevice &device, QList &points, return 0; } +bool OfflineMap::parseMapFile(QIODevice &device, QList &points, + QString &projection, ProjectionSetup &setup, QString &datum) +{ + int el; + + if (!device.open(QIODevice::ReadOnly)) { + _errorString = QString("Error opening map file: %1") + .arg(device.errorString()); + return false; + } + + if ((el = parse(device, points, projection, setup, datum))) { + _errorString = QString("Map file parse error on line %1").arg(el); + return false; + } + + return true; +} + bool OfflineMap::createProjection(const QString &datum, const QString &projection, const ProjectionSetup &setup, QList &points) { if (points.count() < 2) { - qWarning("%s: insufficient number of reference points", - qPrintable(_name)); + _errorString = "Insufficient number of reference points"; return false; } Datum d = Datum::datum(datum); if (d.isNull()) { - qWarning("%s: %s: unknown datum", qPrintable(_name), qPrintable(datum)); + _errorString = QString("%1: Unknown datum").arg(datum); return false; } @@ -208,12 +225,11 @@ bool OfflineMap::createProjection(const QString &datum, else if (!points.first().ll.isNull()) _projection = new UTM(d.ellipsoid(), points.first().ll); else { - qWarning("%s: Can not determine UTM zone", qPrintable(_name)); + _errorString = "Can not determine UTM zone"; return false; } } else { - qWarning("%s: %s: unsupported map projection", qPrintable(_name), - qPrintable(projection)); + _errorString = QString("%1: Unknown map projection").arg(projection); return false; } @@ -270,7 +286,7 @@ bool OfflineMap::computeTransformation(const QList &points) Matrix M = Q.augemented(c); if (!M.eliminate()) { - qWarning("%s: singular transformation matrix", qPrintable(_name)); + _errorString = "Singular transformation matrix"; return false; } @@ -327,17 +343,15 @@ bool OfflineMap::getImageInfo(const QString &path) if (ii.exists()) _imgPath = ii.absoluteFilePath(); else { - qWarning("%s: %s: No such image file", qPrintable(_name), - qPrintable(_imgPath)); + _errorString = QString("%1: No such image file").arg(_imgPath); return false; } - if (_imgPath.endsWith("ozf3", Qt::CaseInsensitive) - || _imgPath.endsWith("ozf4", Qt::CaseInsensitive)) { - qWarning("%s: %s: obfuscated image files are not supported", - qPrintable(_name), qPrintable(_imgPath)); + if (_imgPath.endsWith("ozf3") || _imgPath.endsWith("ozf4")) { + _errorString = QString("%1: Obfuscated image files not supported") + .arg(QFileInfo(_imgPath).fileName()); return false; - } else if (_imgPath.endsWith("ozf2", Qt::CaseInsensitive)) { + } else if (_imgPath.endsWith("ozf2")) { _ozf.load(_imgPath); _size = _ozf.size(); } else { @@ -345,8 +359,8 @@ bool OfflineMap::getImageInfo(const QString &path) _size = img.size(); } if (!_size.isValid()) { - qWarning("%s: %s: error reading map image", qPrintable(_name), - qPrintable(_imgPath)); + _errorString = QString("%1: Error reading map image") + .arg(QFileInfo(_imgPath).fileName()); return false; } @@ -356,7 +370,7 @@ bool OfflineMap::getImageInfo(const QString &path) bool OfflineMap::getTileInfo(const QStringList &tiles, const QString &path) { if (tiles.isEmpty()) { - qWarning("%s: empty tile set", qPrintable(_name)); + _errorString = "Empty tile set."; return false; } @@ -374,9 +388,8 @@ bool OfflineMap::getTileInfo(const QStringList &tiles, const QString &path) _tileSize = QImageReader(path + "/" + tiles.at(i)).size(); } if (!_tileSize.isValid()) { - qWarning("%s: error retrieving tile size: %s: invalid image", - qPrintable(_name), qPrintable(QFileInfo(tiles.at(i)) - .fileName())); + _errorString = QString("Error retrieving tile size: " + "%1: Invalid image").arg(QFileInfo(tiles.at(i)).fileName()); return false; } @@ -384,42 +397,26 @@ bool OfflineMap::getTileInfo(const QStringList &tiles, const QString &path) } } - qWarning("%s: invalid tile names", qPrintable(_name)); - + _errorString = "Invalid tile names"; return false; } -bool OfflineMap::mapLoaded(int res) -{ - if (res) { - if (res == -2) - qWarning("%s: no map file found", qPrintable(_name)); - else if (res == -1) - qWarning("%s: error opening map file", qPrintable(_name)); - else - qWarning("%s: map file parse error on line: %d", qPrintable(_name), - res); - return false; - } - - return true; -} - bool OfflineMap::totalSizeSet() { if (!_size.isValid()) { - qWarning("%s: missing total image size (IWH)", qPrintable(_name)); + _errorString = "Missing total image size (IWH)"; return false; } else return true; } -OfflineMap::OfflineMap(const QString &path, QObject *parent) : Map(parent) +OfflineMap::OfflineMap(const QString &fileName, QObject *parent) + : Map(parent) { - int errorLine = -2; QList points; QString proj, datum; ProjectionSetup setup; + QFileInfo fi(fileName); _valid = false; @@ -427,38 +424,29 @@ OfflineMap::OfflineMap(const QString &path, QObject *parent) : Map(parent) _projection = 0; _resolution = 0; - QFileInfo fi(path); - _name = fi.fileName(); - - QDir dir(path); - QFileInfoList mapFiles = dir.entryInfoList(QDir::Files); - for (int i = 0; i < mapFiles.count(); i++) { - const QString &fileName = mapFiles.at(i).fileName(); - if (fileName.endsWith(".tar")) { - if (!_tar.load(mapFiles.at(i).absoluteFilePath())) { - qWarning("%s: %s: error loading tar file", qPrintable(_name), - qPrintable(fileName)); - return; - } - QStringList tarFiles = _tar.files(); - for (int j = 0; j < tarFiles.size(); j++) { - if (tarFiles.at(j).endsWith(".map")) { - QByteArray ba = _tar.file(tarFiles.at(j)); - QBuffer buffer(&ba); - errorLine = parseMapFile(buffer, points, proj, setup, datum); - _imgPath = QString(); - break; - } - } - break; - } else if (fileName.endsWith(".map")) { - QFile mapFile(mapFiles.at(i).absoluteFilePath()); - errorLine = parseMapFile(mapFile, points, proj, setup, datum); - break; + if (fi.suffix() == "tar") { + if (!_tar.load(fileName)) { + _errorString = "Error reading tar file"; + return; } - } - if (!mapLoaded(errorLine)) + + QString mapFileName = fi.completeBaseName() + ".map"; + QByteArray ba = _tar.file(mapFileName); + if (ba.isNull()) { + _errorString = "Map file not found"; + return; + } + QBuffer mapFile(&ba); + if (!parseMapFile(mapFile, points, proj, setup, datum)) + return; + } else if (fi.suffix() =="map") { + QFile mapFile(fileName); + if (!parseMapFile(mapFile, points, proj, setup, datum)) + return; + } else { + _errorString = "Not a map file"; return; + } if (!createProjection(datum, proj, setup, points)) return; @@ -471,16 +459,17 @@ OfflineMap::OfflineMap(const QString &path, QObject *parent) : Map(parent) return; if (!getTileInfo(_tar.files())) return; + _imgPath = QString(); } else { - QDir set(fi.absoluteFilePath() + "/" + "set"); + QDir set(fi.absolutePath() + "/" + "set"); if (set.exists()) { if (!totalSizeSet()) return; - if (!getTileInfo(set.entryList(), set.canonicalPath())) + if (!getTileInfo(set.entryList(), set.absolutePath())) return; _imgPath = QString(); } else { - if (!getImageInfo(fi.absoluteFilePath())) + if (!getImageInfo(fi.absolutePath())) return; } } @@ -488,36 +477,31 @@ OfflineMap::OfflineMap(const QString &path, QObject *parent) : Map(parent) _valid = true; } -OfflineMap::OfflineMap(Tar &tar, const QString &path, QObject *parent) +OfflineMap::OfflineMap(const QString &fileName, Tar &tar, QObject *parent) : Map(parent) { - int errorLine = -2; QList points; QString proj, datum; ProjectionSetup setup; - + QFileInfo fi(fileName); _valid = false; _img = 0; _projection = 0; - QFileInfo fi(path); - _name = fi.fileName(); - - QFileInfo li(fi.absoluteDir().dirName()); - QString prefix = li.fileName() + "/" + fi.fileName() + "/"; - QStringList tarFiles = tar.files(); - for (int j = 0; j < tarFiles.size(); j++) { - if (tarFiles.at(j).startsWith(prefix)) { - QByteArray ba = tar.file(tarFiles.at(j)); - QBuffer buffer(&ba); - errorLine = parseMapFile(buffer, points, proj, setup, datum); - break; - } - } - if (!mapLoaded(errorLine)) + QFileInfo map(fi.absolutePath()); + QFileInfo layer(map.absolutePath()); + QString mapFile = layer.fileName() + "/" + map.fileName() + "/" + + fi.fileName(); + QByteArray ba = tar.file(mapFile); + if (ba.isNull()) { + _errorString = "Map file not found"; return; + } + QBuffer buffer(&ba); + if (!parseMapFile(buffer, points, proj, setup, datum)) + return; if (!createProjection(datum, proj, setup, points)) return; if (!totalSizeSet()) @@ -526,14 +510,8 @@ OfflineMap::OfflineMap(Tar &tar, const QString &path, QObject *parent) return; computeResolution(points); - QDir dir(path); - QFileInfoList mapFiles = dir.entryInfoList(QDir::Files); - for (int i = 0; i < mapFiles.count(); i++) { - const QString &fileName = mapFiles.at(i).absoluteFilePath(); - if (fileName.endsWith(".tar")) - _tarPath = fileName; - } + _tarPath = fi.absolutePath() + "/" + fi.completeBaseName() + ".tar"; _imgPath = QString(); _valid = true; } @@ -550,8 +528,7 @@ void OfflineMap::load() { if (!_tarPath.isNull() && !_tileSize.isValid()) { if (!_tar.load(_tarPath)) { - qWarning("%s: %s: error loading tar file", qPrintable(_name), - qPrintable(_tarPath)); + qWarning("%s: error loading tar file", qPrintable(_tarPath)); return; } getTileInfo(_tar.files()); diff --git a/src/offlinemap.h b/src/offlinemap.h index 460cc47e..7170b527 100644 --- a/src/offlinemap.h +++ b/src/offlinemap.h @@ -17,8 +17,8 @@ class OfflineMap : public Map Q_OBJECT public: - OfflineMap(const QString &path, QObject *parent = 0); - OfflineMap(Tar &tar, const QString &path, QObject *parent = 0); + OfflineMap(const QString &fileName, QObject *parent = 0); + OfflineMap(const QString &fileName, Tar &tar, QObject *parent = 0); ~OfflineMap(); const QString &name() const {return _name;} @@ -41,7 +41,8 @@ public: void load(); void unload(); - bool isValid() {return _valid;} + bool isValid() const {return _valid;} + const QString &errorString() const {return _errorString;} QPointF ll2pp(const Coordinates &c) const {return _projection->ll2xy(c);} @@ -68,9 +69,10 @@ private: int zone; } ProjectionSetup; - int parseMapFile(QIODevice &device, QList &points, + int parse(QIODevice &device, QList &points, + QString &projection, ProjectionSetup &setup, QString &datum); + bool parseMapFile(QIODevice &device, QList &points, QString &projection, ProjectionSetup &setup, QString &datum); - bool mapLoaded(int res); bool totalSizeSet(); bool createProjection(const QString &datum, const QString &projection, const ProjectionSetup &setup, QList &points); @@ -84,6 +86,9 @@ private: void drawImage(QPainter *painter, const QRectF &rect); QString _name; + bool _valid; + QString _errorString; + QSize _size; Projection *_projection; QTransform _transform, _inverted; @@ -96,8 +101,6 @@ private: QString _imgPath; QSize _tileSize; QString _tileName; - - bool _valid; }; #endif // OFFLINEMAP_H