changeset 116:254b1d2b7096

settings: add torrents page, make rss feed configurable
author Paper <mrpapersonic@gmail.com>
date Tue, 07 Nov 2023 13:52:13 -0500
parents c72b907b9bef
children 2c1b6782e1d0
files CMakeLists.txt include/core/config.h include/core/ini.h include/core/strings.h include/gui/dialog/settings.h rc/locale/en_GB.ts rc/locale/es.ts src/core/config.cc src/core/ini.cc src/core/strings.cc src/gui/dialog/settings.cc src/gui/dialog/settings/torrents.cc src/gui/pages/torrents.cc
diffstat 13 files changed, 238 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Tue Nov 07 12:04:51 2023 -0500
+++ b/CMakeLists.txt	Tue Nov 07 13:52:13 2023 -0500
@@ -57,6 +57,7 @@
 	src/core/config.cc
 	src/core/date.cc
 	src/core/filesystem.cc
+	src/core/ini.cc
 	src/core/http.cc
 	src/core/json.cc
 	src/core/strings.cc
@@ -90,6 +91,7 @@
 	src/gui/dialog/settings.cc
 	src/gui/dialog/settings/application.cc
 	src/gui/dialog/settings/services.cc
+	src/gui/dialog/settings/torrents.cc
 
 	# Translate
 	src/gui/translate/anime.cc
--- a/include/core/config.h	Tue Nov 07 12:04:51 2023 -0500
+++ b/include/core/config.h	Tue Nov 07 13:52:13 2023 -0500
@@ -23,17 +23,28 @@
 				bool highlighted_anime_above_others;
 		} anime_list;
 
+		/* these should preferably be in an
+		   "auth" struct... */
 		struct {
 			public:
 				std::string auth_token;
 				std::string username;
 				int user_id;
 		} anilist;
+
+		struct {
+			public:
+				std::string feed_link;
+		} torrents;
 };
 
 #define WIDEIFY_EX(x) L##x
 #define WIDEIFY(x)    WIDEIFY_EX(x)
 
+/* only on these platforms keep this uppercase.
+   this will not remove compatibility with older
+   versions, since these platforms are case insensitive
+   (on macOS, only by default) */
 #if (defined(WIN32) || defined(MACOSX))
 #define CONFIG_DIR    "Minori"
 #else
--- a/include/core/ini.h	Tue Nov 07 12:04:51 2023 -0500
+++ b/include/core/ini.h	Tue Nov 07 13:52:13 2023 -0500
@@ -4,4 +4,11 @@
 #define MINI_CASE_SENSITIVE
 #include "mini/ini.h"
 
+namespace INI {
+
+std::string GetIniString(const mINI::INIStructure& ini, const std::string& section,
+	                     const std::string& value, const std::string& def = "");
+
+}
+
 #endif
\ No newline at end of file
--- a/include/core/strings.h	Tue Nov 07 12:04:51 2023 -0500
+++ b/include/core/strings.h	Tue Nov 07 13:52:13 2023 -0500
@@ -7,6 +7,7 @@
 #include <cstdint>
 
 class QString;
+class QByteArray;
 
 namespace Strings {
 
@@ -32,12 +33,16 @@
 std::wstring ToWstring(const QString& string);
 std::string ToUtf8String(const std::wstring& wstring);
 std::string ToUtf8String(const QString& string);
+std::string ToUtf8String(const QByteArray& ba);
 QString ToQString(const std::string& string);
 QString ToQString(const std::wstring& wstring);
 
 /* arithmetic :) */
 int ToInt(const std::string& str, int def = 0);
 
+bool ToBool(const std::string& s, const bool def = false);
+std::string ToUtf8String(const bool b);
+
 uint64_t HumanReadableSizeToBytes(const std::string& str);
 
 std::string RemoveLeadingChars(std::string s, const char c);
--- a/include/gui/dialog/settings.h	Tue Nov 07 12:04:51 2023 -0500
+++ b/include/gui/dialog/settings.h	Tue Nov 07 13:52:13 2023 -0500
@@ -3,6 +3,7 @@
 
 #include "core/anime.h"
 #include "core/config.h"
+#include "core/session.h"
 #include <QDialog>
 #include <QWidget>
 #include <QLocale>
@@ -58,6 +59,18 @@
 		bool highlighted_anime_above_others;
 };
 
