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 -
webbrowser.h
+ TabWidget + QTabWidget +
tabwidget.h
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,