1 /* ============================================================
2 * Falkon - Qt web browser
3 * Copyright (C) 2014-2018 David Rosca <nowrep@gmail.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 * ============================================================ */
18 #include "historymenu.h"
19 #include "iconprovider.h"
20 #include "browserwindow.h"
21 #include "tabbedwebview.h"
22 #include "mainapplication.h"
23 #include "closedtabsmanager.h"
24 #include "tabwidget.h"
25 #include "qztools.h"
26 #include "history.h"
27 #include "qzsettings.h"
28 #include "sqldatabase.h"
29 #include "closedwindowsmanager.h"
30 
31 #include <QApplication>
32 #include <QWebEngineHistory>
33 
HistoryMenu(QWidget * parent)34 HistoryMenu::HistoryMenu(QWidget* parent)
35     : Menu(parent)
36 {
37     init();
38 }
39 
setMainWindow(BrowserWindow * window)40 void HistoryMenu::setMainWindow(BrowserWindow* window)
41 {
42     m_window = window;
43 }
44 
goBack()45 void HistoryMenu::goBack()
46 {
47     if (m_window) {
48         m_window->goBack();
49     }
50 }
51 
goForward()52 void HistoryMenu::goForward()
53 {
54     if (m_window) {
55         m_window->goForward();
56     }
57 }
58 
goHome()59 void HistoryMenu::goHome()
60 {
61     if (m_window) {
62         m_window->goHome();
63     }
64 }
65 
showHistoryManager()66 void HistoryMenu::showHistoryManager()
67 {
68     if (m_window) {
69         m_window->showHistoryManager();
70     }
71 }
72 
aboutToShow()73 void HistoryMenu::aboutToShow()
74 {
75     // Set enabled states for Back/Forward actions according to current WebView
76     TabbedWebView* view = m_window ? m_window->weView() : 0;
77 
78     if (view) {
79         actions().at(0)->setEnabled(view->history()->canGoBack());
80         actions().at(1)->setEnabled(view->history()->canGoForward());
81     }
82 
83     while (actions().count() != 8) {
84         QAction* act = actions().at(8);
85         if (act->menu()) {
86             act->menu()->clear();
87         }
88         removeAction(act);
89         delete act;
90     }
91 
92     addSeparator();
93 
94     QSqlQuery query(SqlDatabase::instance()->database());
95     query.exec(QSL("SELECT title, url FROM history ORDER BY date DESC LIMIT 10"));
96 
97     while (query.next()) {
98         const QUrl url = query.value(1).toUrl();
99         const QString title = QzTools::truncatedText(query.value(0).toString(), 40);
100 
101         Action* act = new Action(title);
102         act->setData(url);
103         act->setIcon(IconProvider::iconForUrl(url));
104         connect(act, &QAction::triggered, this, &HistoryMenu::historyEntryActivated);
105         connect(act, &Action::ctrlTriggered, this, &HistoryMenu::historyEntryCtrlActivated);
106         connect(act, &Action::shiftTriggered, this, &HistoryMenu::historyEntryShiftActivated);
107         addAction(act);
108     }
109 }
110 
aboutToHide()111 void HistoryMenu::aboutToHide()
112 {
113     // Enable Back/Forward actions to ensure shortcuts are working
114     actions().at(0)->setEnabled(true);
115     actions().at(1)->setEnabled(true);
116 }
117 
aboutToShowMostVisited()118 void HistoryMenu::aboutToShowMostVisited()
119 {
120     m_menuMostVisited->clear();
121 
122     const QVector<HistoryEntry> mostVisited = mApp->history()->mostVisited(10);
123 
124     for (const HistoryEntry &entry : mostVisited) {
125         Action* act = new Action(QzTools::truncatedText(entry.title, 40));
126         act->setData(entry.url);
127         act->setIcon(IconProvider::iconForUrl(entry.url));
128         connect(act, &QAction::triggered, this, &HistoryMenu::historyEntryActivated);
129         connect(act, &Action::ctrlTriggered, this, &HistoryMenu::historyEntryCtrlActivated);
130         connect(act, &Action::shiftTriggered, this, &HistoryMenu::historyEntryShiftActivated);
131         m_menuMostVisited->addAction(act);
132     }
133 
134     if (m_menuMostVisited->isEmpty()) {
135         m_menuMostVisited->addAction(tr("Empty"))->setEnabled(false);
136     }
137 }
138 
aboutToShowClosedTabs()139 void HistoryMenu::aboutToShowClosedTabs()
140 {
141     m_menuClosedTabs->clear();
142 
143     if (!m_window) {
144         return;
145     }
146 
147     TabWidget* tabWidget = m_window->tabWidget();
148 
149     const auto closedTabs = tabWidget->closedTabsManager()->closedTabs();
150     for (int i = 0; i < closedTabs.count(); ++i) {
151         const ClosedTabsManager::Tab tab = closedTabs.at(i);
152         const QString title = QzTools::truncatedText(tab.tabState.title, 40);
153         m_menuClosedTabs->addAction(tab.tabState.icon, title, tabWidget, SLOT(restoreClosedTab()))->setData(i);
154     }
155 
156     if (m_menuClosedTabs->isEmpty()) {
157         m_menuClosedTabs->addAction(tr("Empty"))->setEnabled(false);
158     }
159     else {
160         m_menuClosedTabs->addSeparator();
161         m_menuClosedTabs->addAction(tr("Restore All Closed Tabs"), tabWidget, &TabWidget::restoreAllClosedTabs);
162         m_menuClosedTabs->addAction(QIcon::fromTheme(QSL("edit-clear")), tr("Clear list"), tabWidget, &TabWidget::clearClosedTabsList);
163     }
164 }
165 
aboutToShowClosedWindows()166 void HistoryMenu::aboutToShowClosedWindows()
167 {
168     m_menuClosedWindows->clear();
169 
170     ClosedWindowsManager *manager = mApp->closedWindowsManager();
171 
172     const auto closedWindows = manager->closedWindows();
173     for (int i = 0; i < closedWindows.count(); ++i) {
174         const ClosedWindowsManager::Window window = closedWindows.at(i);
175         const QString title = QzTools::truncatedText(window.title, 40);
176         QAction *act = m_menuClosedWindows->addAction(window.icon, title, manager, &ClosedWindowsManager::restoreClosedWindow);
177         if (i == 0) {
178             act->setShortcut(QKeySequence(QSL("Ctrl+Shift+N")));
179             act->setShortcutContext(Qt::WidgetShortcut);
180         } else {
181             act->setData(i);
182         }
183     }
184 
185     if (m_menuClosedWindows->isEmpty()) {
186         m_menuClosedWindows->addAction(tr("Empty"))->setEnabled(false);
187     } else {
188         m_menuClosedWindows->addSeparator();
189         m_menuClosedWindows->addAction(tr("Restore All Closed Windows"), manager, &ClosedWindowsManager::restoreAllClosedWindows);
190         m_menuClosedWindows->addAction(QIcon::fromTheme(QSL("edit-clear")), tr("Clear list"), manager, &ClosedWindowsManager::clearClosedWindows);
191     }
192 }
193 
historyEntryActivated()194 void HistoryMenu::historyEntryActivated()
195 {
196     if (QAction* action = qobject_cast<QAction*>(sender())) {
197         openUrl(action->data().toUrl());
198     }
199 }
200 
historyEntryCtrlActivated()201 void HistoryMenu::historyEntryCtrlActivated()
202 {
203     if (QAction* action = qobject_cast<QAction*>(sender())) {
204         openUrlInNewTab(action->data().toUrl());
205     }
206 }
207 
historyEntryShiftActivated()208 void HistoryMenu::historyEntryShiftActivated()
209 {
210     if (QAction* action = qobject_cast<QAction*>(sender())) {
211         openUrlInNewWindow(action->data().toUrl());
212     }
213 }
214 
openUrl(const QUrl & url)215 void HistoryMenu::openUrl(const QUrl &url)
216 {
217     if (m_window) {
218         m_window->loadAddress(url);
219     }
220 }
221 
openUrlInNewTab(const QUrl & url)222 void HistoryMenu::openUrlInNewTab(const QUrl &url)
223 {
224     if (m_window) {
225         m_window->tabWidget()->addView(url, qzSettings->newTabPosition);
226     }
227 }
228 
openUrlInNewWindow(const QUrl & url)229 void HistoryMenu::openUrlInNewWindow(const QUrl &url)
230 {
231     mApp->createWindow(Qz::BW_NewWindow, url);
232 }
233 
init()234 void HistoryMenu::init()
235 {
236     setTitle(tr("Hi&story"));
237 
238     QAction* act = addAction(IconProvider::standardIcon(QStyle::SP_ArrowBack), tr("&Back"), this, &HistoryMenu::goBack);
239     act->setShortcut(QzTools::actionShortcut(QKeySequence::Back, Qt::ALT + Qt::Key_Left, QKeySequence::Forward, Qt::ALT + Qt::Key_Right));
240 
241     act = addAction(IconProvider::standardIcon(QStyle::SP_ArrowForward), tr("&Forward"), this, &HistoryMenu::goForward);
242     act->setShortcut(QzTools::actionShortcut(QKeySequence::Forward, Qt::ALT + Qt::Key_Right, QKeySequence::Back, Qt::ALT + Qt::Key_Left));
243 
244     act = addAction(QIcon::fromTheme("go-home"), tr("&Home"), this, &HistoryMenu::goHome);
245     act->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Home));
246 
247     act = addAction(QIcon::fromTheme("deep-history", QIcon(":/icons/menu/history.svg")), tr("Show &All History"), this, &HistoryMenu::showHistoryManager);
248     act->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_H));
249 
250     addSeparator();
251 
252     connect(this, SIGNAL(aboutToShow()), this, SLOT(aboutToShow()));
253     connect(this, SIGNAL(aboutToHide()), this, SLOT(aboutToHide()));
254 
255     m_menuMostVisited = new Menu(tr("Most Visited"), this);
256     connect(m_menuMostVisited, &QMenu::aboutToShow, this, &HistoryMenu::aboutToShowMostVisited);
257 
258     m_menuClosedTabs = new Menu(tr("Closed Tabs"));
259     connect(m_menuClosedTabs, &QMenu::aboutToShow, this, &HistoryMenu::aboutToShowClosedTabs);
260 
261     m_menuClosedWindows = new Menu(tr("Closed Windows"));
262     connect(m_menuClosedWindows, &QMenu::aboutToShow, this, &HistoryMenu::aboutToShowClosedWindows);
263 
264     addMenu(m_menuMostVisited);
265     addMenu(m_menuClosedTabs);
266     addMenu(m_menuClosedWindows);
267 }
268