# HG changeset patch
# User Zalewa <zalewapl@gmail.com>
# Date 1509281201 -3600
#      Sun Oct 29 13:46:41 2017 +0100
# Node ID cb114b95e71b3a6590b023e4d741f236c4d93cc7
# Parent  33e6ab19ce75772b2b75156ba0a725014aa62f8a
- Basic themes implementation; currently only affects the buddies icon.

diff -r 33e6ab19ce75 -r cb114b95e71b src/core/CMakeFileListing.cmake
--- a/src/core/CMakeFileListing.cmake	Sat Oct 28 21:04:37 2017 -0400
+++ b/src/core/CMakeFileListing.cmake	Sun Oct 29 13:46:41 2017 +0100
@@ -142,6 +142,7 @@
 	gui/serverfilterdock.h
 	gui/serverlist.h
 	gui/standardserverconsole.h
+	gui/theme.h
 	gui/wadseekerinterface.h
 	gui/wadseekershow.h
 	gui/widgets/colorbutton.h
@@ -369,6 +370,7 @@
 	gui/serverfilterdock.cpp
 	gui/serverlist.cpp
 	gui/standardserverconsole.cpp
+	gui/theme.cpp
 	gui/wadseekerinterface.cpp
 	gui/wadseekershow.cpp
 	gui/widgets/colorbutton.cpp
diff -r 33e6ab19ce75 -r cb114b95e71b src/core/configuration/doomseekerconfig.cpp
--- a/src/core/configuration/doomseekerconfig.cpp	Sat Oct 28 21:04:37 2017 -0400
+++ b/src/core/configuration/doomseekerconfig.cpp	Sun Oct 29 13:46:41 2017 +0100
@@ -276,6 +276,7 @@
 	this->slotStyle = 1;
 	this->serverListSortIndex = -1;
 	this->serverListSortDirection = Qt::DescendingOrder;
+	this->theme = "default";
 	this->wadPaths << gDefaultDataPaths->programsDataDirectoryPath();
 	this->wadPaths << gDefaultDataPaths->workingDirectory();
 }
@@ -335,6 +336,7 @@
 	section.createSetting("SlotStyle", this->slotStyle);
 	section.createSetting("ServerListSortIndex", this->serverListSortIndex);
 	section.createSetting("ServerListSortDirection", this->serverListSortDirection);
+	section.createSetting("Theme", this->theme);
 	section.createSetting("WadPaths", FileSearchPath::toVariantList(this->wadPaths));
 
 	initWadAlias();
@@ -383,6 +385,7 @@
 	this->serverListSortIndex = section["ServerListSortIndex"];
 	this->serverListSortDirection = section["ServerListSortDirection"];
 	this->slotStyle = d->slotStyle();
+	this->theme = section["Theme"];
 
 	// Complex data variables.
 
@@ -451,6 +454,7 @@
 	section["ServerListSortIndex"] = this->serverListSortIndex;
 	section["ServerListSortDirection"] = this->serverListSortDirection;
 	section["SlotStyle"] = this->slotStyle;
+	section["Theme"] = this->theme;
 
 	// Complex data variables.
 
diff -r 33e6ab19ce75 -r cb114b95e71b src/core/configuration/doomseekerconfig.h
--- a/src/core/configuration/doomseekerconfig.h	Sat Oct 28 21:04:37 2017 -0400
+++ b/src/core/configuration/doomseekerconfig.h	Sun Oct 29 13:46:41 2017 +0100
@@ -92,6 +92,7 @@
 			int serverListSortIndex;
 			int serverListSortDirection;
 			QString slotStyle;
+			QString theme;
 			QList<FileSearchPath> wadPaths;
 
 			DoomseekerCfg();
diff -r 33e6ab19ce75 -r cb114b95e71b src/core/datapaths.cpp
--- a/src/core/datapaths.cpp	Sat Oct 28 21:04:37 2017 -0400
+++ b/src/core/datapaths.cpp	Sun Oct 29 13:46:41 2017 +0100
@@ -26,6 +26,7 @@
 #include "plugins/engineplugin.h"
 #include "strings.hpp"
 #include <QDesktopServices>
+#include <QFileInfo>
 #include <QProcessEnvironment>
 #include <cassert>
 #include <cstdlib>
@@ -53,9 +54,23 @@
 
 DPointered(DataPaths)
 
+static QStringList uniquePaths(const QStringList &paths)
+{
+	QList<QFileInfo> uniqueMarkers;
+	QStringList result;
+	foreach (const QString &path, paths)
+	{
+		if (!uniqueMarkers.contains(path))
+		{
+			uniqueMarkers << path;
+			result << path;
+		}
+	}
+	return result;
+}
+
 DataPaths *DataPaths::staticDefaultInstance = NULL;
 
