From c6c19ab43f78e00ed072d7c848f9549549bfb876 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 30 Jul 2013 18:54:36 +0200 Subject: [PATCH] Many many changes. --- CMakeLists.txt | 6 + localization/rssguard_cs.ts | 216 +++++++++--------- localization/rssguard_en.ts | 134 +++++------ .../mini-kfaenza/mimetypes/128/text-html.png | Bin 0 -> 15095 bytes .../mini-kfaenza/mimetypes/16/text-html.png | Bin 0 -> 770 bytes .../mini-kfaenza/mimetypes/22/text-html.png | Bin 0 -> 1022 bytes .../mini-kfaenza/mimetypes/32/text-html.png | Bin 0 -> 1819 bytes .../mini-kfaenza/mimetypes/48/text-html.png | Bin 0 -> 3352 bytes .../mini-kfaenza/mimetypes/64/text-html.png | Bin 0 -> 5155 bytes src/gui/basewebview.cpp | 1 - src/gui/dynamicshortcutswidget.cpp | 1 - src/gui/formmain.cpp | 71 +++++- src/gui/formmain.h | 20 +- src/gui/formmain.ui | 64 ++---- src/gui/formsettings.cpp | 31 ++- src/gui/formsettings.ui | 153 ++++++++----- src/gui/tabbar.cpp | 73 ++++++ src/gui/tabbar.h | 34 +++ src/gui/tabcontent.cpp | 16 ++ src/gui/tabcontent.h | 28 +++ src/gui/tabwidget.cpp | 60 +++++ src/gui/tabwidget.h | 41 ++++ src/gui/themefactory.cpp | 12 +- src/gui/themefactory.h | 9 +- src/gui/webbrowser.cpp | 40 ++-- src/gui/webbrowser.h | 21 +- src/main.cpp | 5 +- 27 files changed, 722 insertions(+), 314 deletions(-) create mode 100644 resources/graphics/themes/mini-kfaenza/mimetypes/128/text-html.png create mode 100644 resources/graphics/themes/mini-kfaenza/mimetypes/16/text-html.png create mode 100644 resources/graphics/themes/mini-kfaenza/mimetypes/22/text-html.png create mode 100644 resources/graphics/themes/mini-kfaenza/mimetypes/32/text-html.png create mode 100644 resources/graphics/themes/mini-kfaenza/mimetypes/48/text-html.png create mode 100644 resources/graphics/themes/mini-kfaenza/mimetypes/64/text-html.png create mode 100644 src/gui/tabbar.cpp create mode 100644 src/gui/tabbar.h create mode 100644 src/gui/tabcontent.cpp create mode 100644 src/gui/tabcontent.h create mode 100644 src/gui/tabwidget.cpp create mode 100644 src/gui/tabwidget.h 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 0000000000000000000000000000000000000000..a332b8937f3c2fedc22412c9d36fffe8172b5e64 GIT binary patch literal 15095 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 De$F<7gl*s8dQL~8^EWOcRC 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..2f94a7846c6e7061642b087fb4ba720df23d18c4 GIT binary patch literal 770 zcmV+d1O5DoP)gw0t`#U1?IUf8q|FA_- zEaiDlQ4|0u@bK}!Jl`3z@#=u{Gd0fS8F@A3i%a=2B+qktz21@yArL|U;N|X!pMQHs zty<=j_9d4IXAzVr#)5SNN2qFs461Dz2&FGNy4EMW}6ucvy;>( z5;nH?F($%exV!u(&IeQ#?>)vjhpO`9!@rSe?7`Lf8B!aQSc9mdz+|;VeImugmY;s@ zqpCRPFd>X-8?T0(o2m2VXQydoDK<7Fv7zw7V0Va!awe}(E+wpQ9iXa&5U@uh#Kv%S zeui>tF(x855jHkF-FQvmgw3~aP*w6;nPIH&M>qnUovyLH_m)R%TkH*sW4E(Xf{Di4 z@uG|hPwQ0WBw!*js0eE>_W0$=KRnyo#|Po^g(lx$yGWywA_9}ulq8N$0;cOJJGug;Fo{Xeny9&4@bbvm8-#l=OEB*DfJH?Fk*_lZ;$0OuUt zZWn89&t_S6yWj8M>2|x9KJ1alQ7V=CjYi}4J5=3(H%{8rYXATM07*qoM6N<$g05?9 AwEzGB literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..a56f11ddbc7a802f8e7527ba96d1596a423227ea GIT binary patch literal 1022 zcmV1Z$-gP#vlg5c@Q`)pDCPAX*z>5$$ z(F-TUhv@gom!OonWm|{%II`DoArAAu85$3AdcfF#+a(L zc5t*(>ZL;LXAGdVCeQP&D2lE-fbV%;_4xRB1U9_kWtHbSp668o-vN|}jDY$FBx%OC zzdYmd^A@{t!fTTe*Q*g@zQcQOOyW6aB#0r7QouyF+uhBwYy|rC&ucu|YEvE$aEvCm zFgrCyRB(9s=RQxLAF{YmVezf%2;6ZTf*_c50DU^*?^m{XxOqer`plF=suM+AM+4A2 zOhAF_x!nJ8og~e;bL;X*)PUB*R)`4AR>GGL)@XGy;v^#qeFD$m8jWi-e;sz%XtwF4 zIb&gguYOu*=djB#15hJifG?Jx5Ck6Oai2T4FH2BS5_g3Hc9@APX@ zXRJt4%ay4j<3$gp6k44?9iw@)b$|lILOV$j5nRVGUi8jb;Q-oNJFw!~Oo@Ybk5)G$ z3S4efOM_?%u0aF@K?LG%%7vmw=>7wKQDpkeJ1&JTl~Txq)orrOa@0+^H8%;s?YSv# z%#>K&IAC?-04qZ1I|PRFFR!oh(6HHzNqRY%6;{^v`0lr7Wcf*yVZo(Z4#}+`76L~z z9-4pmxNn7su(&YIew=W%Qp8#zw?ZlO$Z|`TTk_mu0c!=DXY95*EG|r+w&E<+%d>F>3UNRl2O%~$XpeFi+JykXTYMOYD*e|^gA#gMpj zjBv8%sFSj_7c=H*KKtM*wM)^6zx~Qnz_sn|?LU-KgFexpcjF#E{N7|g?$PR`FYdsl z9Ql0wc9nvwNBTq`JUu-LU*uv~QcJ>@@w$W%bhduf~qrbn= zXfy$9fTZ1Szger*u1ri!1X^p1G4y9+436UrzK8#5t1x;Jpcdz literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b01d141626528f9e118bc4624be1d1ab766288dc GIT binary patch literal 1819 zcmV+$2juvPP)<@LE;R#zyZWA5>a5KfGmf2oyCrw`RsQ0baz$lVcfkl zcCr#^SG-bbYWhRa8~KvwANy+#c>=uoeqxU&}=rzvJ7Jk zgTa8JC=f!>>-E^(-DN(X*KGN|Pp{WQN=aFkc%Fwb24f6S6xGjF>i|svxlEG~f<~iJ zQ)aEj7=sW3tu?Jy3n?YW7>c66^E~1>CeL%SEW=t$Q50yc5kerPT$#T~TE)TxvRW_* z0-DVxLI{Kqc%HZNQlrth1Y{|Vp})C>k`l*R$!iU)Y5)hRHqPn5AMk$3c1}P;{ z${K*NmJeQxc<-ODc=IZ;#b{cqhP3L0-^Vu=B+ zF%X7fZJ;d6h~t19?&>WqNdGdV3JA(#-g?XzTb_r%xf*O%hbh}-YQn(F|Cr2L= zg#o=apLcI{@LYu>1yTyCq#CY7Ys;ODh+J#3Tr&y-e*fep?|yF&DZp`@t7cp=p{NWZ zgrF!2q?E)-$}BDT=Kd{u?EqIfNC{Gk8bp#6#A!iZ8qOvu^U~06HrQAT7)=wD>!FM6 zP1|tA1GN|OJZC%}lOzd~_<~X|K!v`G5DVIc_yk0f6*U_|EJX2LhpZ^M(G5BN&uLu| zwbsk>U*84RT0GC=)~#FkzR#<1#+UBrOp=^&b55ZRgSCLbSw67^##pSq+-ATmE7|V0 z2tCExdXHAi#TZjp)~gb%*mE=*k!2YGrEo#O-p)ElXEC$1V0MwSx6`SMO@GZtNkO3v zhbL2vvCJ-VdXYz=ExzY`+R6G!C9IHjIvs=%IF3WEEq{4_M4D?pJdcTdmpCo>`-|7? zZbbCkJ^)ekvL0BA)`q+^?DQj^e>B2fD$!Sbu;KydDl}^?ju71J2Aqy!IxUZ3ypSQA zYf5d<+AfAMSiA7RFrG6_=DZrm-0U@Ru9V@WaFzko9(eikCCA6d93CE$r3nx3b(zE& z+uardI31^47bNC zQS!BS*7@M@l#6uE(aD5v*uZlgN^KXz7)oPN0$!a@$g+ZOfAJ1xN{5U8scxNQV1c~+1Xh^y}rJFEtA2Z?&xW^+x5KL?bg{# zDc{t?TCGe~GJYSoMFoGD^S#*}=iVq`r9hP2hPRKz*3}x8rRdxLhj( ztaAy#jz*)s2M-?H==FMD)e%?i^zvLviQ_o+e0f}bzRGm@_u$}Q_UO^0KR$c*>{r0K zxYRua_JJ=0tAc;_aSXf@7e002ov JPDHLkV1h;wZ#Dn` literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..36a1338c6a3f5997d7ada44b146bec6b745648bb GIT binary patch literal 3352 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 R*N^}J002ovPDHLkV1hsq-+urA literal 0 HcmV?d00001 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,