1 /*
2  *    Copyright 2012, 2013 Thomas Schöps
3  *    Copyright 2012-2018 Kai Pastor
4  *
5  *    This file is part of OpenOrienteering.
6  *
7  *    OpenOrienteering is free software: you can redistribute it and/or modify
8  *    it under the terms of the GNU General Public License as published by
9  *    the Free Software Foundation, either version 3 of the License, or
10  *    (at your option) any later version.
11  *
12  *    OpenOrienteering is distributed in the hope that it will be useful,
13  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *    GNU General Public License for more details.
16  *
17  *    You should have received a copy of the GNU General Public License
18  *    along with OpenOrienteering.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 
22 #include "home_screen_widget.h"
23 
24 #include <QApplication> // IWYU pragma: keep
25 #include <QAbstractButton>
26 #include <QCheckBox>
27 #include <QCommandLinkButton>
28 #include <QDirIterator>
29 #include <QFileInfo>
30 #include <QLabel>
31 #include <QListWidget>
32 #include <QMessageBox>
33 #include <QPainter>
34 #include <QScroller>
35 #include <QSettings>
36 #include <QVBoxLayout>
37 
38 #include "settings.h"
39 #include "core/app_permissions.h"
40 #include "core/storage_location.h" // IWYU pragma: keep
41 #include "fileformats/file_format_registry.h"
42 #include "gui/home_screen_controller.h"
43 #include "gui/main_window.h"
44 #include "gui/settings_dialog.h"
45 #include "gui/util_gui.h"
46 
47 
48 namespace OpenOrienteering {
49 
50 //### AbstractHomeScreenWidget ###
51 
AbstractHomeScreenWidget(HomeScreenController * controller,QWidget * parent)52 AbstractHomeScreenWidget::AbstractHomeScreenWidget(HomeScreenController* controller, QWidget* parent)
53 : QWidget(parent),
54   controller(controller)
55 {
56 	Q_ASSERT(controller->getWindow());
57 }
58 
~AbstractHomeScreenWidget()59 AbstractHomeScreenWidget::~AbstractHomeScreenWidget()
60 {
61 	// nothing
62 }
63 
makeHeadline(const QString & text,QWidget * parent) const64 QLabel* AbstractHomeScreenWidget::makeHeadline(const QString& text, QWidget* parent) const
65 {
66 	QLabel* title_label = new QLabel(text, parent);
67 	QFont title_font = title_label->font();
68 	int pixel_size = title_font.pixelSize();
69 	if (pixel_size > 0)
70 	{
71 		title_font.setPixelSize(pixel_size * 2);
72 	}
73 	else
74 	{
75 		pixel_size = title_font.pointSize();
76 		title_font.setPointSize(pixel_size * 2);
77 	}
78 	title_font.setBold(true);
79 	title_label->setFont(title_font);
80 	title_label->setAlignment(Qt::AlignLeft | Qt::AlignTop);
81 	return title_label;
82 }
83 
makeButton(const QString & text,QWidget * parent) const84 QAbstractButton* AbstractHomeScreenWidget::makeButton(const QString& text, QWidget* parent) const
85 {
86 	QAbstractButton* button = new QCommandLinkButton(text, parent);
87 	QFont button_font = button->font();
88 	int pixel_size = button_font.pixelSize();
89 	if (pixel_size > 0)
90 	{
91 		button_font.setPixelSize(pixel_size * 3 / 2);
92 	}
93 	else
94 	{
95 		pixel_size = button_font.pointSize();
96 		button_font.setPointSize(pixel_size * 3 / 2);
97 	}
98 	button->setFont(button_font);
99 	return button;
100 }
101 
makeButton(const QString & text,const QIcon & icon,QWidget * parent) const102 QAbstractButton* AbstractHomeScreenWidget::makeButton(const QString& text, const QIcon& icon, QWidget* parent) const
103 {
104 	QAbstractButton* button = makeButton(text, parent);
105 	button->setIcon(icon);
106 	return button;
107 }
108 
109 
110 
111 //### HomeScreenWidgetDesktop ###
112 
HomeScreenWidgetDesktop(HomeScreenController * controller,QWidget * parent)113 HomeScreenWidgetDesktop::HomeScreenWidgetDesktop(HomeScreenController* controller, QWidget* parent)
114 : AbstractHomeScreenWidget(controller, parent)
115 {
116 	QLabel* title_label = new QLabel(QString::fromLatin1("<img src=\":/images/title.png\"/>"));
117 	title_label->setAlignment(Qt::AlignCenter);
118 	QWidget* menu_widget = makeMenuWidget(controller, parent);
119 	QWidget* recent_files_widget = makeRecentFilesWidget(controller, parent);
120 	QWidget* tips_widget = makeTipsWidget(controller, parent);
121 
122 	QGridLayout* layout = new QGridLayout();
123 	layout->setSpacing(2 * layout->spacing());
124 	layout->addWidget(title_label, 0, 0, 1, 2);
125 	layout->addWidget(menu_widget, 1, 0, 2, 1);
126 	layout->addWidget(recent_files_widget, 1, 1);
127 	layout->setRowStretch(1, 4);
128 	layout->addWidget(tips_widget, 2, 1);
129 	layout->setRowStretch(2, 3);
130 	setLayout(layout);
131 
132 	setAutoFillBackground(false);
133 }
134 
~HomeScreenWidgetDesktop()135 HomeScreenWidgetDesktop::~HomeScreenWidgetDesktop()
136 {
137 	// nothing
138 }
139 
makeMenuWidget(HomeScreenController * controller,QWidget * parent)140 QWidget* HomeScreenWidgetDesktop::makeMenuWidget(HomeScreenController* controller, QWidget* parent)
141 {
142 	MainWindow* window = controller->getWindow();
143 
144 	QVBoxLayout* menu_layout = new QVBoxLayout();
145 
146 	QLabel* menu_headline = makeHeadline(tr("Activities"));
147 	menu_layout->addWidget(menu_headline);
148 	QAbstractButton* button_new_map = makeButton(
149 	  tr("Create a new map ..."), QIcon(QString::fromLatin1(":/images/new.png")));
150 	menu_layout->addWidget(button_new_map);
151 	QAbstractButton* button_open_map = makeButton(
152 	  tr("Open map ..."), QIcon(QString::fromLatin1(":/images/open.png")));
153 	menu_layout->addWidget(button_open_map);
154 
155 	menu_layout->addStretch(1);
156 
157 	auto* button_touch = makeButton(tr("Touch mode"), QIcon{QLatin1String(":/images/tool-touch-cursor.png")});
158 	button_touch->setCheckable(true);
159 	button_touch->setChecked(Settings::getInstance().touchModeEnabled());
160 	menu_layout->addWidget(button_touch);
161 	QAbstractButton* button_settings = makeButton(
162 	  tr("Settings"), QIcon(QString::fromLatin1(":/images/settings.png")));
163 	menu_layout->addWidget(button_settings);
164 	QAbstractButton* button_about = makeButton(
165 	  tr("About %1", "As in 'About OpenOrienteering Mapper'").arg(window->appName()), QIcon(QString::fromLatin1(":/images/about.png")));
166 	menu_layout->addWidget(button_about);
167 	QAbstractButton* button_help = makeButton(
168 	  tr("Help"), QIcon(QString::fromLatin1(":/images/help.png")));
169 	menu_layout->addWidget(button_help);
170 	QAbstractButton* button_exit = makeButton(
171 	  tr("Exit"), QIcon(QString::fromLatin1(":/qt-project.org/styles/commonstyle/images/standardbutton-close-32.png"))); // From Qt5
172 	menu_layout->addWidget(button_exit);
173 
174 	connect(button_new_map, &QAbstractButton::clicked, window, &MainWindow::showNewMapWizard);
175 	connect(button_open_map, &QAbstractButton::clicked, window, &MainWindow::showOpenDialog);
176 	connect(button_touch, &QAbstractButton::toggled, this, [](bool enabled) { Settings::getInstance().setTouchModeEnabled(enabled); });
177 	connect(button_settings, &QAbstractButton::clicked, window, &MainWindow::showSettings);
178 	connect(button_about, &QAbstractButton::clicked, window, &MainWindow::showAbout);
179 	connect(button_help, &QAbstractButton::clicked, window, &MainWindow::showHelp);
180 	connect(button_exit, &QAbstractButton::clicked, qApp, &QApplication::closeAllWindows);
181 
182 	QWidget* menu_widget = new QWidget(parent);
183 	menu_widget->setLayout(menu_layout);
184 	menu_widget->setAutoFillBackground(true);
185 	return menu_widget;
186 }
187 
makeRecentFilesWidget(HomeScreenController * controller,QWidget * parent)188 QWidget* HomeScreenWidgetDesktop::makeRecentFilesWidget(HomeScreenController* controller, QWidget* parent)
189 {
190 	QGridLayout* recent_files_layout = new QGridLayout();
191 
192 	QLabel* recent_files_headline = makeHeadline(tr("Recent maps"));
193 	recent_files_layout->addWidget(recent_files_headline, 0, 0, 1, 2);
194 
195 	recent_files_list = new QListWidget();
196 	QFont list_font = recent_files_list->font();
197 	int pixel_size = list_font.pixelSize();
198 	if (pixel_size > 0)
199 	{
200 		list_font.setPixelSize(pixel_size * 3 / 2);
201 	}
202 	else
203 	{
204 		pixel_size = list_font.pointSize();
205 		list_font.setPointSize(pixel_size * 3 / 2);
206 	}
207 	recent_files_list->setFont(list_font);
208 	recent_files_list->setSpacing(pixel_size/2);
209 	recent_files_list->setCursor(Qt::PointingHandCursor);
210 	recent_files_list->setStyleSheet(QString::fromLatin1(" \
211 	  QListWidget::item:hover { \
212 	    color: palette(highlighted-text); \
213 	    background: palette(highlight); \
214 	  } "));
215 	recent_files_layout->addWidget(recent_files_list, 1, 0, 1, 2);
216 
217 	open_mru_file_check = new QCheckBox(tr("Open most recently used file on start"));
218 	recent_files_layout->addWidget(open_mru_file_check, 2, 0, 1, 1);
219 
220 	QPushButton* clear_list_button = new QPushButton(tr("Clear list"));
221 	recent_files_layout->addWidget(clear_list_button, 2, 1, 1, 1);
222 
223 	recent_files_layout->setRowStretch(1, 1);
224 	recent_files_layout->setColumnStretch(0, 1);
225 
226 	connect(recent_files_list, &QListWidget::itemClicked, this, &HomeScreenWidgetDesktop::recentFileClicked);
227 	connect(open_mru_file_check, &QAbstractButton::clicked, controller, &HomeScreenController::setOpenMRUFile);
228 	connect(clear_list_button, &QAbstractButton::clicked, controller, &HomeScreenController::clearRecentFiles);
229 
230 	QWidget* recent_files_widget = new QWidget(parent);
231 	recent_files_widget->setLayout(recent_files_layout);
232 	recent_files_widget->setAutoFillBackground(true);
233 	return recent_files_widget;
234 }
235 
makeTipsWidget(HomeScreenController * controller,QWidget * parent)236 QWidget* HomeScreenWidgetDesktop::makeTipsWidget(HomeScreenController* controller, QWidget* parent)
237 {
238 	QGridLayout* tips_layout = new QGridLayout();
239 	QWidget* tips_headline = makeHeadline(tr("Tip of the day"));
240 	tips_layout->addWidget(tips_headline, 0, 0, 1, 3);
241 	tips_label = new QLabel();
242 	tips_label->setWordWrap(true);
243 	tips_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
244 	tips_check = new QCheckBox(tr("Show tip of the day"));
245 	tips_check->setChecked(true);
246 	tips_layout->addWidget(tips_check, 2, 0, 1, 1);
247 	tips_layout->addWidget(tips_label, 1, 0, 1, 3);
248 	QPushButton* prev_button = new QPushButton(QIcon(QString::fromLatin1(":/images/arrow-left.png")), tr("Previous"));
249 	tips_layout->addWidget(prev_button, 2, 1, 1, 1);
250 	QPushButton* next_button = new QPushButton(QIcon(QString::fromLatin1(":/images/arrow-right.png")), tr("Next"));
251 	tips_layout->addWidget(next_button, 2, 2, 1, 1);
252 
253 	tips_layout->setRowStretch(1, 1);
254 	tips_layout->setColumnStretch(0, 1);
255 
256 	tips_children.reserve(4);
257 	tips_children.push_back(tips_headline);
258 	tips_children.push_back(tips_label);
259 	tips_children.push_back(prev_button);
260 	tips_children.push_back(next_button);
261 
262 	MainWindow* window = controller->getWindow();
263 	connect(tips_label, &QLabel::linkActivated, window, &MainWindow::linkClicked);
264 	connect(tips_check, &QAbstractButton::clicked, controller, &HomeScreenController::setTipsVisible);
265 	connect(prev_button, &QAbstractButton::clicked, controller, &HomeScreenController::goToPreviousTip);
266 	connect(next_button, &QAbstractButton::clicked, controller, &HomeScreenController::goToNextTip);
267 
268 	QWidget* tips_widget = new QWidget(parent);
269 	tips_widget->setLayout(tips_layout);
270 	tips_widget->setAutoFillBackground(true);
271 	return tips_widget;
272 }
273 
setRecentFiles(const QStringList & files)274 void HomeScreenWidgetDesktop::setRecentFiles(const QStringList& files)
275 {
276 	recent_files_list->clear();
277 	for (auto&& file : files)
278 	{
279 		QListWidgetItem* new_item = new QListWidgetItem(QFileInfo(file).fileName());
280 		new_item->setData(pathRole(), file);
281 		new_item->setToolTip(file);
282 		recent_files_list->addItem(new_item);
283 	}
284 }
285 
recentFileClicked(QListWidgetItem * item)286 void HomeScreenWidgetDesktop::recentFileClicked(QListWidgetItem* item)
287 {
288 	setEnabled(false);
289 	QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 100 /* ms */);
290 	QString path = item->data(pathRole()).toString();
291 	controller->getWindow()->openPath(path);
292 	setEnabled(true);
293 }
294 
paintEvent(QPaintEvent *)295 void HomeScreenWidgetDesktop::paintEvent(QPaintEvent*)
296 {
297 	// Background
298 	QPainter p(this);
299 	p.setPen(Qt::NoPen);
300 	p.setBrush(Qt::gray);
301 	p.drawRect(rect());
302 }
303 
setOpenMRUFileChecked(bool state)304 void HomeScreenWidgetDesktop::setOpenMRUFileChecked(bool state)
305 {
306 	open_mru_file_check->setChecked(state);
307 }
308 
setTipOfTheDay(const QString & text)309 void HomeScreenWidgetDesktop::setTipOfTheDay(const QString& text)
310 {
311 	tips_label->setText(text);
312 }
313 
setTipsVisible(bool state)314 void HomeScreenWidgetDesktop::setTipsVisible(bool state)
315 {
316 	QGridLayout* layout = qobject_cast<QGridLayout*>(this->layout());
317 	for (auto widget : tips_children)
318 	{
319 		widget->setVisible(state);
320 	}
321 	if (layout)
322 		layout->setRowStretch(2, state ? 3 : 0);
323 
324 	tips_check->setChecked(state);
325 }
326 
327 
328 
329 //### HomeScreenWidgetMobile ###
330 
HomeScreenWidgetMobile(HomeScreenController * controller,QWidget * parent)331 HomeScreenWidgetMobile::HomeScreenWidgetMobile(HomeScreenController* controller, QWidget* parent)
332 : AbstractHomeScreenWidget(controller, parent)
333 {
334 	auto* layout = new QVBoxLayout();
335 	layout->setSpacing(2 * layout->spacing());
336 
337 	title_pixmap = QPixmap::fromImage(QImage(QString::fromLatin1(":/images/title.png")));
338 	title_label = new QLabel();
339 	title_label->setPixmap(title_pixmap);
340 	title_label->setAlignment(Qt::AlignCenter);
341 	layout->addWidget(title_label);
342 
343 	file_list_widget = makeFileListWidget();
344 	connect(file_list_widget, &QListWidget::itemClicked, this, &HomeScreenWidgetMobile::itemClicked);
345 	layout->addWidget(file_list_widget, 1);
346 
347 	auto settings_button = new QPushButton(HomeScreenWidgetDesktop::tr("Settings"));
348 	connect(settings_button, &QPushButton::clicked, controller->getWindow(), &MainWindow::showSettings);
349 	QPushButton* help_button = new QPushButton(HomeScreenWidgetDesktop::tr("Help"));
350 	connect(help_button, &QPushButton::clicked, controller->getWindow(), &MainWindow::showHelp);
351 	QPushButton* about_button = new QPushButton(tr("About Mapper"));
352 	connect(about_button, &QPushButton::clicked, controller->getWindow(), &MainWindow::showAbout);
353 	QHBoxLayout* buttons_layout = new QHBoxLayout();
354 	buttons_layout->setContentsMargins(0, 0, 0, 0);
355 	buttons_layout->addWidget(settings_button);
356 	buttons_layout->addStretch(1);
357 	buttons_layout->addWidget(help_button);
358 	buttons_layout->addWidget(about_button);
359 	layout->addLayout(buttons_layout);
360 
361 	setLayout(layout);
362 	setAutoFillBackground(false);
363 
364 	updateFileListWidget();
365 }
366 
367 HomeScreenWidgetMobile::~HomeScreenWidgetMobile() = default;
368 
369 
resizeEvent(QResizeEvent *)370 void HomeScreenWidgetMobile::resizeEvent(QResizeEvent* /*event*/)
371 {
372 	adjustTitlePixmapSize();
373 }
374 
adjustTitlePixmapSize()375 void HomeScreenWidgetMobile::adjustTitlePixmapSize()
376 {
377 	auto label_size = title_label->size();
378 	auto scaled_width = qRound(title_pixmap.devicePixelRatio() * label_size.width());
379 	if (title_pixmap.width() > scaled_width)
380 	{
381 		if (title_label->pixmap()->width() != scaled_width)
382 		{
383 			label_size.setHeight(title_pixmap.height());
384 			title_label->setPixmap(title_pixmap.scaled(label_size, Qt::KeepAspectRatio, Qt::SmoothTransformation));
385 		}
386 	}
387 	else if (title_label->pixmap()->width() != title_pixmap.width())
388 	{
389 		title_label->setPixmap(title_pixmap);
390 	}
391 }
392 
setRecentFiles(const QStringList &)393 void HomeScreenWidgetMobile::setRecentFiles(const QStringList& /*files*/)
394 {
395 	// nothing
396 }
397 
setOpenMRUFileChecked(bool)398 void HomeScreenWidgetMobile::setOpenMRUFileChecked(bool /*state*/)
399 {
400 	// nothing
401 }
402 
setTipOfTheDay(const QString &)403 void HomeScreenWidgetMobile::setTipOfTheDay(const QString& /*text*/)
404 {
405 	// nothing
406 }
407 
setTipsVisible(bool)408 void HomeScreenWidgetMobile::setTipsVisible(bool /*state*/)
409 {
410 	// nothing
411 }
412 
showSettings()413 void HomeScreenWidgetMobile::showSettings()
414 {
415 	auto window = this->window();
416 
417 	SettingsDialog dialog(window);
418 	dialog.setGeometry(window->geometry());
419 	dialog.exec();
420 }
421 
itemClicked(QListWidgetItem * item)422 void HomeScreenWidgetMobile::itemClicked(QListWidgetItem* item)
423 {
424 	auto file_path = item->data(pathRole()).toString();
425 	auto hint = static_cast<StorageLocation::Hint>(item->data(hintRole()).toInt());
426 
427 	if (file_path == QLatin1String("doc:"))
428 	{
429 #ifdef Q_OS_ANDROID
430 		Util::showHelp(window(), "android-storage.html");
431 #endif
432 	}
433 	else if (file_path == QLatin1String(".."))
434 	{
435 		if (!history.empty())
436 			history.pop_back();
437 		updateFileListWidget();
438 	}
439 	else if (hint == StorageLocation::HintNoAccess)
440 	{
441 		AppPermissions::requestPermission(AppPermissions::StorageAccess, this, &HomeScreenWidgetMobile::permissionRequestDone);
442 	}
443 	else if (QFileInfo(file_path).isDir())
444 	{
445 		history.emplace_back(file_path, hint);
446 		updateFileListWidget();
447 	}
448 	else
449 	{
450 		setEnabled(false);
451 		if (hint != StorageLocation::HintNormal)
452 		{
453 			auto hint_text = StorageLocation::fileHintTextTemplate(hint);
454 			QMessageBox::warning(this, ::OpenOrienteering::MainWindow::tr("Warning"), hint_text.arg(item->data(Qt::DisplayRole).toString()));
455 		}
456 
457 		QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 100 /* ms */);
458 		controller->getWindow()->openPath(file_path);
459 		setEnabled(true);
460 	}
461 }
462 
permissionRequestDone()463 void HomeScreenWidgetMobile::permissionRequestDone()
464 {
465 	auto* item = file_list_widget->currentItem();
466 	if (AppPermissions::checkPermission(AppPermissions::StorageAccess) == AppPermissions::Granted
467 	    && item != nullptr)
468 	{
469 		// We only handle permissions for top-level storage locations.
470 		auto path = item->data(pathRole()).toString();
471 		StorageLocation::refresh();
472 		const auto locations = StorageLocation::knownLocations();
473 		for (const auto& location : *locations)
474 		{
475 			if (QFileInfo(location.path()).filePath() == path)
476 			{
477 				item->setData(hintRole(), location.hint());
478 				itemClicked(item);
479 				break;
480 			}
481 		}
482 	}
483 }
484 
makeFileListWidget()485 QListWidget* HomeScreenWidgetMobile::makeFileListWidget()
486 {
487 	file_list_widget = new QListWidget();
488 	QScroller::grabGesture(file_list_widget->viewport(), QScroller::TouchGesture);
489 	QFont list_font = file_list_widget->font();
490 	int pixel_size = list_font.pixelSize();
491 	if (pixel_size > 0)
492 	{
493 		list_font.setPixelSize(pixel_size * 3 / 2);
494 	}
495 	else
496 	{
497 		pixel_size = list_font.pointSize();
498 		list_font.setPointSize(pixel_size * 3 / 2);
499 	}
500 	file_list_widget->setFont(list_font);
501 	file_list_widget->setSpacing(pixel_size/2);
502 	file_list_widget->setCursor(Qt::PointingHandCursor);
503 	file_list_widget->setStyleSheet(QString::fromLatin1(" \
504 	  QListWidget::item:hover { \
505 	    color: palette(highlighted-text); \
506 	    background: palette(highlight); \
507 	  } "));
508 
509 	return file_list_widget;
510 }
511 
updateFileListWidget()512 void HomeScreenWidgetMobile::updateFileListWidget()
513 {
514 	file_list_widget->clear();
515 
516 	if (history.empty())
517 	{
518 		// First screen.
519 		// Recent files first.
520 		Settings& settings = Settings::getInstance();
521 		auto recent_files = settings.getSetting(Settings::General_RecentFilesList).toStringList();
522 		for (auto& file_path : recent_files)
523 		{
524 			auto file_info = QFileInfo(file_path);
525 			if (file_info.exists())
526 				addItemToFileList(file_info);
527 		}
528 
529 #ifdef Q_OS_ANDROID
530 		// If there are no recent files, offer a link to the Android storage manual page.
531 		if (file_list_widget->count() == 0)
532 		{
533 			auto* help_item = new QListWidgetItem(tr("Help"));
534 			help_item->setData(pathRole(), QLatin1String("doc:"));
535 			help_item->setIcon(file_list_widget->style()->standardIcon(QStyle::SP_DialogHelpButton));
536 			file_list_widget->addItem(help_item);
537 		}
538 #endif
539 
540 		// Device-specific locations next.
541 		// For disambiguation, using the full path for the label.
542 		StorageLocation::refresh();
543 		const auto locations = StorageLocation::knownLocations();
544 		for (const auto& location : *locations)
545 		{
546 			auto file_info = QFileInfo(location.path());
547 			auto icon = file_list_widget->style()->standardIcon(QStyle::SP_DirIcon);
548 			addItemToFileList(location.path(), file_info, location.hint(), icon);
549 		}
550 
551 		// Examples last.
552 		// The examples path isn't writable, so the hint will be overridden.
553 		auto file_info = QFileInfo(QLatin1String("data:/examples"));
554 		addItemToFileList(tr("Examples"), file_info);
555 	}
556 	else
557 	{
558 		// Backwards navigation on top.
559 		auto* parent_item = new QListWidgetItem(QLatin1String(".."));
560 		parent_item->setData(pathRole(), QLatin1String(".."));
561 		parent_item->setIcon(file_list_widget->style()->standardIcon(QStyle::SP_FileDialogToParent));
562 		file_list_widget->addItem(parent_item);
563 
564 		// Contents of selected location, files first.
565 		const auto& location = history.back();
566 		QIcon icon;
567 		switch (location.hint())
568 		{
569 		case StorageLocation::HintApplication:
570 			icon = file_list_widget->style()->standardIcon(QStyle::SP_MessageBoxInformation);
571 			break;
572 		case StorageLocation::HintReadOnly:
573 			icon = file_list_widget->style()->standardIcon(QStyle::SP_MessageBoxWarning);
574 			break;
575 		case StorageLocation::HintNormal:
576 		case StorageLocation::HintNoAccess:
577 		case StorageLocation::HintInvalid:
578 			break;
579 		}
580 
581 		constexpr auto filters = QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot;
582 		constexpr auto flags = QDir::DirsLast | QDir::Name | QDir::IgnoreCase | QDir::LocaleAware;
583 		auto const info_list = QDir(location.path()).entryInfoList(filters, flags);
584 		for (const auto& file_info : info_list)
585 		{
586 			addItemToFileList(file_info, location.hint(), icon);
587 		}
588 	}
589 }
590 
591 
addItemToFileList(const QFileInfo & file_info,int hint,const QIcon & icon)592 void HomeScreenWidgetMobile::addItemToFileList(const QFileInfo& file_info, int hint, const QIcon& icon)
593 {
594 	addItemToFileList(file_info.fileName(), file_info, hint, icon);
595 }
596 
addItemToFileList(const QString & label,const QFileInfo & file_info,int hint,const QIcon & icon)597 void HomeScreenWidgetMobile::addItemToFileList(const QString& label, const QFileInfo& file_info, int hint, const QIcon& icon)
598 {
599 	const auto file_path = file_info.filePath();
600 	if (hint == StorageLocation::HintNoAccess)
601 	{
602 		// When there is no access, avoid extra QFileInfo calls.
603 		auto* new_item = new QListWidgetItem(label);
604 		new_item->setData(pathRole(), file_path);
605 		new_item->setData(hintRole(), hint);
606 		new_item->setToolTip(StorageLocation::fileHintTextTemplate(StorageLocation::HintNoAccess).arg(file_path));
607 		new_item->setIcon(style()->standardIcon(QStyle::SP_MessageBoxQuestion));
608 		file_list_widget->addItem(new_item);
609 		return;
610 	}
611 
612 	const auto* format = FileFormats.findFormatForFilename(file_path, &FileFormat::supportsReading);
613 	if (file_info.isDir() ||
614 	    (format && format->fileType() == FileFormat::MapFile))
615 	{
616 		auto* new_item = new QListWidgetItem(label);
617 		new_item->setData(pathRole(), file_path);
618 		new_item->setData(hintRole(), hint);
619 		new_item->setToolTip(file_path);
620 		if (file_info.isDir())
621 		{
622 			// Use dir icon.
623 			new_item->setIcon(icon.isNull() ? file_list_widget->style()->standardIcon(QStyle::SP_DirIcon) : icon);
624 		}
625 		else if (hint == StorageLocation::HintReadOnly
626 		         || (file_info.isWritable() && format->supportsWriting()))
627 		{
628 			// Use icon as-is.
629 			new_item->setIcon(icon);
630 		}
631 		else
632 		{
633 			// Override with read-only warning.
634 			new_item->setData(hintRole(), StorageLocation::HintReadOnly);
635 			new_item->setIcon(file_list_widget->style()->standardIcon(QStyle::SP_MessageBoxWarning));
636 			new_item->setToolTip(StorageLocation::fileHintTextTemplate(StorageLocation::HintReadOnly).arg(file_path));
637 		}
638 		file_list_widget->addItem(new_item);
639 	}
640 }
641 
642 
643 }  // namespace OpenOrienteering
644