-
 #ifdef Q_OS_MAC
 const QString DataPaths::PROGRAMS_APPDATA_DIR_NAME = "Library/Preferences/Doomseeker";
 const QString DataPaths::PROGRAMS_APPDATASUPPORT_DIR_NAME = "Library/Application Support/Doomseeker";
@@ -69,6 +84,8 @@
 const QString DataPaths::TRANSLATIONS_DIR_NAME = "translations";
 const QString DataPaths::UPDATE_PACKAGES_DIR_NAME = "updates";
 const QString DataPaths::UPDATE_PACKAGE_FILENAME_PREFIX = "doomseeker-update-pkg-";
+const QString DataPaths::THEME_APPEARANCE_DIR = "theme/appearance";
+const QString DataPaths::THEME_SLOTS_DIR = "theme/slots";
 
 DataPaths::DataPaths(bool bPortableModeOn)
 {
@@ -315,12 +332,13 @@
 
 QStringList DataPaths::staticDataSearchDirs(const QString& subdir)
 {
-	QStringList paths;
-	paths.append(QDir::currentPath()); // current working dir
-	paths.append(QCoreApplication::applicationDirPath()); // where exe is located
+	QStringList pathCandidates;
+	pathCandidates.append(QDir::currentPath()); // current working dir
+	pathCandidates.append(QCoreApplication::applicationDirPath()); // where exe is located
 #ifndef Q_OS_WIN32
-	paths.append(INSTALL_PREFIX "/share/doomseeker"); // standard arch independent linux path
+	pathCandidates.append(INSTALL_PREFIX "/share/doomseeker"); // standard arch independent linux path
 #endif
+	QStringList paths = uniquePaths(pathCandidates);
 	QString subdirFiltered = subdir.trimmed();
 	if (!subdirFiltered.isEmpty())
 	{
diff -r 33e6ab19ce75 -r cb114b95e71b src/core/datapaths.h
--- a/src/core/datapaths.h	Sat Oct 28 21:04:37 2017 -0400
+++ b/src/core/datapaths.h	Sun Oct 29 13:46:41 2017 +0100
@@ -92,6 +92,8 @@
 		static const QString PROGRAMS_APPDATASUPPORT_DIR_NAME;
 		static const QString DEMOS_DIR_NAME;
 		static const QString CHATLOGS_DIR_NAME;
+		static const QString THEME_APPEARANCE_DIR;
+		static const QString THEME_SLOTS_DIR;
 		static const QString TRANSLATIONS_DIR_NAME;
 		static const QString UPDATE_PACKAGES_DIR_NAME;
 		static const QString UPDATE_PACKAGE_FILENAME_PREFIX;
diff -r 33e6ab19ce75 -r cb114b95e71b src/core/gui/dockBuddiesList.cpp
--- a/src/core/gui/dockBuddiesList.cpp	Sat Oct 28 21:04:37 2017 -0400
+++ b/src/core/gui/dockBuddiesList.cpp	Sun Oct 29 13:46:41 2017 +0100
@@ -24,6 +24,7 @@
 #include "ui_addBuddyDlg.h"
 #include "ui_dockBuddiesList.h"
 #include "configuration/doomseekerconfig.h"
+#include "gui/theme.h"
 #include "serverapi/mastermanager.h"
 #include "serverapi/playerslist.h"
 #include "serverapi/server.h"
@@ -74,7 +75,7 @@
 : QDockWidget(parent), masterClient(NULL), save(false)
 {
 	d->setupUi(this);
-	this->toggleViewAction()->setIcon(QIcon(":/icons/buddies.png"));
+	this->toggleViewAction()->setIcon(Theme::main.icon("icons/buddies.png"));
 
 	// Set up the model
 	d->buddiesTableModel = new QStandardItemModel();
diff -r 33e6ab19ce75 -r cb114b95e71b src/core/gui/helpers/playersdiagram.cpp
--- a/src/core/gui/helpers/playersdiagram.cpp	Sat Oct 28 21:04:37 2017 -0400
+++ b/src/core/gui/helpers/playersdiagram.cpp	Sun Oct 29 13:46:41 2017 +0100
@@ -244,5 +244,5 @@
 
 QStringList PlayersDiagram::stylePaths()
 {
-	return gDefaultDataPaths->staticDataSearchDirs("theme/slots");
+	return gDefaultDataPaths->staticDataSearchDirs(DataPaths::THEME_SLOTS_DIR);
 }
diff -r 33e6ab19ce75 -r cb114b95e71b src/core/gui/mainwindow.cpp
--- a/src/core/gui/mainwindow.cpp	Sat Oct 28 21:04:37 2017 -0400
+++ b/src/core/gui/mainwindow.cpp	Sun Oct 29 13:46:41 2017 +0100
@@ -44,6 +44,7 @@
 #include "gui/serverdetailsdock.h"
 #include "gui/serverfilterdock.h"
 #include "gui/serverlist.h"
+#include "gui/theme.h"
 #include "gui/wadseekerinterface.h"
 #include "gui/wadseekershow.h"
 #include "ip2c/ip2cloader.h"
@@ -202,8 +203,9 @@
 	d->connectionHandler = NULL;
 	d->updateChannelOnUpdateStart = new UpdateChannel();
 	d->updaterInstallerErrorCode = 0;
+	d->application = application;
 
-	d->application = application;
+	setupTheme();
 
 	this->setAttribute(Qt::WA_DeleteOnClose, true);
 	d->setupUi(this);
@@ -1398,6 +1400,11 @@
 	d->menuActionAbout->setIcon(style.standardIcon(QStyle::SP_MessageBoxInformation));
 }
 
+void MainWindow::setupTheme()
+{
+	Theme::main = Theme(gConfig.doomseeker.theme.trimmed());
+}
+
 void MainWindow::setupToolBar()
 {
 	QToolBar* pToolBar = new QToolBar(tr("Main Toolbar"), this);
diff -r 33e6ab19ce75 -r cb114b95e71b src/core/gui/mainwindow.h
--- a/src/core/gui/mainwindow.h	Sat Oct 28 21:04:37 2017 -0400
+++ b/src/core/gui/mainwindow.h	Sun Oct 29 13:46:41 2017 +0100
@@ -235,6 +235,7 @@
 
 		void connectIP2CLoader(IP2CLoader* loader);
 		void fixIconsDpi();
+		void setupTheme();
 
 	private slots:
 		void ip2cDownloadProgress(qint64 current, qint64 max);
diff -r 33e6ab19ce75 -r cb114b95e71b src/core/gui/theme.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/gui/theme.cpp	Sun Oct 29 13:46:41 2017 +0100
@@ -0,0 +1,75 @@
+//------------------------------------------------------------------------------
+// theme.cpp
+//------------------------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301  USA
+//
+//------------------------------------------------------------------------------
+// Copyright (C) 2017 "Zalewa" <zalewapl@gmail.com>
+//------------------------------------------------------------------------------
+#include "theme.h"
+
+#include "datapaths.h"
+#include "strings.hpp"
+#include <QFile>
+#include <QStringList>
+
+Theme Theme::main;
+
+DClass<Theme>
+{
+public:
+	QString name;
+
+	/**
+	 * Try to resolve the resource against one of the possible theme paths
+	 * and if it cannot, return path to Qt Resource System.
+	 */
+	QString resolve(const QString &resourceName)
+	{
+		if (!this->name.isEmpty())
+		{
+			QStringList themePaths = gDefaultDataPaths->staticDataSearchDirs(DataPaths::THEME_APPEARANCE_DIR);
+			bool found = false;
+			QString themed = Strings::combinePaths(this->name, resourceName);
+			foreach (QFile file, Strings::combineManyPaths(themePaths, themed))
+			{
+				if (file.exists())
+					return file.fileName();
+			}
+		}
+		return ":" + resourceName;
+	}
+};
+DPointered(Theme)
+
+Theme::Theme()
+{
+}
+
+Theme::Theme(const QString &name)
+{
+	d->name = name;
+}
+
+Theme::~Theme()
+{
+}
+
+QIcon Theme::icon(const QString &name)
+{
+	return QIcon(d->resolve(name));
+}
diff -r 33e6ab19ce75 -r cb114b95e71b src/core/gui/theme.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/gui/theme.h	Sun Oct 29 13:46:41 2017 +0100
@@ -0,0 +1,48 @@
+//------------------------------------------------------------------------------
+// theme.h
+//------------------------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301  USA
+//
+//------------------------------------------------------------------------------
+// Copyright (C) 2017 "Zalewa" <zalewapl@gmail.com>
+//------------------------------------------------------------------------------
+#ifndef id7d5231b5_4e8a_45c7_9868_8f4c3a96fd21
+#define id7d5231b5_4e8a_45c7_9868_8f4c3a96fd21
+
+#include "dptr.h"
+#include <QIcon>
+
+/**
+ * Theme implementation is half-hearted right now. Its primary purpose is
+ * to allow to unbake non-free icons from Doomseeker's executable.
+ */
+class Theme
+{
+public:
+	static Theme main;
+
+	Theme();
+	Theme(const QString &theme);
+	~Theme();
+
+	QIcon icon(const QString &name);
+
+private:
+	DPtr<Theme> d;
+};
+
+#endif
