diff --git a/CMakeLists.txt b/CMakeLists.txt
index 22cc02374..01847c924 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -171,6 +171,9 @@ set(APP_SOURCES
src/gui/basewebview.cpp
src/gui/baselineedit.cpp
src/gui/locationlineedit.cpp
+ src/gui/tabwidget.cpp
+ src/gui/tabbar.cpp
+ src/gui/tabcontent.cpp
# CORE sources.
src/core/debugging.cpp
@@ -209,6 +212,9 @@ set(APP_HEADERS
src/gui/basewebview.h
src/gui/baselineedit.h
src/gui/locationlineedit.h
+ src/gui/tabwidget.h
+ src/gui/tabbar.h
+ src/gui/tabcontent.h
# CORE headers.
src/core/basenetworkaccessmanager.h
diff --git a/localization/rssguard_cs.ts b/localization/rssguard_cs.ts
index bbf0b52fe..6f762a5b5 100644
--- a/localization/rssguard_cs.ts
+++ b/localization/rssguard_cs.ts
@@ -96,27 +96,19 @@
<b>%8</b><br><b>Version:</b> %1 (build on %2 with CMake %3)<br><b>Revision:</b> %4<br><b>Build date:</b> %5<br><b>Qt:</b> %6 (compiled against %7)<br>
+ <b>%8</b><br><b>Verze:</b> %1 (OS při sestavování %2 verze CMake %3)<br><b>Revize:</b> %4<br><b>Datum sestavení:</b> %5<br><b>Qt:</b> %6 (při kompilaci %7)<br>
+
+
+ <body>Authors and contributors:<ul><li>Martin Rotter (<a href="mailto://rotter.martinos@gmail.com">rotter.martinos@gmail.com</a>) (author of RSS Guard)</li><li>snakebite & tiheum (authors of KFaenza/Faenza icon theme)</li><li>Digia Plc (author of QtSingleApplication component)</li><li>Artem Galichkin (<a href="mailto://doomer3d@gmail.com">doomer3d@gmail.com</a>) (author of original QKeySequenceWidget component)</li></ul></body>
- <body>Authors and contributors:<ul><li>Martin Rotter (<a href="mailto://rotter.martinos@gmail.com">rotter.martinos@gmail.com</a>) (author of RSS Guard)</li><li>snakebite & tiheum (authors of KFaenza/Faenza icon theme)</li><li>Digia Plc (author of QtSingleApplication component)</li></ul></body>
-
-
-
- <body>RSS Guard is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3 or later.<br><br>Contacts:<ul><li><a href="mailto://rotter.martinos@gmail.com">rotter.martinos@gmail</a> ~email</li><li><a href="http://www.rssguard.sf.net">www.rssguard.sf.net</a> ~website</li></ul>You can obtain source code for Qonverter from its website.<br><br><br>Copyright © 2011-%1 Martin Rotter</body>
-
+ <body>RSS Guard is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://rotter.martinos@gmail.com">rotter.martinos@gmail</a> ~email</li><li><a href="http://www.rssguard.sf.net">www.rssguard.sf.net</a> ~website</li></ul>You can obtain source code for RSS Guard from its website.<br><br><br>Copyright © 2011-%1 Martin Rotter</body>
+ <body>RSS Guard je (velmi) jednoduchá čtečka kanálů.<br><br>Tento software je šířen pod licencí GNU General Public, verze 3.<br><br>Kontakty:<ul><li><a href="mailto://rotter.martinos@gmail.com">rotter.martinos@gmail</a> ~email</li><li><a href="http://www.rssguard.sf.net">www.rssguard.sf.net</a> ~webová stránka</li></ul>Zdrojové kódy aplikace RSS Guard lze získat na její webové stránce.<br><br><br>Copyright © 2011-%1 Martin Rotter</body>
FormMain
-
- MainWindow
-
-
-
- ...
-
-
&File
&Soubor
@@ -149,30 +141,6 @@
&Settings
Na&stavení
-
- Tab 1
-
-
-
- Tab 2
-
-
-
- Ctrl+Shift+I
-
-
-
- Ctrl+Shift+E
-
-
-
- Ctrl+Shift+Q
-
-
-
- Ctrl+Shift+S
-
-
&About RSS Guard
&O aplikaci RSS Guard
@@ -182,183 +150,171 @@
&Režime celé obrazovky
- Ctrl+Shift+F
-
+ Feeds
+ Kanály
+
+
+ Browser your feeds and messages
+ Procházej své kanály a zprávy
+
+
+ Web browser
+ Webový prohlížeč
FormSettings
General
-
+ Obecné
User interface
-
+ Uživatelské rozhraní
Icon theme
-
+ Téma ikon
system icon theme (default)
-
+ systémové téma ikon (výchozí)
Settings
-
+ Nastavení
Keyboard shortcuts
-
+ Klávesové zkratky
Language
-
+ Lokalizacce
Proxy
-
+
Launch RSS Guard on operating system startup
-
+ Spouštět RSS Guard při spuštěníí operačního systému
Icons && skins
-
+ Ikony && skiny
Skin
-
-
-
- Notifications
-
+
Tray icon
-
-
-
- disable
-
-
-
- enable
-
+ Notifikační ikona
When main window is closed, then
-
+ Je-li hlavní okno aplikace zavřeno, pak
hide it.
-
+ jej pouze skrýt (aplikace běží na pozadí).
quit the application.
-
+ aplikaci ukončit.
Start application hidden
-
+ Spouštět aplikaci skrytou
Web browser
-
-
-
- Color of website loading progress bar
-
+ Webový prohlížeč
&Change...
-
+ &Změnit...
Use custom color for web browser progress bar
-
-
-
- Miscellaneous
-
+ Použít barevný průběhový pás při načítání stránky
Type
-
+ Typ
Host
-
+ Server
Hostname or IP of your proxy server
-
+ Webový název IP adresa proxy serveru
Port
-
+
Username
-
+ Uživatelské jméno
Your username for proxy server authentication
-
+ Vaše uživatelské jméno pro autentifikaci
Password
-
+ Heslo
Your password for proxy server authentication
-
+ Vaše heslo pro autentifikaci
Display password
-
+ Zobrazit heslo
Password is stored in plain string in RSS Guard configuration file.
-
+ Heslo je uloženo v nezašifrované podobě jako prostý text v souboru s nastavením aplikace RSS Guard.
Code
-
+ Kód
Version
-
+ Verze
Author
-
+ Autor
Email
-
+
Select color for web browser progress bar
-
+ Zvolit barvu pro průběhový pás při načítání stránky
No proxy
-
+ Žádné proxy
Socks5
-
+
Http
-
+
Language of Qonverter was changed. Note that changes will take effect on next Qonverter start.
-
+ Jazyk
Do you want to restart now?
@@ -372,16 +328,70 @@
Problem with RSS Guard restart
-
- Qonverter couldn't be restarted, please restart it manually for changes to take effect.
-
-
(not supported on this platform)
- disable (Tray icon is not available.)
+ Tray area && notifications
+
+
+
+ Disable
+
+
+
+ Enable
+
+
+
+ Tabs
+
+
+
+ Close tabs with
+
+
+
+ Left mouse button double-click
+
+
+
+ Middle mouse button single-click
+
+
+
+ Open new tabs with left mouse button double-click on tab bar
+
+
+
+ Enable mouse gestures
+
+
+
+ Mouse gestures work with right mouse button. Possible gestures are:
+<ul>
+<li>previous web page (drag mouse left)</li>
+<li>next web page (drag mouse right)</li>
+<li>reload current web page (drag mouse up)</li>
+<li>open new web browser tab (drag mouse down)</li>
+</ul>
+
+
+
+ Web browser & proxy
+
+
+
+ Language of RSS Guard was changed. Note that changes will take effect on next Qonverter start.
+
+
+
+ RSS Guard couldn't be restarted, please restart it manually for changes to take effect.
+
+
+
+ Disable (Tray icon is not available.)
diff --git a/localization/rssguard_en.ts b/localization/rssguard_en.ts
index cf261227b..1a4028c24 100644
--- a/localization/rssguard_en.ts
+++ b/localization/rssguard_en.ts
@@ -99,24 +99,16 @@
- <body>Authors and contributors:<ul><li>Martin Rotter (<a href="mailto://rotter.martinos@gmail.com">rotter.martinos@gmail.com</a>) (author of RSS Guard)</li><li>snakebite & tiheum (authors of KFaenza/Faenza icon theme)</li><li>Digia Plc (author of QtSingleApplication component)</li></ul></body>
+ <body>Authors and contributors:<ul><li>Martin Rotter (<a href="mailto://rotter.martinos@gmail.com">rotter.martinos@gmail.com</a>) (author of RSS Guard)</li><li>snakebite & tiheum (authors of KFaenza/Faenza icon theme)</li><li>Digia Plc (author of QtSingleApplication component)</li><li>Artem Galichkin (<a href="mailto://doomer3d@gmail.com">doomer3d@gmail.com</a>) (author of original QKeySequenceWidget component)</li></ul></body>
- <body>RSS Guard is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3 or later.<br><br>Contacts:<ul><li><a href="mailto://rotter.martinos@gmail.com">rotter.martinos@gmail</a> ~email</li><li><a href="http://www.rssguard.sf.net">www.rssguard.sf.net</a> ~website</li></ul>You can obtain source code for Qonverter from its website.<br><br><br>Copyright © 2011-%1 Martin Rotter</body>
+ <body>RSS Guard is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://rotter.martinos@gmail.com">rotter.martinos@gmail</a> ~email</li><li><a href="http://www.rssguard.sf.net">www.rssguard.sf.net</a> ~website</li></ul>You can obtain source code for RSS Guard from its website.<br><br><br>Copyright © 2011-%1 Martin Rotter</body>
FormMain
-
- MainWindow
-
-
-
- ...
-
-
&File
@@ -149,30 +141,6 @@
&Settings
-
- Tab 1
-
-
-
- Tab 2
-
-
-
- Ctrl+Shift+I
-
-
-
- Ctrl+Shift+E
-
-
-
- Ctrl+Shift+Q
-
-
-
- Ctrl+Shift+S
-
-
&About RSS Guard
@@ -182,7 +150,15 @@
- Ctrl+Shift+F
+ Feeds
+
+
+
+ Browser your feeds and messages
+
+
+
+ Web browser
@@ -232,22 +208,10 @@
Skin
-
- Notifications
-
-
Tray icon
-
- disable
-
-
-
- enable
-
-
When main window is closed, then
@@ -268,10 +232,6 @@
Web browser
-
- Color of website loading progress bar
-
-
&Change...
@@ -280,10 +240,6 @@
Use custom color for web browser progress bar
-
- Miscellaneous
-
-
Type
@@ -356,10 +312,6 @@
Http
-
- Language of Qonverter was changed. Note that changes will take effect on next Qonverter start.
-
-
Do you want to restart now?
@@ -372,16 +324,70 @@
Problem with RSS Guard restart
-
- Qonverter couldn't be restarted, please restart it manually for changes to take effect.
-
-
(not supported on this platform)
- disable (Tray icon is not available.)
+ Tray area && notifications
+
+
+
+ Disable
+
+
+
+ Enable
+
+
+
+ Tabs
+
+
+
+ Close tabs with
+
+
+
+ Left mouse button double-click
+
+
+
+ Middle mouse button single-click
+
+
+
+ Open new tabs with left mouse button double-click on tab bar
+
+
+
+ Enable mouse gestures
+
+
+
+ Mouse gestures work with right mouse button. Possible gestures are:
+<ul>
+<li>previous web page (drag mouse left)</li>
+<li>next web page (drag mouse right)</li>
+<li>reload current web page (drag mouse up)</li>
+<li>open new web browser tab (drag mouse down)</li>
+</ul>
+
+
+
+ Web browser & proxy
+
+
+
+ Language of RSS Guard was changed. Note that changes will take effect on next Qonverter start.
+
+
+
+ RSS Guard couldn't be restarted, please restart it manually for changes to take effect.
+
+
+
+ Disable (Tray icon is not available.)
diff --git a/resources/graphics/themes/mini-kfaenza/mimetypes/128/text-html.png b/resources/graphics/themes/mini-kfaenza/mimetypes/128/text-html.png
new file mode 100644
index 000000000..a332b8937
Binary files /dev/null and b/resources/graphics/themes/mini-kfaenza/mimetypes/128/text-html.png differ
diff --git a/resources/graphics/themes/mini-kfaenza/mimetypes/16/text-html.png b/resources/graphics/themes/mini-kfaenza/mimetypes/16/text-html.png
new file mode 100644
index 000000000..2f94a7846
Binary files /dev/null and b/resources/graphics/themes/mini-kfaenza/mimetypes/16/text-html.png differ
diff --git a/resources/graphics/themes/mini-kfaenza/mimetypes/22/text-html.png b/resources/graphics/themes/mini-kfaenza/mimetypes/22/text-html.png
new file mode 100644
index 000000000..a56f11ddb
Binary files /dev/null and b/resources/graphics/themes/mini-kfaenza/mimetypes/22/text-html.png differ
diff --git a/resources/graphics/themes/mini-kfaenza/mimetypes/32/text-html.png b/resources/graphics/themes/mini-kfaenza/mimetypes/32/text-html.png
new file mode 100644
index 000000000..b01d14162
Binary files /dev/null and b/resources/graphics/themes/mini-kfaenza/mimetypes/32/text-html.png differ
diff --git a/resources/graphics/themes/mini-kfaenza/mimetypes/48/text-html.png b/resources/graphics/themes/mini-kfaenza/mimetypes/48/text-html.png
new file mode 100644
index 000000000..36a1338c6
Binary files /dev/null and b/resources/graphics/themes/mini-kfaenza/mimetypes/48/text-html.png differ
diff --git a/resources/graphics/themes/mini-kfaenza/mimetypes/64/text-html.png b/resources/graphics/themes/mini-kfaenza/mimetypes/64/text-html.png
new file mode 100644
index 000000000..d97f66ec0
Binary files /dev/null and b/resources/graphics/themes/mini-kfaenza/mimetypes/64/text-html.png differ
diff --git a/src/gui/basewebview.cpp b/src/gui/basewebview.cpp
index 47534c84a..b6556eb75 100644
--- a/src/gui/basewebview.cpp
+++ b/src/gui/basewebview.cpp
@@ -120,7 +120,6 @@ void BaseWebView::mousePressEvent(QMouseEvent *event) {
m_gestureOrigin = event->pos();
}
- // TODO: Add mouse gestures (from quite-rss).
QWebView::mousePressEvent(event);
}
diff --git a/src/gui/dynamicshortcutswidget.cpp b/src/gui/dynamicshortcutswidget.cpp
index 4ea5153bf..a6ab25bf3 100644
--- a/src/gui/dynamicshortcutswidget.cpp
+++ b/src/gui/dynamicshortcutswidget.cpp
@@ -28,7 +28,6 @@ void DynamicShortcutsWidget::updateShortcuts() {
void DynamicShortcutsWidget::populate(const QList actions) {
m_actionBindings.clear();
- // TODO: Make labels smaller correctly and review this method.
int row_id = 0;
bool second_column = false;
diff --git a/src/gui/formmain.cpp b/src/gui/formmain.cpp
index 4f7bfe6b0..09f938332 100644
--- a/src/gui/formmain.cpp
+++ b/src/gui/formmain.cpp
@@ -7,6 +7,7 @@
#include "gui/webbrowser.h"
#include "gui/themefactory.h"
#include "gui/systemtrayicon.h"
+#include "gui/tabbar.h"
#include "core/settings.h"
#include "core/defs.h"
#include "qtsingleapplication/qtsingleapplication.h"
@@ -20,10 +21,14 @@ FormMain::FormMain(QWidget *parent) : QMainWindow(parent), m_ui(new Ui::FormMain
// Initialize singleton.
s_instance = this;
+ // Prepare main window.
+ prepareMenus();
+ prepareTabs();
+
// Establish connections.
createConnections();
- prepareMenus();
+ setupIcons();
}
FormMain::~FormMain() {
@@ -51,6 +56,58 @@ QList FormMain::getActions() {
return actions;
}
+void FormMain::prepareTabs() {
+ // Create widget for "Feeds" page and add it.
+ WebBrowser *browser = new WebBrowser(m_ui->m_tabWidget);
+ int index_of_browser = m_ui->m_tabWidget->addTab(static_cast(browser),
+ QIcon(),
+ tr("Feeds"),
+ TabBar::FeedReader);
+ m_ui->m_tabWidget->setTabToolTip(index_of_browser, tr("Browser your feeds and messages"));
+}
+
+void FormMain::addEmptyBrowser() {
+ addBrowser(false, true);
+}
+
+void FormMain::addLinkedBrowser() {
+
+}
+
+void FormMain::addBrowser(bool move_after_current,
+ bool make_active,
+ const QUrl &initial_url) {
+ // Create new WebBrowser.
+ WebBrowser *browser = new WebBrowser(m_ui->m_tabWidget);
+ int final_index;
+
+ if (move_after_current) {
+ // Insert web browser after current tab.
+ final_index = m_ui->m_tabWidget->insertTab(m_ui->m_tabWidget->currentIndex() + 1,
+ browser,
+ QIcon(),
+ tr("Web browser"),
+ TabBar::Closable);
+ }
+ else {
+ // Add new browser as the last tab.
+ final_index = m_ui->m_tabWidget->addTab(browser,
+ QIcon(),
+ tr("Web browser"),
+ TabBar::Closable);
+ }
+
+ // Load initial web page if desired.
+ if (initial_url.isValid()) {
+ browser->navigateToUrl(initial_url);
+ }
+
+ // Make new web browser active if desired.
+ if (make_active) {
+ m_ui->m_tabWidget->setCurrentIndex(final_index);
+ }
+}
+
void FormMain::prepareMenus() {
// Setup menu for tray icon.
if (SystemTrayIcon::isSystemTrayAvailable()) {
@@ -138,6 +195,14 @@ void FormMain::setupIcons() {
foreach (WebBrowser *browser, WebBrowser::runningWebBrowsers()) {
browser->setupIcons();
}
+
+ // Find tab, which contains "Feeds" page and reload its icon.
+ for (int index = 0; index < m_ui->m_tabWidget->count(); index++) {
+ if (m_ui->m_tabWidget->tabBar()->tabType(index) == TabBar::FeedReader) {
+ m_ui->m_tabWidget->setTabIcon(index, QIcon(APP_ICON_PATH));
+ break;
+ }
+ }
}
void FormMain::createConnections() {
@@ -155,6 +220,10 @@ void FormMain::createConnections() {
// General connections.
connect(qApp, &QCoreApplication::aboutToQuit, this, &FormMain::cleanupResources);
+
+ // TabWidget connections.
+ connect(m_ui->m_tabWidget->tabBar(), &TabBar::emptySpaceDoubleClicked,
+ this, &FormMain::addEmptyBrowser);
}
void FormMain::closeEvent(QCloseEvent *event) {
diff --git a/src/gui/formmain.h b/src/gui/formmain.h
index 88a991628..5a9dc7865 100644
--- a/src/gui/formmain.h
+++ b/src/gui/formmain.h
@@ -2,7 +2,7 @@
#define FORMMAIN_H
#include
-#include
+#include
#include "ui_formmain.h"
@@ -11,6 +11,7 @@ class FormMain : public QMainWindow {
Q_OBJECT
public:
+ // Constructors and destructors.
explicit FormMain(QWidget *parent = 0);
virtual ~FormMain();
@@ -21,12 +22,16 @@ class FormMain : public QMainWindow {
// NOTE: This is used for setting dynamic shortcuts for given actions.
QList getActions();
+ // Singleton accessor.
static FormMain *getInstance();
protected:
// Creates all needed menus and sets them up.
void prepareMenus();
+ // Initializes "Feeds" tab and related stuff.
+ void prepareTabs();
+
// Creates needed connections for this window.
void createConnections();
@@ -56,11 +61,24 @@ class FormMain : public QMainWindow {
void switchFullscreenMode(bool turn_fullscreen_on);
protected slots:
+ // Used for last-minute cleanups.
void cleanupResources();
// Displays various dialogs.
void showSettings();
void showAbout();
+
+ // Adds new WebBrowser tab to global TabWidget.
+ void addEmptyBrowser();
+
+ // Adds new WebBrowser with link. This is used when user
+ // selects to "Open link in new tab.".
+ void addLinkedBrowser();
+
+ // General method for adding WebBrowsers.
+ void addBrowser(bool move_after_current,
+ bool make_active,
+ const QUrl &initial_url = QUrl());
private:
Ui::FormMain *m_ui;
diff --git a/src/gui/formmain.ui b/src/gui/formmain.ui
index 1a9befae8..af005af84 100644
--- a/src/gui/formmain.ui
+++ b/src/gui/formmain.ui
@@ -11,14 +11,14 @@
- MainWindow
+ MainWindow
-
-
+
- 0
+ -1
true
@@ -26,45 +26,6 @@
true
-
-
- Tab 1
-
-
-
-
-
-
-
-
-
-
- Tab 2
-
-
-
-
- 140
- 110
- 61
- 51
-
-
-
- ...
-
-
-
-
-
-
-
-
- 32
- 32
-
-
-
-
@@ -116,7 +77,7 @@
&Import
- Ctrl+Shift+I
+ Ctrl+Shift+I
@@ -124,7 +85,7 @@
E&xport
- Ctrl+Shift+E
+ Ctrl+Shift+E
@@ -132,7 +93,7 @@
&Quit
- Ctrl+Shift+Q
+ Ctrl+Shift+Q
@@ -140,13 +101,16 @@
&Settings
- Ctrl+Shift+S
+ Ctrl+Shift+S
&About RSS Guard
+
+ Ctrl+Shift+A
+
@@ -156,15 +120,15 @@
&Fullscreen mode
- Ctrl+Shift+F
+ Ctrl+Shift+F
- WebBrowser
- QWidget
-
+ TabWidget
+ QTabWidget
+
1
diff --git a/src/gui/formsettings.cpp b/src/gui/formsettings.cpp
index 4bba0e7f6..c07d8d570 100644
--- a/src/gui/formsettings.cpp
+++ b/src/gui/formsettings.cpp
@@ -7,6 +7,7 @@
#include "gui/themefactory.h"
#include "gui/systemtrayicon.h"
#include "gui/formmain.h"
+#include "gui/webbrowser.h"
#include "core/settings.h"
#include "core/defs.h"
#include "core/localization.h"
@@ -205,7 +206,7 @@ void FormSettings::saveLanguage() {
Settings::getInstance()->setValue(APP_CFG_GEN, "language", new_lang);
QMessageBox msg_question(this);
- msg_question.setText(tr("Language of Qonverter was changed. Note that changes will take effect on next Qonverter start."));
+ msg_question.setText(tr("Language of RSS Guard was changed. Note that changes will take effect on next Qonverter start."));
msg_question.setInformativeText(tr("Do you want to restart now?"));
msg_question.setWindowTitle(tr("Language changed"));
msg_question.setIcon(QMessageBox::Question);
@@ -216,7 +217,7 @@ void FormSettings::saveLanguage() {
if (!QProcess::startDetached(qApp->applicationFilePath())) {
QMessageBox::warning(this,
tr("Problem with RSS Guard restart"),
- tr("Qonverter couldn't be restarted, please restart it manually for changes to take effect."));
+ tr("RSS Guard couldn't be restarted, please restart it manually for changes to take effect."));
}
else {
qApp->quit();
@@ -283,7 +284,7 @@ void FormSettings::loadInterface() {
}
// Tray icon is not supported on this machine.
else {
- m_ui->m_radioTrayOff->setText(tr("disable (Tray icon is not available.)"));
+ m_ui->m_radioTrayOff->setText(tr("Disable (Tray icon is not available.)"));
m_ui->m_radioTrayOff->setChecked(true);
m_ui->m_grpTray->setDisabled(true);
}
@@ -315,6 +316,17 @@ void FormSettings::loadInterface() {
}
#endif
}
+
+ // Load tab settings.
+ m_ui->m_checkCloseTabsMiddleClick->setChecked(Settings::getInstance()->value(APP_CFG_GUI,
+ "tab_close_mid_button",
+ true).toBool());
+ m_ui->m_checkCloseTabsDoubleClick->setChecked(Settings::getInstance()->value(APP_CFG_GUI,
+ "tab_close_double_button",
+ true).toBool());
+ m_ui->m_checkNewTabDoubleClick->setChecked(Settings::getInstance()->value(APP_CFG_GUI,
+ "tab_new_double_button",
+ true).toBool());
}
void FormSettings::saveInterface() {
@@ -336,5 +348,16 @@ void FormSettings::saveInterface() {
}
// Save selected icon theme.
- ThemeFactory::setCurrentIconTheme(m_ui->m_cmbIconTheme->itemData(m_ui->m_cmbIconTheme->currentIndex()).toString());
+ QString selected_icon_theme = m_ui->m_cmbIconTheme->itemData(m_ui->m_cmbIconTheme->currentIndex()).toString();
+ if (!selected_icon_theme.isEmpty()) {
+ ThemeFactory::setCurrentIconTheme(selected_icon_theme);
+ }
+
+ // Save tab settings.
+ Settings::getInstance()->setValue(APP_CFG_GUI, "tab_close_mid_button",
+ m_ui->m_checkCloseTabsMiddleClick->isChecked());
+ Settings::getInstance()->setValue(APP_CFG_GUI, "tab_close_double_button",
+ m_ui->m_checkCloseTabsDoubleClick->isChecked());
+ Settings::getInstance()->setValue(APP_CFG_GUI, "tab_new_double_button",
+ m_ui->m_checkNewTabDoubleClick->isChecked());
}
diff --git a/src/gui/formsettings.ui b/src/gui/formsettings.ui
index 5aa5f850a..2b75c150a 100644
--- a/src/gui/formsettings.ui
+++ b/src/gui/formsettings.ui
@@ -115,7 +115,7 @@
QTabWidget::North
- 1
+ 0
@@ -149,7 +149,7 @@
- Notifications
+ Tray area && notifications
-
@@ -208,6 +208,46 @@
+
+
+ Tabs
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+ -
+
+
+ Close tabs with
+
+
+
-
+
+
+ Left mouse button double-click
+
+
+
+ -
+
+
+ Middle mouse button single-click
+
+
+
+
+
+
+ -
+
+
+ Open new tabs with left mouse button double-click on tab bar
+
+
+
+
+
@@ -265,15 +305,18 @@
0
-
-
+
0
-
+
Web browser
+
+ QFormLayout::AllNonFixedFieldsGrow
+
-
@@ -284,26 +327,6 @@
- -
-
-
- Color of website loading progress bar
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
- 20
-
-
-
- -
-
-
- &Change...
-
-
-
-
@@ -330,9 +353,22 @@
+ -
+
+
+
+ 0
+ 0
+
+
+
+ &Change...
+
+
+
-
+
Proxy
@@ -345,6 +381,9 @@
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+ m_cmbProxyType
+
-
@@ -358,6 +397,9 @@
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+ m_txtProxyHost
+
-
@@ -380,6 +422,9 @@
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+ m_spinProxyPort
+
-
@@ -405,6 +450,9 @@
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+ m_txtProxyUsername
+
-
@@ -425,6 +473,9 @@
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+ m_txtProxyPassword
+
-
@@ -535,8 +586,8 @@
accept()
- 248
- 254
+ 257
+ 404
157
@@ -551,8 +602,8 @@
reject()
- 316
- 260
+ 325
+ 404
286
@@ -583,12 +634,12 @@
setEnabled(bool)
- 370
- 108
+ 261
+ 37
- 292
- 135
+ 261
+ 37
@@ -599,12 +650,12 @@
setEnabled(bool)
- 370
- 108
+ 261
+ 37
- 478
- 135
+ 261
+ 37
@@ -615,28 +666,12 @@
setEnabled(bool)
- 417
- 108
+ 261
+ 37
- 417
- 162
-
-
-
-
- m_checkBrowserProgressColor
- toggled(bool)
- m_lblBrowserProgressColor
- setEnabled(bool)
-
-
- 300
- 48
-
-
- 275
- 73
+ 261
+ 37
@@ -651,8 +686,8 @@
48
- 544
- 74
+ 667
+ 54
diff --git a/src/gui/tabbar.cpp b/src/gui/tabbar.cpp
new file mode 100644
index 000000000..e86a03cbb
--- /dev/null
+++ b/src/gui/tabbar.cpp
@@ -0,0 +1,73 @@
+#include
+
+#include "core/defs.h"
+#include "core/settings.h"
+#include "gui/tabbar.h"
+
+
+TabBar::TabBar(QWidget *parent) : QTabBar(parent) {
+ setDocumentMode(true);
+ setUsesScrollButtons(true);
+ setContextMenuPolicy(Qt::CustomContextMenu);
+}
+
+TabBar::~TabBar() {
+}
+
+void TabBar::setTabType(int index, const TabBar::TabType &type) {
+ setTabData(index, QVariant(type));
+}
+
+TabBar::TabType TabBar::tabType(int index) {
+ return static_cast(tabData(index).value());
+}
+
+void TabBar::mousePressEvent(QMouseEvent *event) {
+ QTabBar::mousePressEvent(event);
+
+ int tab_index = tabAt(event->pos());
+
+ // Check if user clicked on some tab or on empty space.
+ if (tab_index >= 0) {
+ // Check if user clicked tab with middle button.
+ // NOTE: This needs to be done here because
+ // destination does not know the original event.
+ if (event->button() & Qt::MiddleButton && Settings::getInstance()->value(APP_CFG_GUI,
+ "tab_close_mid_button",
+ true).toBool()) {
+ if (tabType(tab_index) == TabBar::Closable) {
+ // This tab is closable, so we can close it.
+ emit tabCloseRequested(tab_index);
+ }
+ }
+ }
+}
+
+void TabBar::mouseDoubleClickEvent(QMouseEvent *event) {
+ QTabBar::mouseDoubleClickEvent(event);
+
+ int tab_index = tabAt(event->pos());
+
+ // Check if user clicked on some tab or on empty space.
+ if (tab_index >= 0) {
+ // Check if user clicked tab with middle button.
+ // NOTE: This needs to be done here because
+ // destination does not know the original event.
+ if (event->button() & Qt::LeftButton && Settings::getInstance()->value(APP_CFG_GUI,
+ "tab_close_double_button",
+ true).toBool()) {
+ if (tabType(tab_index) == TabBar::Closable) {
+ // This tab is closable, so we can close it.
+ emit tabCloseRequested(tab_index);
+ }
+ }
+ }
+ // Check if new tab should be opened with initial web browser.
+ // NOTE: This check could be unnecesary here and should be done in
+ // destination object but we keep it here for consistency.
+ else if (Settings::getInstance()->value(APP_CFG_GUI,
+ "tab_new_double_button",
+ true).toBool()) {
+ emit emptySpaceDoubleClicked();
+ }
+}
diff --git a/src/gui/tabbar.h b/src/gui/tabbar.h
new file mode 100644
index 000000000..22e712743
--- /dev/null
+++ b/src/gui/tabbar.h
@@ -0,0 +1,34 @@
+#ifndef TABBAR_H
+#define TABBAR_H
+
+#include
+
+
+class TabBar : public QTabBar {
+ Q_OBJECT
+
+ public:
+ enum TabType {
+ FeedReader = 1000,
+ NonClosable = 1001,
+ Closable = 1002
+ };
+
+ explicit TabBar(QWidget *parent = 0);
+ virtual ~TabBar();
+
+ // Getter/setter for tab type.
+ void setTabType(int index, const TabBar::TabType &type);
+ TabBar::TabType tabType(int index);
+
+ protected:
+ void mouseDoubleClickEvent(QMouseEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+
+ signals:
+ // Emmited if empty space on tab bar is double clicked.
+ void emptySpaceDoubleClicked();
+
+};
+
+#endif // TABBAR_H
diff --git a/src/gui/tabcontent.cpp b/src/gui/tabcontent.cpp
new file mode 100644
index 000000000..a53103686
--- /dev/null
+++ b/src/gui/tabcontent.cpp
@@ -0,0 +1,16 @@
+#include "gui/tabcontent.h"
+
+
+TabContent::TabContent(QWidget *parent) : QWidget(parent), m_index(-1) {
+}
+
+TabContent::~TabContent() {
+}
+
+void TabContent::setIndex(int index) {
+ m_index = index;
+}
+
+int TabContent::index() const {
+ return m_index;
+}
diff --git a/src/gui/tabcontent.h b/src/gui/tabcontent.h
new file mode 100644
index 000000000..4bf54d42b
--- /dev/null
+++ b/src/gui/tabcontent.h
@@ -0,0 +1,28 @@
+#ifndef TABCONTENT_H
+#define TABCONTENT_H
+
+#include
+
+
+class WebBrowser;
+
+// Base class for all widgets which are placed inside tabs of TabWidget
+class TabContent : public QWidget {
+ Q_OBJECT
+
+ public:
+ TabContent(QWidget *parent = 0);
+ virtual ~TabContent();
+
+ virtual int index() const;
+ virtual void setIndex(int index);
+
+ // Obtains instance contained in this TabContent.
+ // This is used for obtaining the menu from the instance and so on.
+ virtual WebBrowser *webBrowser() = 0;
+
+ private:
+ int m_index;
+};
+
+#endif // TABCONTENT_H
diff --git a/src/gui/tabwidget.cpp b/src/gui/tabwidget.cpp
new file mode 100644
index 000000000..3437b3755
--- /dev/null
+++ b/src/gui/tabwidget.cpp
@@ -0,0 +1,60 @@
+#include "gui/tabwidget.h"
+#include "gui/tabbar.h"
+
+
+TabWidget::TabWidget(QWidget *parent) : QTabWidget(parent) {
+ setTabBar(new TabBar(this));
+ createConnections();
+}
+
+TabWidget::~TabWidget() {
+ qDebug("Destroying TabWidget instance.");
+}
+
+void TabWidget::createConnections() {
+ connect(tabBar(), &QTabBar::tabCloseRequested, this, &TabWidget::closeTab);
+}
+
+TabBar *TabWidget::tabBar() {
+ return static_cast(QTabWidget::tabBar());
+}
+
+void TabWidget::closeTab(int index) {
+ removeTab(index);
+}
+
+void TabWidget::removeTab(int index) {
+ widget(index)->deleteLater();
+ QTabWidget::removeTab(index);
+}
+
+int TabWidget::addTab(TabContent *widget, const QIcon &icon,
+ const QString &label, const TabBar::TabType &type) {
+ int index = QTabWidget::addTab(widget, icon, label);
+ tabBar()->setTabType(index, type);
+
+ return index;
+}
+
+int TabWidget::addTab(TabContent *widget, const QString &label, const TabBar::TabType &type) {
+ int index = QTabWidget::addTab(widget, label);
+ tabBar()->setTabType(index, type);
+
+ return index;
+}
+
+int TabWidget::insertTab(int index, QWidget *widget, const QIcon &icon,
+ const QString &label, const TabBar::TabType &type) {
+ int tab_index = QTabWidget::insertTab(index, widget, icon, label);
+ tabBar()->setTabType(tab_index, type);
+
+ return tab_index;
+}
+
+int TabWidget::insertTab(int index, QWidget *widget, const QString &label,
+ const TabBar::TabType &type) {
+ int tab_index = QTabWidget::insertTab(index, widget, label);
+ tabBar()->setTabType(tab_index, type);
+
+ return tab_index;
+}
diff --git a/src/gui/tabwidget.h b/src/gui/tabwidget.h
new file mode 100644
index 000000000..130ae3fc2
--- /dev/null
+++ b/src/gui/tabwidget.h
@@ -0,0 +1,41 @@
+#ifndef TABWIDGET_H
+#define TABWIDGET_H
+
+#include
+
+#include "gui/tabbar.h"
+#include "gui/tabcontent.h"
+
+
+class TabWidget : public QTabWidget {
+ Q_OBJECT
+
+ public:
+ // Constructors and destructors.
+ explicit TabWidget(QWidget *parent = 0);
+ virtual ~TabWidget();
+
+ // Manimulators for tabs.
+ int addTab(TabContent *widget, const QString &,
+ const TabBar::TabType &type = TabBar::NonClosable);
+ int addTab(TabContent *widget, const QIcon &icon,
+ const QString &label, const TabBar::TabType &type = TabBar::NonClosable);
+ int insertTab(int index, QWidget *widget, const QString &label,
+ const TabBar::TabType &type = TabBar::Closable);
+ int insertTab(int index, QWidget *widget, const QIcon &icon,
+ const QString &label, const TabBar::TabType &type = TabBar::NonClosable);
+ void removeTab(int index);
+
+ // Returns tab bar.
+ TabBar *tabBar();
+
+ protected:
+ // Creates necesary connections.
+ void createConnections();
+
+ public slots:
+ // Closes tab with given index and deletes contained widget.
+ void closeTab(int index);
+};
+
+#endif // TABWIDGET_H
diff --git a/src/gui/themefactory.cpp b/src/gui/themefactory.cpp
index 8e4bb56ab..ab7a07613 100644
--- a/src/gui/themefactory.cpp
+++ b/src/gui/themefactory.cpp
@@ -58,10 +58,10 @@ void ThemeFactory::setCurrentIconTheme(const QString &theme_name) {
Settings::getInstance()->setValue(APP_CFG_GUI,
"icon_theme",
theme_name);
- loadCurrentIconTheme();
+ loadCurrentIconTheme(true);
}
-void ThemeFactory::loadCurrentIconTheme() {
+void ThemeFactory::loadCurrentIconTheme(bool notify_widgets) {
QString theme_name = getCurrentIconTheme();
QStringList installed_themes = getInstalledIconThemes();
@@ -82,9 +82,11 @@ void ThemeFactory::loadCurrentIconTheme() {
// NOTE: Event is delivered even if custom icon theme is not set
// as active, because all widgets need to do initial
// icons initialization based in the event receival.
- foreach (QWidget *widget, QtSingleApplication::allWidgets()) {
- QtSingleApplication::postEvent((QObject*) widget,
- new ThemeFactoryEvent());
+ if (notify_widgets) {
+ foreach (QWidget *widget, QtSingleApplication::allWidgets()) {
+ QtSingleApplication::postEvent((QObject*) widget,
+ new ThemeFactoryEvent());
+ }
}
}
diff --git a/src/gui/themefactory.h b/src/gui/themefactory.h
index d3a079da3..1534eab04 100644
--- a/src/gui/themefactory.h
+++ b/src/gui/themefactory.h
@@ -11,11 +11,6 @@ class ThemeFactory {
ThemeFactory();
public:
- enum Type {
- SYSTEM,
- USER
- };
-
// Adds custom application path to be search for icons.
static void setupSearchPaths();
@@ -25,7 +20,9 @@ class ThemeFactory {
static QStringList getInstalledIconThemes();
// Loads name of selected icon theme for the application and activates it.
- static void loadCurrentIconTheme();
+ // NOTE: All existing widgets get a chance to repaint its icons if
+ // notify_widgets is true.
+ static void loadCurrentIconTheme(bool notify_widgets);
// Returns name of currently activated theme for the application.
static QString getCurrentIconTheme();
diff --git a/src/gui/webbrowser.cpp b/src/gui/webbrowser.cpp
index 5ae5f0daa..ea1078658 100644
--- a/src/gui/webbrowser.cpp
+++ b/src/gui/webbrowser.cpp
@@ -19,7 +19,7 @@ QPointer WebBrowser::m_networkManager;
QList WebBrowser::m_runningWebBrowsers;
WebBrowser::WebBrowser(QWidget *parent)
- : QWidget(parent), m_layout(new QVBoxLayout(this)),
+ : TabContent(parent), m_layout(new QVBoxLayout(this)),
m_toolBar(new QToolBar(tr("Navigation panel"), this)),
m_webView(new BaseWebView(this)),
m_txtLocation(new LocationLineEdit(this)),
@@ -32,11 +32,6 @@ WebBrowser::WebBrowser(QWidget *parent)
// NOTE: This is used primarily for dynamic icon theme switching.
m_runningWebBrowsers.append(this);
- // TODO: Make this better, add location box, search box, better icons for buttons,
- // note that icons must be loaded via separate method,
- // and main window will be responsible for reloading
- // icons on all web browsers.
-
// Set properties of some components.
m_toolBar->layout()->setMargin(0);
m_toolBar->setFloatable(false);
@@ -64,18 +59,26 @@ WebBrowser::WebBrowser(QWidget *parent)
m_layout->addWidget(m_toolBar);
m_layout->addWidget(m_webView);
m_layout->setMargin(0);
+ m_layout->setContentsMargins(0, -1, 0, 0);
createConnections();
+ setupIcons();
}
void WebBrowser::createConnections() {
// When user confirms new url, then redirect to it.
- connect(m_txtLocation, &LocationLineEdit::submitted,
- this, &WebBrowser::navigateToUrl);
+ connect(m_txtLocation,
+ &LocationLineEdit::submitted,
+ this,
+ static_cast(&WebBrowser::navigateToUrl));
// If new page loads, then update current url.
connect(m_webView, &BaseWebView::urlChanged,
this, &WebBrowser::updateUrl);
+ // Signal forwarding.
+ connect(m_webView, &BaseWebView::newTabRequested,
+ this, &WebBrowser::newTabRequested);
+
// Change location textbox status according to webpage status.
connect(m_webView, &BaseWebView::loadProgress,
m_txtLocation, &LocationLineEdit::setProgress);
@@ -87,14 +90,16 @@ void WebBrowser::updateUrl(const QUrl &url) {
m_txtLocation->setText(url.toString());
}
-void WebBrowser::navigateToUrl(const QString &textual_url) {
- QUrl extracted_url = QUrl::fromUserInput(textual_url);
-
- if (extracted_url.isValid()) {
- m_webView->load(extracted_url);
+void WebBrowser::navigateToUrl(const QUrl &url) {
+ if (url.isValid()) {
+ m_webView->load(url);
}
}
+void WebBrowser::navigateToUrl(const QString &textual_url) {
+ navigateToUrl(QUrl::fromUserInput(textual_url));
+}
+
WebBrowser::~WebBrowser() {
qDebug("Erasing WebBrowser instance.");
@@ -105,6 +110,14 @@ WebBrowser::~WebBrowser() {
delete m_layout;
}
+WebBrowser *WebBrowser::webBrowser() {
+ return this;
+}
+
+QMenu *WebBrowser::globalMenu() {
+ return nullptr;
+}
+
void WebBrowser::setupIcons() {
m_actionBack->setIcon(ThemeFactory::fromTheme("go-previous"));
m_actionForward->setIcon(ThemeFactory::fromTheme("go-next"));
@@ -123,7 +136,6 @@ void WebBrowser::setNavigationBarVisible(bool visible) {
WebBrowserNetworkAccessManager *WebBrowser::globalNetworkManager() {
if (m_networkManager.isNull()) {
- // TODO: Not sure if qApp is needed here.
m_networkManager = new WebBrowserNetworkAccessManager(qApp);
}
diff --git a/src/gui/webbrowser.h b/src/gui/webbrowser.h
index 2df9668f7..86dae4988 100644
--- a/src/gui/webbrowser.h
+++ b/src/gui/webbrowser.h
@@ -3,14 +3,17 @@
#include
+#include "gui/tabcontent.h"
+
class QToolBar;
class QVBoxLayout;
class LocationLineEdit;
class BaseWebView;
class WebBrowserNetworkAccessManager;
+class QMenu;
-class WebBrowser : public QWidget {
+class WebBrowser : public TabContent {
Q_OBJECT
public:
@@ -21,6 +24,13 @@ class WebBrowser : public QWidget {
// Reloads icons for all buttons.
void setupIcons();
+ // Returns this instance.
+ // NOTE: This is needed due to TabContent interface.
+ WebBrowser *webBrowser();
+
+ // Returns global menu for this web browser.
+ QMenu *globalMenu();
+
// Returns pointer to global network access manager
// for web browsers.
// NOTE: All web browsers use shared network access manager,
@@ -31,8 +41,13 @@ class WebBrowser : public QWidget {
static QList runningWebBrowsers();
public slots:
+ // Switches visibility of navigation bar.
void setNavigationBarVisible(bool visible);
+ // Loads new url into the web browser.
+ void navigateToUrl(const QString &url);
+ void navigateToUrl(const QUrl &url);
+
protected:
// Creates necessary connections.
void createConnections();
@@ -41,8 +56,8 @@ class WebBrowser : public QWidget {
// Updates url (for example on location text box).
void updateUrl(const QUrl &url);
- // Loads new url into the web browser.
- void navigateToUrl(const QString &url);
+ signals:
+ void newTabRequested();
private:
QVBoxLayout *m_layout;
diff --git a/src/main.cpp b/src/main.cpp
index ddf2fbde6..ca6701868 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -62,8 +62,9 @@ int main(int argc, char *argv[]) {
QtSingleApplication::addLibraryPath(APP_PLUGIN_PATH);
#endif
- // Add an extra path for non-system icon themes.
+ // Add an extra path for non-system icon themes and set current icon theme.
ThemeFactory::setupSearchPaths();
+ ThemeFactory::loadCurrentIconTheme(false);
// Load localization and setup locale before any widget is constructed.
LoadLocalization();
@@ -110,7 +111,7 @@ int main(int argc, char *argv[]) {
// Load icon theme from settings.
// NOTE: Make sure that this is done after main window and
// other startup widgets are created.
- ThemeFactory::loadCurrentIconTheme();
+ //ThemeFactory::loadCurrentIconTheme();
// Setup single-instance behavior.
QObject::connect(&application, &QtSingleApplication::messageReceived,