+class SettingsPageTorrents final : public SettingsPage {
+		Q_OBJECT
+
+	public:
+		SettingsPageTorrents(QWidget* parent = nullptr);
+		void SaveInfo() override;
+
+	private:
+		QWidget* CreateGeneralWidget();
+		decltype(session.config.torrents.feed_link) feed_link;
+};
+
 class SettingsDialog final : public QDialog {
 		Q_OBJECT
 
--- a/rc/locale/en_GB.ts	Tue Nov 07 12:04:51 2023 -0500
+++ b/rc/locale/en_GB.ts	Tue Nov 07 13:52:13 2023 -0500
@@ -565,6 +565,11 @@
         <source>Application</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <location filename="../../src/gui/dialog/settings.cc" line="94"/>
+        <source>Torrents</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>SettingsPageApplication</name>
@@ -739,6 +744,29 @@
     </message>
 </context>
 <context>
+    <name>SettingsPageTorrents</name>
+    <message>
+        <location filename="../../src/gui/dialog/settings/torrents.cc" line="20"/>
+        <source>URLs</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../src/gui/dialog/settings/torrents.cc" line="31"/>
+        <source>URL of the RSS feed to check:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../src/gui/dialog/settings/torrents.cc" line="59"/>
+        <source>Application</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../src/gui/dialog/settings/torrents.cc" line="61"/>
+        <source>General</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>StatisticsPage</name>
     <message>
         <location filename="../../src/gui/pages/statistics.cc" line="24"/>
@@ -775,22 +803,22 @@
 <context>
     <name>TorrentsPage</name>
     <message>
-        <location filename="../../src/gui/pages/torrents.cc" line="266"/>
+        <location filename="../../src/gui/pages/torrents.cc" line="270"/>
         <source>&amp;Check new torrents</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../src/gui/pages/torrents.cc" line="276"/>
+        <location filename="../../src/gui/pages/torrents.cc" line="280"/>
         <source>Download &amp;marked torrents</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../src/gui/pages/torrents.cc" line="280"/>
+        <location filename="../../src/gui/pages/torrents.cc" line="284"/>
         <source>&amp;Discard all</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../src/gui/pages/torrents.cc" line="286"/>
+        <location filename="../../src/gui/pages/torrents.cc" line="290"/>
         <source>&amp;Settings</source>
         <translation type="unfinished"></translation>
     </message>
--- a/rc/locale/es.ts	Tue Nov 07 12:04:51 2023 -0500
+++ b/rc/locale/es.ts	Tue Nov 07 13:52:13 2023 -0500
@@ -646,6 +646,11 @@
         <source>Application</source>
         <translation>Aplicación</translation>
     </message>
+    <message>
+        <location filename="../../src/gui/dialog/settings.cc" line="94"/>
+        <source>Torrents</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>SettingsPageApplication</name>
@@ -820,6 +825,29 @@
     </message>
 </context>
 <context>
+    <name>SettingsPageTorrents</name>
+    <message>
+        <location filename="../../src/gui/dialog/settings/torrents.cc" line="20"/>
+        <source>URLs</source>
+        <translation>URLs</translation>
+    </message>
+    <message>
+        <location filename="../../src/gui/dialog/settings/torrents.cc" line="31"/>
+        <source>URL of the RSS feed to check:</source>
+        <translation>URL del feed RSS para comprobar:</translation>
+    </message>
+    <message>
+        <location filename="../../src/gui/dialog/settings/torrents.cc" line="59"/>
+        <source>Application</source>
+        <translation>Aplicación</translation>
+    </message>
+    <message>
+        <location filename="../../src/gui/dialog/settings/torrents.cc" line="61"/>
+        <source>General</source>
+        <translation>General</translation>
+    </message>
+</context>
+<context>
     <name>StatisticsPage</name>
     <message>
         <location filename="../../src/gui/pages/statistics.cc" line="24"/>
@@ -862,22 +890,22 @@
 <context>
     <name>TorrentsPage</name>
     <message>
-        <location filename="../../src/gui/pages/torrents.cc" line="266"/>
+        <location filename="../../src/gui/pages/torrents.cc" line="270"/>
         <source>&amp;Check new torrents</source>
         <translation>&amp;Comprueba nuevos torrentes</translation>
     </message>
     <message>
-        <location filename="../../src/gui/pages/torrents.cc" line="276"/>
+        <location filename="../../src/gui/pages/torrents.cc" line="280"/>
         <source>Download &amp;marked torrents</source>
         <translation>Descargar torrents &amp;marcados</translation>
     </message>
     <message>
-        <location filename="../../src/gui/pages/torrents.cc" line="280"/>
+        <location filename="../../src/gui/pages/torrents.cc" line="284"/>
         <source>&amp;Discard all</source>
         <translation>&amp;Descartar todo</translation>
     </message>
     <message>
-        <location filename="../../src/gui/pages/torrents.cc" line="286"/>
+        <location filename="../../src/gui/pages/torrents.cc" line="290"/>
         <source>&amp;Settings</source>
         <translation>Configuración (&amp;S)</translation>
     </message>
--- a/src/core/config.cc	Tue Nov 07 12:04:51 2023 -0500
+++ b/src/core/config.cc	Tue Nov 07 13:52:13 2023 -0500
@@ -17,22 +17,6 @@
 #include <fstream>
 #include <limits.h>
 
-/* Move these to strings.cc or the translation stuff, please. */
-static bool string_to_bool(const std::string& s, bool def = false) {
-	if (s.length() < 4)
-		return def;
-	std::string l = Strings::ToLower(s);
-	if (Strings::BeginningMatchesSubstring(l, "true"))
-		return true;
-	else if (Strings::BeginningMatchesSubstring(l, "false"))
-		return false;
-	return def;
-}
-
-static std::string bool_to_string(bool b) {
-	return b ? "true" : "false";
-}
-
 int Config::Load() {
 	Filesystem::Path cfg_path = Filesystem::GetConfigPath();
 
@@ -40,16 +24,22 @@
 	mINI::INIStructure ini;
 	file.read(ini);
 
-	service = Translate::ToService(ini.get("General").get("Service"));
-	locale.SetActiveLocale(QLocale(Strings::ToQString(ini.get("General").get("Locale"))));
-	anime_list.language = Translate::ToLanguage(ini.get("Anime List").get("Title language"));
-	anime_list.display_aired_episodes = string_to_bool(ini.get("Anime List").get("Display only aired episodes"), true);
-	anime_list.display_available_episodes = string_to_bool(ini.get("Anime List").get("Display only available episodes in library"), true);
-	anime_list.highlight_anime_if_available = string_to_bool(ini.get("Anime List").get("Highlight anime if available"), true);
-	anime_list.highlighted_anime_above_others = string_to_bool(ini.get("Anime List").get("Display highlighted anime above others"));
-	anilist.auth_token = ini.get("AniList").get("Auth Token");
-	anilist.user_id = Strings::ToInt(ini.get("AniList").get("User ID"));
-	theme.SetTheme(Translate::ToTheme(ini.get("Appearance").get("Theme")));
+	service = Translate::ToService(INI::GetIniString(ini, "General", "Service", "None"));
+	/* ew */
+	locale.SetActiveLocale(QLocale(Strings::ToQString(INI::GetIniString(ini, "General", "Locale", "en_US"))));
+
+	anime_list.language = Translate::ToLanguage(INI::GetIniString(ini, "Anime List", "Title language", "Romaji"));
+	anime_list.display_aired_episodes = Strings::ToBool(INI::GetIniString(ini, "Anime List", "Display only aired episodes", ""), true);
+	anime_list.display_available_episodes = Strings::ToBool(INI::GetIniString(ini, "Anime List", "Display only available episodes in library", ""), true);
+	anime_list.highlight_anime_if_available = Strings::ToBool(INI::GetIniString(ini, "Anime List", "Highlight anime if available", ""), true);
+	anime_list.highlighted_anime_above_others = Strings::ToBool(INI::GetIniString(ini, "Anime List", "Display highlighted anime above others", ""), false);
+
+	anilist.auth_token = INI::GetIniString(ini, "AniList", "Auth Token", "");
+	anilist.user_id = Strings::ToInt(INI::GetIniString(ini, "AniList", "User ID", ""), 0);
+
+	torrents.feed_link = INI::GetIniString(ini, "Torrents", "RSS Feed Link", "https://www.tokyotosho.info/rss.php?filter=1,11&zwnj=0");
+
+	theme.SetTheme(Translate::ToTheme(INI::GetIniString(ini, "Appearance", "Theme", "Default")));
 
 	return 0;
 }
@@ -65,13 +55,14 @@
 	ini["General"]["Service"] = Translate::ToString(service);
 	ini["General"]["Locale"] = Strings::ToUtf8String(locale.GetLocale().name());
 	ini["Anime List"]["Title language"] = Translate::ToString(anime_list.language);
-	ini["Anime List"]["Display only aired episodes"] = bool_to_string(anime_list.display_aired_episodes);
-	ini["Anime List"]["Display only available episodes in library"] = bool_to_string(anime_list.display_available_episodes);
-	ini["Anime List"]["Highlight anime if available"] = bool_to_string(anime_list.highlight_anime_if_available);
-	ini["Anime List"]["Display highlighted anime above others"] = bool_to_string(anime_list.highlighted_anime_above_others);
+	ini["Anime List"]["Display only aired episodes"] = Strings::ToUtf8String(anime_list.display_aired_episodes);
+	ini["Anime List"]["Display only available episodes in library"] = Strings::ToUtf8String(anime_list.display_available_episodes);
+	ini["Anime List"]["Highlight anime if available"] = Strings::ToUtf8String(anime_list.highlight_anime_if_available);
+	ini["Anime List"]["Display highlighted anime above others"] = Strings::ToUtf8String(anime_list.highlighted_anime_above_others);
 	ini["AniList"]["Auth Token"] = anilist.auth_token;
 	ini["AniList"]["User ID"] = std::to_string(anilist.user_id);
 	ini["Appearance"]["Theme"] = Translate::ToString(theme.GetTheme());
+	ini["Torrents"]["RSS Feed Link"] = torrents.feed_link;
 
 	file.write(ini);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/ini.cc	Tue Nov 07 13:52:13 2023 -0500
@@ -0,0 +1,13 @@
+#include "core/ini.h"
+
+namespace INI {
+
+/* this should be in some ini.cc or whatever */
+std::string GetIniString(const mINI::INIStructure& ini, const std::string& section,
+	                              const std::string& value, const std::string& def) {
+	if (!ini.has(section) || !ini.get(section).has(value))
+		return def;
+	return ini.get(section).get(value); // ack
+}
+
+}
\ No newline at end of file
--- a/src/core/strings.cc	Tue Nov 07 12:04:51 2023 -0500
+++ b/src/core/strings.cc	Tue Nov 07 13:52:13 2023 -0500
@@ -156,6 +156,21 @@
 	return tmp;
 }
 
