1 /**********************************************************************************************
2     Copyright (C) 2014 Oliver Eichler <oliver.eichler@gmx.de>
3 
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 3 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 
17 **********************************************************************************************/
18 
19 #include "CMainWindow.h"
20 #include "map/CMapDraw.h"
21 #include "map/CMapItem.h"
22 #include "map/CMapList.h"
23 #include "misc.h"
24 
25 #include <QtWidgets>
26 
dragEnterEvent(QDragEnterEvent * e)27 void CMapTreeWidget::dragEnterEvent(QDragEnterEvent* e)
28 {
29     collapseAll();
30     QTreeWidget::dragEnterEvent(e);
31 }
32 
dragMoveEvent(QDragMoveEvent * e)33 void CMapTreeWidget::dragMoveEvent(QDragMoveEvent* e)
34 {
35     CMapItem* item = dynamic_cast<CMapItem*>(itemAt(e->pos()));
36 
37     if(item && item->isActivated())
38     {
39         e->setDropAction(Qt::MoveAction);
40         QTreeWidget::dragMoveEvent(e);
41     }
42     else
43     {
44         e->setDropAction(Qt::IgnoreAction);
45     }
46 }
47 
dropEvent(QDropEvent * e)48 void CMapTreeWidget::dropEvent(QDropEvent* e)
49 {
50     CMapItem* item = dynamic_cast<CMapItem*>(currentItem());
51     if(item)
52     {
53         item->showChildren(false);
54     }
55 
56     QTreeWidget::dropEvent(e);
57 
58     if(item)
59     {
60         item->showChildren(true);
61     }
62 
63     emit sigChanged();
64 }
65 
CMapList(QWidget * parent)66 CMapList::CMapList(QWidget* parent)
67     : QWidget(parent)
68 {
69     setupUi(this);
70     lineFilter->addAction(actionClearFilter, QLineEdit::TrailingPosition);
71 
72     connect(treeWidget, &CMapTreeWidget::customContextMenuRequested, this, &CMapList::slotContextMenu);
73     connect(treeWidget, &CMapTreeWidget::sigChanged, this, &CMapList::sigChanged);
74     connect(actionActivate, &QAction::triggered, this, &CMapList::slotActivate);
75     connect(actionMoveUp, &QAction::triggered, this, &CMapList::slotMoveUp);
76     connect(actionMoveDown, &QAction::triggered, this, &CMapList::slotMoveDown);
77     connect(actionReloadMaps, &QAction::triggered, this, &CMapList::slotReloadMaps);
78     connect(labelHelpFillMapList, &QLabel::linkActivated, &CMainWindow::self(), static_cast<void (CMainWindow::*)(const QString&)>(&CMainWindow::slotLinkActivated));
79     connect(lineFilter, &QLineEdit::textChanged, this, &CMapList::slotFilter);
80 
81     menu = new QMenu(this);
82     menu->addAction(actionActivate);
83     menu->addAction(actionMoveUp);
84     menu->addAction(actionMoveDown);
85     menu->addSeparator();
86     menu->addAction(actionReloadMaps);
87     menu->addAction(CMainWindow::self().getMapSetupAction());
88 }
89 
~CMapList()90 CMapList::~CMapList()
91 {
92 }
93 
clear()94 void CMapList::clear()
95 {
96     treeWidget->clear();
97 }
98 
99 
sort()100 void CMapList::sort()
101 {
102     QList<CMapItem*> items1;
103     while(treeWidget->topLevelItemCount())
104     {
105         CMapItem* item = dynamic_cast<CMapItem*>(treeWidget->takeTopLevelItem(0));
106         if(item != nullptr)
107         {
108             items1 << item;
109         }
110     }
111 
112     qSort(items1.begin(), items1.end(), &sortByName<CMapItem>);
113 
114     QList<QTreeWidgetItem*> items2;
115     for(CMapItem* item : qAsConst(items1))
116     {
117         items2 << item;
118     }
119     treeWidget->addTopLevelItems(items2);
120 }
121 
count()122 int CMapList::count()
123 {
124     return treeWidget->topLevelItemCount();
125 }
126 
item(int i)127 CMapItem* CMapList::item(int i)
128 {
129     return dynamic_cast<CMapItem*>(treeWidget->topLevelItem(i));
130 }
131 
updateHelpText()132 void CMapList::updateHelpText()
133 {
134     bool haveMaps = (treeWidget->topLevelItemCount() > 0);
135 
136     labelHelpFillMapList->setVisible(!haveMaps);
137 
138     if(!haveMaps)
139     {
140         labelIcon->show();
141         labelHelpActivateMap->hide();
142     }
143     else
144     {
145         CMapItem* item = dynamic_cast<CMapItem*>(treeWidget->topLevelItem(0));
146 
147         bool showHelp = !(item && item->isActivated());
148         labelIcon->setVisible(showHelp);
149         labelHelpActivateMap->setVisible(showHelp);
150     }
151 }
152 
slotActivate()153 void CMapList::slotActivate()
154 {
155     CMapItem* item = dynamic_cast<CMapItem*>(treeWidget->currentItem());
156     if(nullptr == item)
157     {
158         return;
159     }
160 
161     bool activated = item->toggleActivate();
162     if(!activated)
163     {
164         treeWidget->setCurrentItem(0);
165     }
166 
167     updateHelpText();
168 }
169 
slotMoveUp()170 void CMapList::slotMoveUp()
171 {
172     CMapItem* item = dynamic_cast<CMapItem*>(treeWidget->currentItem());
173     if(item == nullptr)
174     {
175         return;
176     }
177 
178     int index = treeWidget->indexOfTopLevelItem(item);
179     if(index == NOIDX)
180     {
181         return;
182     }
183 
184     item->showChildren(false);
185     treeWidget->takeTopLevelItem(index);
186     treeWidget->insertTopLevelItem(index - 1, item);
187     item->showChildren(true);
188     treeWidget->setCurrentItem(0);
189     emit treeWidget->sigChanged();
190 }
191 
slotMoveDown()192 void CMapList::slotMoveDown()
193 {
194     CMapItem* item = dynamic_cast<CMapItem*>(treeWidget->currentItem());
195     if(item == nullptr)
196     {
197         return;
198     }
199 
200     int index = treeWidget->indexOfTopLevelItem(item);
201     if(index == NOIDX)
202     {
203         return;
204     }
205 
206     item->showChildren(false);
207     treeWidget->takeTopLevelItem(index);
208     treeWidget->insertTopLevelItem(index + 1, item);
209     item->showChildren(true);
210     treeWidget->setCurrentItem(0);
211     emit treeWidget->sigChanged();
212 }
213 
slotContextMenu(const QPoint & point)214 void CMapList::slotContextMenu(const QPoint& point)
215 {
216     CMapItem* item = dynamic_cast<CMapItem*>(treeWidget->currentItem());
217 
218     bool itemIsSelected = nullptr != item;
219     bool itemIsActivated = item ? item->isActivated() : false;
220 
221     actionActivate->setEnabled(itemIsSelected);
222     actionMoveUp->setEnabled(itemIsSelected);
223     actionMoveDown->setEnabled(itemIsSelected);
224 
225     actionActivate->setChecked(itemIsActivated);
226     actionActivate->setText(itemIsActivated ? tr("Deactivate") : tr("Activate"));
227 
228     if(itemIsSelected)
229     {
230         CMapItem* item1 = dynamic_cast<CMapItem*>(treeWidget->itemBelow(item));
231         actionMoveUp->setEnabled(itemIsActivated && (treeWidget->itemAbove(item) != 0));
232         actionMoveDown->setEnabled(itemIsActivated && item1 && item1->isActivated());
233     }
234     QPoint p = treeWidget->mapToGlobal(point);
235     menu->exec(p);
236 }
237 
saveResource(const QString & name,QDir & dir)238 static void saveResource(const QString& name, QDir& dir)
239 {
240     QFile resource1(QString("://map/%1").arg(name));
241     resource1.open(QIODevice::ReadOnly);
242 
243     QFile file(dir.absoluteFilePath(name));
244     file.open(QIODevice::WriteOnly);
245     file.write(resource1.readAll());
246     file.close();
247 }
248 
slotMapHonk()249 void CMapList::slotMapHonk()
250 {
251     QString mapPath = CMainWindow::self().getMapsPath();
252     if(mapPath.isEmpty())
253     {
254         mapPath = QDir::homePath();
255     }
256 
257     mapPath = QFileDialog::getExistingDirectory(CMainWindow::getBestWidgetForParent(), tr("Where do you want to store maps?"), mapPath);
258     if(mapPath.isEmpty())
259     {
260         return;
261     }
262 
263     QDir dir(mapPath);
264 
265     saveResource("WorldSat.wmts", dir);
266     saveResource("WorldTopo.wmts", dir);
267     saveResource("OpenStreetMap.tms", dir);
268     saveResource("OSM_Topo.tms", dir);
269     saveResource("OpenCycleMap.tms", dir);
270 
271     CMapDraw::setupMapPath(mapPath);
272 
273     CCanvas* canvas = CMainWindow::self().getVisibleCanvas();
274     if(canvas)
275     {
276         canvas->setScales(CCanvas::eScalesSquare);
277     }
278 }
279 
slotReloadMaps()280 void CMapList::slotReloadMaps()
281 {
282     CMapDraw::setupMapPath(CMapDraw::getMapPaths());
283 }
284 
285 
slotFilter(const QString & str)286 void CMapList::slotFilter(const QString& str)
287 {
288     actionClearFilter->setIcon(str.isEmpty() ? QIcon("://icons/32x32/Filter.png") : QIcon("://icons/32x32/Cancel.png"));
289 
290     const int N = treeWidget->topLevelItemCount();
291 
292     if(str.isEmpty())
293     {
294         for(int n = 0; n < N; n++)
295         {
296             CMapItem* map = dynamic_cast<CMapItem*>(treeWidget->topLevelItem(n));
297             if(map == nullptr)
298             {
299                 continue;
300             }
301             map->setHidden(false);
302         }
303     }
304     else
305     {
306         const QString& tmp = str.toUpper();
307         for(int n = 0; n < N; n++)
308         {
309             CMapItem* map = dynamic_cast<CMapItem*>(treeWidget->topLevelItem(n));
310             if(map == nullptr)
311             {
312                 continue;
313             }
314 
315             map->setHidden(!map->getName().toUpper().contains(tmp));
316         }
317     }
318 }
319