Falkon Develop
Cross-platform Qt-based web browser
history.cpp
Go to the documentation of this file.
1/* ============================================================
2* Falkon - Qt web browser
3* Copyright (C) 2010-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 "history.h"
19#include "historymodel.h"
20#include "browserwindow.h"
21#include "iconprovider.h"
22#include "settings.h"
23#include "mainapplication.h"
24#include "sqldatabase.h"
25#include "webview.h"
26#include "qzsettings.h"
27
28#include <QWebEngineProfile>
29
30History::History(QObject* parent)
31 : QObject(parent)
32 , m_isSaving(true)
33 , m_model(nullptr)
34{
36}
37
39{
40 if (!m_model) {
41 m_model = new HistoryModel(this);
42 }
43
44 return m_model;
45}
46
48{
49 Settings settings;
50 settings.beginGroup(QSL("Web-Browser-Settings"));
51 m_isSaving = settings.value(QSL("allowHistory"), true).toBool();
52 settings.endGroup();
53}
54
55// AddHistoryEntry
57{
58 if (!m_isSaving) {
59 return;
60 }
61
62 const QUrl url = view->url();
63 const QString title = view->title();
64
65 addHistoryEntry(url, title);
66}
67
68void History::addHistoryEntry(const QUrl &url, QString title)
69{
70 if (!m_isSaving) {
71 return;
72 }
73
74 const QStringList schemes = {
75 QSL("http"), QSL("https"), QSL("ftp"), QSL("file")
76 };
77
78 if (!schemes.contains(url.scheme()) && !qzSettings->allowedSchemes.contains(url.scheme())) {
79 return;
80 }
81
82 if (title.isEmpty()) {
83 title = tr("Empty Page");
84 }
85
86 auto job = new SqlQueryJob(QSL("SELECT id, count, date, title FROM history WHERE url=?"), this);
87 job->addBindValue(url);
88 connect(job, &SqlQueryJob::finished, this, [=]() {
89 if (job->records().isEmpty()) {
90 auto job = new SqlQueryJob(QSL("INSERT INTO history (count, date, url, title) VALUES (1,?,?,?)"), this);
91 job->addBindValue(QDateTime::currentMSecsSinceEpoch());
92 job->addBindValue(url);
93 job->addBindValue(title);
94 connect(job, &SqlQueryJob::finished, this, [=]() {
95 HistoryEntry entry;
96 entry.id = job->lastInsertId().toInt();
97 entry.count = 1;
98 entry.date = QDateTime::currentDateTime();
99 entry.url = url;
100 entry.urlString = QString::fromUtf8(url.toEncoded());
101 entry.title = title;
102 Q_EMIT historyEntryAdded(entry);
103 });
104 job->start();
105 } else {
106 const auto record = job->records().at(0);
107 const int id = record.value(0).toInt();
108 const int count = record.value(1).toInt();
109 const QDateTime date = QDateTime::fromMSecsSinceEpoch(record.value(2).toLongLong());
110 const QString oldTitle = record.value(3).toString();
111
112 auto job = new SqlQueryJob(QSL("UPDATE history SET count = count + 1, date=?, title=? WHERE url=?"), this);
113 job->addBindValue(QDateTime::currentMSecsSinceEpoch());
114 job->addBindValue(title);
115 job->addBindValue(url);
116 connect(job, &SqlQueryJob::finished, this, [=]() {
117 HistoryEntry before;
118 before.id = id;
119 before.count = count;
120 before.date = date;
121 before.url = url;
122 before.urlString = QString::fromUtf8(url.toEncoded());
123 before.title = oldTitle;
124
125 HistoryEntry after = before;
126 after.count = count + 1;
127 after.date = QDateTime::currentDateTime();
128 after.title = title;
129
130 Q_EMIT historyEntryEdited(before, after);
131 });
132 job->start();
133 }
134 });
135 job->start();
136}
137
138// DeleteHistoryEntry
140{
141 QList<int> list;
142 list.append(index);
143
144 deleteHistoryEntry(list);
145}
146
147void History::deleteHistoryEntry(const QList<int> &list)
148{
149 QSqlDatabase db = SqlDatabase::instance()->database();
150 db.transaction();
151
152 for (int index : list) {
153 QSqlQuery query(SqlDatabase::instance()->database());
154 query.prepare(QSL("SELECT count, date, url, title FROM history WHERE id=?"));
155 query.addBindValue(index);
156 query.exec();
157
158 if (!query.isActive() || !query.next()) {
159 continue;
160 }
161
162 HistoryEntry entry;
163 entry.id = index;
164 entry.count = query.value(0).toInt();
165 entry.date = QDateTime::fromMSecsSinceEpoch(query.value(1).toLongLong());
166 entry.url = query.value(2).toUrl();
167 entry.urlString = QString::fromUtf8(entry.url.toEncoded());
168 entry.title = query.value(3).toString();
169
170 query.prepare(QSL("DELETE FROM history WHERE id=?"));
171 query.addBindValue(index);
172 query.exec();
173
174 query.prepare(QSL("DELETE FROM icons WHERE url=?"));
175 query.addBindValue(entry.url.toEncoded(QUrl::RemoveFragment));
176 query.exec();
177
178 Q_EMIT historyEntryDeleted(entry);
179 }
180
181 db.commit();
182}
183
184void History::deleteHistoryEntry(const QString &url)
185{
186 QSqlQuery query(SqlDatabase::instance()->database());
187 query.prepare(QSL("SELECT id FROM history WHERE url=?"));
188 query.bindValue(0, url);
189 query.exec();
190 if (query.next()) {
191 int id = query.value(0).toInt();
193 }
194}
195
196void History::deleteHistoryEntry(const QString &url, const QString &title)
197{
198 QSqlQuery query(SqlDatabase::instance()->database());
199 query.prepare(QSL("SELECT id FROM history WHERE url=? AND title=?"));
200 query.bindValue(0, url);
201 query.bindValue(1, title);
202 query.exec();
203 if (query.next()) {
204 int id = query.value(0).toInt();
206 }
207}
208
209QList<int> History::indexesFromTimeRange(qint64 start, qint64 end)
210{
211 QList<int> list;
212
213 if (start < 0 || end < 0) {
214 return list;
215 }
216
217 QSqlQuery query(SqlDatabase::instance()->database());
218 query.prepare(QSL("SELECT id FROM history WHERE date BETWEEN ? AND ?"));
219 query.addBindValue(end);
220 query.addBindValue(start);
221 query.exec();
222
223 while (query.next()) {
224 list.append(query.value(0).toInt());
225 }
226
227 return list;
228}
229
230QVector<HistoryEntry> History::mostVisited(int count)
231{
232 QVector<HistoryEntry> list;
233 QSqlQuery query(SqlDatabase::instance()->database());
234 query.prepare(QSL("SELECT count, date, id, title, url FROM history ORDER BY count DESC LIMIT %1").arg(count));
235 query.exec();
236 while (query.next()) {
237 HistoryEntry entry;
238 entry.count = query.value(0).toInt();
239 entry.date = query.value(1).toDateTime();
240 entry.id = query.value(2).toInt();
241 entry.title = query.value(3).toString();
242 entry.url = query.value(4).toUrl();
243 list.append(entry);
244 }
245 return list;
246}
247
249{
250 QSqlQuery query(SqlDatabase::instance()->database());
251 query.exec(QSL("DELETE FROM history"));
252 query.exec(QSL("VACUUM"));
253
254 mApp->webProfile()->clearAllVisitedLinks();
255
256 Q_EMIT resetHistory();
257}
258
260{
261 m_isSaving = state;
262}
263
265{
266 return m_isSaving;
267}
268
270{
271 switch (month) {
272 case 1:
273 return tr("January");
274 case 2:
275 return tr("February");
276 case 3:
277 return tr("March");
278 case 4:
279 return tr("April");
280 case 5:
281 return tr("May");
282 case 6:
283 return tr("June");
284 case 7:
285 return tr("July");
286 case 8:
287 return tr("August");
288 case 9:
289 return tr("September");
290 case 10:
291 return tr("October");
292 case 11:
293 return tr("November");
294 case 12:
295 return tr("December");
296 default:
297 qWarning("Month number out of range!");
298 return {};
299 }
300}
301
302QList<HistoryEntry> History::searchHistoryEntry(const QString &text)
303{
304 QList<HistoryEntry> list;
305 QSqlQuery query(SqlDatabase::instance()->database());
306 query.prepare(QSL("SELECT count, date, id, title, url FROM history WHERE title LIKE ? OR url LIKE ?"));
307 query.bindValue(0, QSL("%%1%").arg(text));
308 query.bindValue(1, QSL("%%1%").arg(text));
309 query.exec();
310 while (query.next()) {
311 HistoryEntry entry;
312 entry.count = query.value(0).toInt();
313 entry.date = query.value(1).toDateTime();
314 entry.id = query.value(2).toInt();
315 entry.title = query.value(3).toString();
316 entry.url = query.value(4).toUrl();
317 list.append(entry);
318 }
319 return list;
320}
321
323{
324 QSqlQuery query(SqlDatabase::instance()->database());
325 query.prepare(QSL("SELECT count, date, id, title, url FROM history WHERE url = ?"));
326 query.bindValue(0, text);
327 query.exec();
328
329 HistoryEntry entry;
330 if (query.next()) {
331 entry.count = query.value(0).toInt();
332 entry.date = query.value(1).toDateTime();
333 entry.id = query.value(2).toInt();
334 entry.title = query.value(3).toString();
335 entry.url = query.value(4).toUrl();
336 }
337 return entry;
338}
History(QObject *parent)
Definition: history.cpp:30
QList< int > indexesFromTimeRange(qint64 start, qint64 end)
Definition: history.cpp:209
HistoryEntry getHistoryEntry(const QString &text)
Definition: history.cpp:322
void historyEntryDeleted(const HistoryEntry &entry)
void setSaving(bool state)
Definition: history.cpp:259
void historyEntryEdited(const HistoryEntry &before, const HistoryEntry &after)
void addHistoryEntry(WebView *view)
Definition: history.cpp:56
void clearHistory()
Definition: history.cpp:248
void deleteHistoryEntry(int index)
Definition: history.cpp:139
HistoryModel * model()
Definition: history.cpp:38
QVector< HistoryEntry > mostVisited(int count)
Definition: history.cpp:230
void resetHistory()
QList< HistoryEntry > searchHistoryEntry(const QString &text)
Definition: history.cpp:302
bool isSaving()
Definition: history.cpp:264
static QString titleCaseLocalizedMonth(int month)
Definition: history.cpp:269
void loadSettings()
Definition: history.cpp:47
void beginGroup(const QString &prefix)
Definition: settings.cpp:79
void endGroup()
Definition: settings.cpp:84
QVariant value(const QString &key, const QVariant &defaultValue=QVariant())
Definition: settings.cpp:74
static SqlDatabase * instance()
QSqlDatabase database()
void finished(SqlQueryJob *job)
QString title(bool allowEmpty=false) const
Definition: webview.cpp:107
#define mApp
State state
#define QSL(x)
Definition: qzcommon.h:40
#define qzSettings
Definition: qzsettings.h:69
Definition: history.h:39
QDateTime date
Definition: history.h:42
QString title
Definition: history.h:45
int id
Definition: history.h:40
QUrl url
Definition: history.h:43
QString urlString
Definition: history.h:44
int count
Definition: history.h:41