diff --git a/gpxsee.pro b/gpxsee.pro index c0fd7ab4..e8ecd1d9 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -30,6 +30,7 @@ HEADERS += src/common/config.h \ src/common/range.h \ src/common/rectc.h \ src/common/textcodec.h \ + src/common/treenode.h \ src/common/wgs84.h \ src/common/util.h \ src/common/rtree.h \ diff --git a/src/GUI/gui.cpp b/src/GUI/gui.cpp index 783dbf51..7a010be3 100644 --- a/src/GUI/gui.cpp +++ b/src/GUI/gui.cpp @@ -57,13 +57,15 @@ GUI::GUI() { + TreeNode mapActions; + loadPOIs(); createMapView(); createGraphTabs(); createStatusBar(); - createActions(); - createMenus(); + createActions(mapActions); + createMenus(mapActions); createToolBars(); createBrowser(); @@ -118,27 +120,40 @@ void GUI::createBrowser() _browser->setFilter(Data::filter()); } -void GUI::createMapActions() +TreeNode GUI::createMapActionsNode(const TreeNode &node) { - _mapsActionGroup = new QActionGroup(this); - _mapsActionGroup->setExclusive(true); + TreeNode tree(node.name()); - QString mapDir(ProgramPaths::mapDir()); - if (mapDir.isNull()) - return; + for (int i = 0; i < node.childs().size(); i++) + tree.addChild(createMapActionsNode(node.childs().at(i))); - QList maps(MapList::loadMaps(mapDir)); - for (int i = 0; i < maps.count(); i++) { - Map *map = maps.at(i); + for (int i = 0; i < node.items().size(); i++) { + Map *map = node.items().at(i); if (map->isValid()) { MapAction *a = createMapAction(map); connect(a, SIGNAL(loaded()), this, SLOT(mapInitialized())); + tree.addItem(a); } else { qWarning("%s: %s", qPrintable(map->path()), qPrintable(map->errorString())); delete map; } } + + return tree; +} + +TreeNode GUI::createMapActions() +{ + _mapsActionGroup = new QActionGroup(this); + _mapsActionGroup->setExclusive(true); + + QString mapDir(ProgramPaths::mapDir()); + if (mapDir.isNull()) + return TreeNode(); + + TreeNode maps(MapList::loadMaps(mapDir)); + return createMapActionsNode(maps); } MapAction *GUI::createMapAction(Map *map) @@ -195,7 +210,7 @@ QAction *GUI::createPOIFileAction(const QString &fileName) return a; } -void GUI::createActions() +void GUI::createActions(TreeNode &mapActions) { QActionGroup *ag; @@ -300,7 +315,7 @@ void GUI::createActions() createPOIFilesActions(); // Map actions - createMapActions(); + mapActions = createMapActions(); _showMapAction = new QAction(QIcon(SHOW_MAP_ICON), tr("Show map"), this); _showMapAction->setEnabled(false); @@ -523,7 +538,19 @@ void GUI::createActions() connect(_firstAction, SIGNAL(triggered()), this, SLOT(first())); } -void GUI::createMenus() +void GUI::createMapNodeMenu(const TreeNode &node, QMenu *menu) +{ + for (int i = 0; i < node.childs().size(); i++) { + QMenu *cm = new QMenu(node.childs().at(i).name(), menu); + menu->addMenu(cm); + createMapNodeMenu(node.childs().at(i), cm); + } + + for (int i = 0; i < node.items().size(); i++) + menu->addAction(node.items().at(i)); +} + +void GUI::createMenus(const TreeNode &mapActions) { QMenu *fileMenu = menuBar()->addMenu(tr("&File")); fileMenu->addAction(_openFileAction); @@ -542,7 +569,7 @@ void GUI::createMenus() #endif // Q_OS_MAC _mapMenu = menuBar()->addMenu(tr("&Map")); - _mapMenu->addActions(_mapsActionGroup->actions()); + createMapNodeMenu(mapActions, _mapMenu); _mapsEnd = _mapMenu->addSeparator(); _mapMenu->addAction(_loadMapAction); _mapMenu->addAction(_loadMapDirAction); @@ -1500,15 +1527,18 @@ static MapAction *findMapAction(const QList &mapActions, return 0; } -bool GUI::loadMap(const QString &fileName, MapAction *&action, bool silent) +bool GUI::loadMapNode(const TreeNode &node, MapAction *&action, + bool silent, const QList &existingActions) { - QList maps(MapList::loadMaps(fileName)); - QList existingActions(_mapsActionGroup->actions()); - MapAction *lastReady = 0; bool valid = false; - for (int i = 0; i < maps.size(); i++) { - Map *map = maps.at(i); + action = 0; + + for (int i = 0; i < node.childs().size(); i++) + valid = loadMapNode(node.childs().at(i), action, silent, existingActions); + + for (int i = 0; i < node.items().size(); i++) { + Map *map = node.items().at(i); MapAction *a; if (!(a = findMapAction(existingActions, map))) { @@ -1524,7 +1554,7 @@ bool GUI::loadMap(const QString &fileName, MapAction *&action, bool silent) _mapMenu->insertAction(_mapsEnd, a); if (map->isReady()) { - lastReady = a; + action = a; _showMapAction->setEnabled(true); _clearMapCacheAction->setEnabled(true); } else @@ -1534,15 +1564,21 @@ bool GUI::loadMap(const QString &fileName, MapAction *&action, bool silent) valid = true; map = a->data().value(); if (map->isReady()) - lastReady = a; + action = a; } } - action = lastReady; - return valid; } +bool GUI::loadMap(const QString &fileName, MapAction *&action, bool silent) +{ + TreeNode maps(MapList::loadMaps(fileName)); + QList existingActions(_mapsActionGroup->actions()); + + return loadMapNode(maps, action, silent, existingActions); +} + void GUI::mapLoaded() { MapAction *action = static_cast(QObject::sender()); @@ -1579,21 +1615,17 @@ void GUI::mapLoadedDir() } } -void GUI::loadMapDir() +void GUI::loadMapDirNode(const TreeNode &node, QList &actions, + QMenu *menu, const QList &existingActions) { - QString dir(QFileDialog::getExistingDirectory(this, - tr("Select map directory"), _mapDir, QFileDialog::ShowDirsOnly)); - if (dir.isEmpty()) - return; + for (int i = 0; i < node.childs().size(); i++) { + QMenu *cm = new QMenu(node.childs().at(i).name(), menu); + menu->addMenu(cm); + loadMapDirNode(node.childs().at(i), actions, cm, existingActions); + } - QList maps(MapList::loadMaps(dir)); - QList actions; - QList existingActions(_mapsActionGroup->actions()); - QFileInfo fi(dir); - QMenu *menu = new QMenu(fi.fileName()); - - for (int i = 0; i < maps.size(); i++) { - Map *map = maps.at(i); + for (int i = 0; i < node.items().size(); i++) { + Map *map = node.items().at(i); MapAction *a; if (!(a = findMapAction(existingActions, map))) { @@ -1612,24 +1644,39 @@ void GUI::loadMapDir() } else connect(a, SIGNAL(loaded()), this, SLOT(mapLoadedDir())); } + + _areaCount++; } else { map = a->data().value(); if (map->isReady()) actions.append(a); } } +} + +void GUI::loadMapDir() +{ + QString dir(QFileDialog::getExistingDirectory(this, + tr("Select map directory"), _mapDir, QFileDialog::ShowDirsOnly)); + if (dir.isEmpty()) + return; + + QFileInfo fi(dir); + TreeNode maps(MapList::loadMaps(dir)); + QList existingActions(_mapsActionGroup->actions()); + QList actions; + QMenu *menu = new QMenu(maps.name()); + + loadMapDirNode(maps, actions, menu, existingActions); _mapView->loadMaps(actions); if (menu->isEmpty()) delete menu; - else { - menu->setStyleSheet("QMenu { menu-scrollable: 1; }"); + else _mapMenu->insertMenu(_mapsEnd, menu); - } _mapDir = fi.absolutePath(); - _areaCount += maps.size(); _fileActionGroup->setEnabled(true); _reloadFileAction->setEnabled(false); } diff --git a/src/GUI/gui.h b/src/GUI/gui.h index e6687768..6b027eb2 100644 --- a/src/GUI/gui.h +++ b/src/GUI/gui.h @@ -6,6 +6,7 @@ #include #include #include +#include "common/treenode.h" #include "data/graph.h" #include "units.h" #include "timetype.h" @@ -113,9 +114,11 @@ private: QAction *createPOIFileAction(const QString &fileName); MapAction *createMapAction(Map *map); void createPOIFilesActions(); - void createMapActions(); - void createActions(); - void createMenus(); + TreeNode createMapActionsNode(const TreeNode &node); + TreeNode createMapActions(); + void createActions(TreeNode &mapActions); + void createMapNodeMenu(const TreeNode &node, QMenu *menu); + void createMenus(const TreeNode &mapActions); void createToolBars(); void createStatusBar(); void createMapView(); @@ -125,6 +128,10 @@ private: bool openPOIFile(const QString &fileName); bool loadFile(const QString &fileName, bool silent = false); void loadData(const Data &data); + bool loadMapNode(const TreeNode &node, MapAction *&action, + bool silent, const QList &existingActions); + void loadMapDirNode(const TreeNode &node, QList &actions, + QMenu *menu, const QList &existingActions); void updateStatusBarInfo(); void updateWindowTitle(); void updateNavigationActions(); diff --git a/src/common/treenode.h b/src/common/treenode.h new file mode 100644 index 00000000..ba182302 --- /dev/null +++ b/src/common/treenode.h @@ -0,0 +1,29 @@ +#ifndef TREENODE_H +#define TREENODE_H + +#include +#include + +template +class TreeNode +{ +public: + TreeNode() {} + TreeNode(const QString &name) : _name(name) {} + + const QString &name() const {return _name;} + const QList &childs() const {return _childs;} + const QList &items() const {return _items;} + + void addItem(T node) {_items.append(node);} + void addChild(const TreeNode &child) {_childs.append(child);} + + bool isEmpty() const {return _childs.isEmpty() && _items.isEmpty();} + +private: + QString _name; + QList _childs; + QList _items; +}; + +#endif // TREENODE_H diff --git a/src/map/maplist.cpp b/src/map/maplist.cpp index 80f7d365..8d5bde91 100644 --- a/src/map/maplist.cpp +++ b/src/map/maplist.cpp @@ -18,23 +18,23 @@ #include "maplist.h" -Map *MapList::loadFile(const QString &path, bool *terminate) +Map *MapList::loadFile(const QString &path, bool *isDir) { QFileInfo fi(path); QString suffix = fi.suffix().toLower(); Map *map = 0; if (Atlas::isAtlas(path)) { - if (terminate) - *terminate = true; + if (isDir) + *isDir = true; map = new Atlas(path); } else if (suffix == "xml") { if (MapSource::isMap(path)) { map = MapSource::loadMap(path); } else if (GMAP::isGMAP(path)) { map = new IMGMap(path); - if (terminate) - *terminate = true; + if (isDir) + *isDir = true; } } else if (suffix == "jnx") map = new JNXMap(path); @@ -60,39 +60,44 @@ Map *MapList::loadFile(const QString &path, bool *terminate) return map ? map : new InvalidMap(path, "Unknown file format"); } -QList MapList::loadDir(const QString &path) +TreeNode MapList::loadDir(const QString &path, TreeNode *parent) { QDir md(path); md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); md.setSorting(QDir::DirsLast); QFileInfoList ml = md.entryInfoList(); - QList list; + TreeNode tree(md.dirName()); for (int i = 0; i < ml.size(); i++) { const QFileInfo &fi = ml.at(i); QString suffix = fi.suffix().toLower(); - bool terminate = false; - if (fi.isDir() && fi.fileName() != "set") - list.append(loadDir(fi.absoluteFilePath())); - else if (filter().contains("*." + suffix)) { - list.append(loadFile(fi.absoluteFilePath(), &terminate)); - if (terminate) + if (fi.isDir()) { + TreeNode child(loadDir(fi.absoluteFilePath(), &tree)); + if (!child.isEmpty()) + tree.addChild(child); + } else if (filter().contains("*." + suffix)) { + bool isDir = false; + Map *map = loadFile(fi.absoluteFilePath(), &isDir); + if (isDir) { + parent->addItem(map); break; + } else + tree.addItem(map); } } - return list; + return tree; } -QList MapList::loadMaps(const QString &path) +TreeNode MapList::loadMaps(const QString &path) { if (QFileInfo(path).isDir()) return loadDir(path); else { - QList list; - list.append(loadFile(path, 0)); - return list; + TreeNode tree; + tree.addItem(loadFile(path)); + return tree; } } diff --git a/src/map/maplist.h b/src/map/maplist.h index 37a8d21b..115b18a2 100644 --- a/src/map/maplist.h +++ b/src/map/maplist.h @@ -2,19 +2,21 @@ #define MAPLIST_H #include +#include "common/treenode.h" class Map; class MapList { public: - static QList loadMaps(const QString &path); + static TreeNode loadMaps(const QString &path); static QString formats(); static QStringList filter(); private: - static Map *loadFile(const QString &path, bool *terminate); - static QList loadDir(const QString &path); + static Map *loadFile(const QString &path, bool *isDir = 0); + static TreeNode loadDir(const QString &path, + TreeNode *parent = 0); }; #endif // MAPLIST_H