+bool ToBool(const std::string& s, const bool def) {
+	if (s.length() < 4)
+		return def;
+	std::string l = Strings::ToLower(s);
+	if (Strings::BeginningMatchesSubstring(l, "true"))
+		return true;
+	else if (Strings::BeginningMatchesSubstring(l, "false"))
+		return false;
+	return def;
+}
+
+std::string ToUtf8String(const bool b) {
+	return b ? "true" : "false";
+}
+
 uint64_t HumanReadableSizeToBytes(const std::string& str) {
 	const std::unordered_map<std::string, uint64_t> bytes_map = {
 		{"KB", 1 << 10},
--- a/src/gui/dialog/settings.cc	Tue Nov 07 12:04:51 2023 -0500
+++ b/src/gui/dialog/settings.cc	Tue Nov 07 13:52:13 2023 -0500
@@ -91,7 +91,7 @@
 			sidebar->AddItem(tr("Application"), SideBar::CreateIcon(":/icons/24x24/application-sidebar-list.png"));
 			// sidebar->AddItem(tr("Recognition"), SideBar::CreateIcon(":/icons/24x24/question.png"));
 			// sidebar->AddItem(tr("Sharing"), SideBar::CreateIcon(":/icons/24x24/megaphone.png"));
-			// sidebar->AddItem(tr("Torrents"), SideBar::CreateIcon(":/icons/24x24/feed.png"));
+			sidebar->AddItem(tr("Torrents"), SideBar::CreateIcon(":/icons/24x24/feed.png"));
 			// sidebar->AddItem(tr("Advanced"), SideBar::CreateIcon(":/icons/24x24/gear.png"));
 
 			sidebar->setIconSize(QSize(24, 24));
@@ -109,6 +109,7 @@
 			stacked = new QStackedWidget(widget);
 			stacked->addWidget(new SettingsPageServices(stacked));
 			stacked->addWidget(new SettingsPageApplication(stacked));
+			stacked->addWidget(new SettingsPageTorrents(stacked));
 			stacked->setCurrentIndex(0);
 
 			connect(sidebar, &QListWidget::currentRowChanged, stacked, &QStackedWidget::setCurrentIndex);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/dialog/settings/torrents.cc	Tue Nov 07 13:52:13 2023 -0500
@@ -0,0 +1,62 @@
+#include "core/session.h"
+#include "core/strings.h"
+#include "gui/dialog/settings.h"
+#include <QLineEdit>
+#include <QGroupBox>
+#include <QLabel>
+#include <QSizePolicy>
+#include <QVBoxLayout>
+#include <algorithm>
+
+QWidget* SettingsPageTorrents::CreateGeneralWidget() {
+	QWidget* result = new QWidget(this);
+	result->setAutoFillBackground(true);
+	result->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
+
+	QVBoxLayout* full_layout = new QVBoxLayout(result);
+
+	{
+		/* URLs */
+		QGroupBox* group = new QGroupBox(tr("URLs"), result);
+		group->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
+
+		QVBoxLayout* group_layout = new QVBoxLayout(group);
+
+		{
+			/* Feed link */
+			QWidget* widget = new QWidget(group);
+			QVBoxLayout* widget_layout = new QVBoxLayout(widget);
+
+			{
+				QLabel* sync_combo_box_label = new QLabel(tr("URL of the RSS feed to check:"), widget);
+				widget_layout->addWidget(sync_combo_box_label);
+			}
+
+			{
+				/* Username: this literally never gets used btw */
+				QLineEdit* lineedit = new QLineEdit(Strings::ToQString(feed_link), widget);
+				connect(lineedit, &QLineEdit::editingFinished, this,
+				        [this, lineedit] { feed_link = Strings::ToUtf8String(lineedit->text()); });
+				widget_layout->addWidget(lineedit);
+			}
+
+			group_layout->addWidget(widget);
+		}
+
+		full_layout->addWidget(group);
+	}
+
+	full_layout->setSpacing(10);
+	full_layout->addStretch();
+
+	return result;
+}
+
+void SettingsPageTorrents::SaveInfo() {
+	session.config.torrents.feed_link = feed_link;
+}
+
+SettingsPageTorrents::SettingsPageTorrents(QWidget* parent) : SettingsPage(parent, tr("Application")) {
+	feed_link = session.config.torrents.feed_link;
+	AddTab(CreateGeneralWidget(), tr("General"));
+}
--- a/src/gui/pages/torrents.cc	Tue Nov 07 12:04:51 2023 -0500
+++ b/src/gui/pages/torrents.cc	Tue Nov 07 13:52:13 2023 -0500
@@ -41,7 +41,7 @@
 }
 
 QByteArray TorrentsPageListModel::DownloadTorrentList() {
-	return HTTP::Get("https://www.tokyotosho.info/rss.php?filter=1,11&zwnj=0");
+	return HTTP::Get(session.config.torrents.feed_link);
 }
 
 void TorrentsPageListModel::ParseTorrentList(const QByteArray& ba) {
@@ -173,38 +173,42 @@
 QVariant TorrentsPageListModel::data(const QModelIndex& index, int role) const {
 	if (!index.isValid())
 		return QVariant();
+
+	const TorrentModelItem& item = list.at(index.row());
+
 	switch (role) {
 		case Qt::DisplayRole:
 			switch (index.column()) {
-				case TL_TITLE: return Strings::ToQString(list.at(index.row()).GetTitle());
-				case TL_EPISODE: return Strings::ToQString(list.at(index.row()).GetEpisode());
-				case TL_GROUP: return Strings::ToQString(list.at(index.row()).GetGroup());
-				case TL_SIZE: return session.config.locale.GetLocale().formattedDataSize(list.at(index.row()).GetSize());
-				case TL_RESOLUTION: return Strings::ToQString(list.at(index.row()).GetResolution());
-				case TL_SEEDERS: return list.at(index.row()).GetSeeders();
-				case TL_LEECHERS: return list.at(index.row()).GetLeechers();
-				case TL_DOWNLOADERS: return list.at(index.row()).GetDownloaders();
-				case TL_DESCRIPTION: return Strings::ToQString(list.at(index.row()).GetDescription());
-				case TL_FILENAME: return Strings::ToQString(list.at(index.row()).GetFilename());
-				case TL_RELEASEDATE: return list.at(index.row()).GetDate();
+				case TL_TITLE: return Strings::ToQString(item.GetTitle());
+				case TL_EPISODE: return Strings::ToQString(item.GetEpisode());
+				case TL_GROUP: return Strings::ToQString(item.GetGroup());
+				case TL_SIZE: return session.config.locale.GetLocale().formattedDataSize(item.GetSize());
+				case TL_RESOLUTION: return Strings::ToQString(item.GetResolution());
+				case TL_SEEDERS: return item.GetSeeders();
+				case TL_LEECHERS: return item.GetLeechers();
+				case TL_DOWNLOADERS: return item.GetDownloaders();
+				case TL_DESCRIPTION: return Strings::ToQString(item.GetDescription());
+				case TL_FILENAME: return Strings::ToQString(item.GetFilename());
+				case TL_RELEASEDATE: return item.GetDate();
 				default: return "";
 			}
 			break;
 		case Qt::UserRole:
 			switch (index.column()) {
-				case TL_EPISODE: return Strings::ToInt(list.at(index.row()).GetEpisode(), -1);
-				case TL_SIZE: return list.at(index.row()).GetSize();
+				case TL_EPISODE: return Strings::ToInt(item.GetEpisode(), -1);
+				case TL_SIZE: return item.GetSize();
 				default: return data(index, Qt::DisplayRole);
 			}
 			break;
 		case Qt::CheckStateRole:
 			switch (index.column()) {
-				case 0: return list.at(index.row()).GetChecked() ? Qt::Checked : Qt::Unchecked;
+				case 0: return item.GetChecked() ? Qt::Checked : Qt::Unchecked;
 				default: return {};
 			}
 		case Qt::SizeHintRole: {
 			switch (index.column()) {
 				default: {
+					/* max horizontal size of 100, height size = size of current font */
 					const QString d = data(index, Qt::DisplayRole).toString();
 					const QFontMetrics metric = QFontMetrics(QFont());
 
@@ -263,7 +267,7 @@
 		{
 			/* this needs to be stored somewhere to replicate Taiga's
 			   "timer" feature */
-			QAction* action = toolbar->addAction(QIcon(":/icons/16x16/arrow-circle-315.png"), tr("&Check new torrents"), [this]{
+			toolbar->addAction(QIcon(":/icons/16x16/arrow-circle-315.png"), tr("&Check new torrents"), [this]{
 				QThreadPool::globalInstance()->start([this] {
 					Refresh();
 				});
@@ -273,17 +277,17 @@
 		toolbar->addSeparator();
 
 		{
-			QAction* action = toolbar->addAction(QIcon(":/icons/16x16/navigation-270-button.png"), tr("Download &marked torrents"));
+			toolbar->addAction(QIcon(":/icons/16x16/navigation-270-button.png"), tr("Download &marked torrents"));
 		}
 
 		{
-			QAction* action = toolbar->addAction(QIcon(":/icons/16x16/cross-button.png"), tr("&Discard all"));
+			toolbar->addAction(QIcon(":/icons/16x16/cross-button.png"), tr("&Discard all"));
 		}
 
 		toolbar->addSeparator();
 
 		{
-			QAction* action = toolbar->addAction(QIcon(":/icons/16x16/gear.png"), tr("&Settings"));
+			toolbar->addAction(QIcon(":/icons/16x16/gear.png"), tr("&Settings"));
 		}
 
 		layout->addWidget(toolbar);