File indexing completed on 2024-05-12 04:58:05

0001 /* ============================================================
0002 * Falkon - Qt web browser
0003 * Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com>
0004 *
0005 * This program is free software: you can redistribute it and/or modify
0006 * it under the terms of the GNU General Public License as published by
0007 * the Free Software Foundation, either version 3 of the License, or
0008 * (at your option) any later version.
0009 *
0010 * This program is distributed in the hope that it will be useful,
0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013 * GNU General Public License for more details.
0014 *
0015 * You should have received a copy of the GNU General Public License
0016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017 * ============================================================ */
0018 #include "history.h"
0019 #include "historymodel.h"
0020 #include "browserwindow.h"
0021 #include "iconprovider.h"
0022 #include "settings.h"
0023 #include "mainapplication.h"
0024 #include "sqldatabase.h"
0025 #include "webview.h"
0026 #include "qzsettings.h"
0027 
0028 #include <QWebEngineProfile>
0029 
0030 History::History(QObject* parent)
0031     : QObject(parent)
0032     , m_isSaving(true)
0033     , m_model(nullptr)
0034 {
0035     loadSettings();
0036 }
0037 
0038 HistoryModel* History::model()
0039 {
0040     if (!m_model) {
0041         m_model = new HistoryModel(this);
0042     }
0043 
0044     return m_model;
0045 }
0046 
0047 void History::loadSettings()
0048 {
0049     Settings settings;
0050     settings.beginGroup(QSL("Web-Browser-Settings"));
0051     m_isSaving = settings.value(QSL("allowHistory"), true).toBool();
0052     settings.endGroup();
0053 }
0054 
0055 // AddHistoryEntry
0056 void History::addHistoryEntry(WebView* view)
0057 {
0058     if (!m_isSaving) {
0059         return;
0060     }
0061 
0062     const QUrl url = view->url();
0063     const QString title = view->title();
0064 
0065     addHistoryEntry(url, title);
0066 }
0067 
0068 void History::addHistoryEntry(const QUrl &url, QString title)
0069 {
0070     if (!m_isSaving) {
0071         return;
0072     }
0073 
0074     const QStringList schemes = {
0075         QSL("http"), QSL("https"), QSL("ftp"), QSL("file")
0076     };
0077 
0078     if (!schemes.contains(url.scheme()) && !qzSettings->allowedSchemes.contains(url.scheme())) {
0079         return;
0080     }
0081 
0082     if (title.isEmpty()) {
0083         title = tr("Empty Page");
0084     }
0085 
0086     auto job = new SqlQueryJob(QSL("SELECT id, count, date, title FROM history WHERE url=?"), this);
0087     job->addBindValue(url);
0088     connect(job, &SqlQueryJob::finished, this, [=]() {
0089         if (job->records().isEmpty()) {
0090             auto job = new SqlQueryJob(QSL("INSERT INTO history (count, date, url, title) VALUES (1,?,?,?)"), this);
0091             job->addBindValue(QDateTime::currentMSecsSinceEpoch());
0092             job->addBindValue(url);
0093             job->addBindValue(title);
0094             connect(job, &SqlQueryJob::finished, this, [=]() {
0095                 HistoryEntry entry;
0096                 entry.id = job->lastInsertId().toInt();
0097                 entry.count = 1;
0098                 entry.date = QDateTime::currentDateTime();
0099                 entry.url = url;
0100                 entry.urlString = QString::fromUtf8(url.toEncoded());
0101                 entry.title = title;
0102                 Q_EMIT historyEntryAdded(entry);
0103             });
0104             job->start();
0105         } else {
0106             const auto record = job->records().at(0);
0107             const int id = record.value(0).toInt();
0108             const int count = record.value(1).toInt();
0109             const QDateTime date = QDateTime::fromMSecsSinceEpoch(record.value(2).toLongLong());
0110             const QString oldTitle = record.value(3).toString();
0111 
0112             auto job = new SqlQueryJob(QSL("UPDATE history SET count = count + 1, date=?, title=? WHERE url=?"), this);
0113             job->addBindValue(QDateTime::currentMSecsSinceEpoch());
0114             job->addBindValue(title);
0115             job->addBindValue(url);
0116             connect(job, &SqlQueryJob::finished, this, [=]() {
0117                 HistoryEntry before;
0118                 before.id = id;
0119                 before.count = count;
0120                 before.date = date;
0121                 before.url = url;
0122                 before.urlString = QString::fromUtf8(url.toEncoded());
0123                 before.title = oldTitle;
0124 
0125                 HistoryEntry after = before;
0126                 after.count = count + 1;
0127                 after.date = QDateTime::currentDateTime();
0128                 after.title = title;
0129 
0130                 Q_EMIT historyEntryEdited(before, after);
0131             });
0132             job->start();
0133         }
0134     });
0135     job->start();
0136 }
0137 
0138 // DeleteHistoryEntry
0139 void History::deleteHistoryEntry(int index)
0140 {
0141     QList<int> list;
0142     list.append(index);
0143 
0144     deleteHistoryEntry(list);
0145 }
0146 
0147 void History::deleteHistoryEntry(const QList<int> &list)
0148 {
0149     QSqlDatabase db = SqlDatabase::instance()->database();
0150     db.transaction();
0151 
0152     for (int index : list) {
0153         QSqlQuery query(SqlDatabase::instance()->database());
0154         query.prepare(QSL("SELECT count, date, url, title FROM history WHERE id=?"));
0155         query.addBindValue(index);
0156         query.exec();
0157 
0158         if (!query.isActive() || !query.next()) {
0159             continue;
0160         }
0161 
0162         HistoryEntry entry;
0163         entry.id = index;
0164         entry.count = query.value(0).toInt();
0165         entry.date = QDateTime::fromMSecsSinceEpoch(query.value(1).toLongLong());
0166         entry.url = query.value(2).toUrl();
0167         entry.urlString = QString::fromUtf8(entry.url.toEncoded());
0168         entry.title = query.value(3).toString();
0169 
0170         query.prepare(QSL("DELETE FROM history WHERE id=?"));
0171         query.addBindValue(index);
0172         query.exec();
0173 
0174         query.prepare(QSL("DELETE FROM icons WHERE url=?"));
0175         query.addBindValue(entry.url.toEncoded(QUrl::RemoveFragment));
0176         query.exec();
0177 
0178         Q_EMIT historyEntryDeleted(entry);
0179     }
0180 
0181     db.commit();
0182 }
0183 
0184 void History::deleteHistoryEntry(const QString &url)
0185 {
0186     QSqlQuery query(SqlDatabase::instance()->database());
0187     query.prepare(QSL("SELECT id FROM history WHERE url=?"));
0188     query.bindValue(0, url);
0189     query.exec();
0190     if (query.next()) {
0191         int id = query.value(0).toInt();
0192         deleteHistoryEntry(id);
0193     }
0194 }
0195 
0196 void History::deleteHistoryEntry(const QString &url, const QString &title)
0197 {
0198     QSqlQuery query(SqlDatabase::instance()->database());
0199     query.prepare(QSL("SELECT id FROM history WHERE url=? AND title=?"));
0200     query.bindValue(0, url);
0201     query.bindValue(1, title);
0202     query.exec();
0203     if (query.next()) {
0204         int id = query.value(0).toInt();
0205         deleteHistoryEntry(id);
0206     }
0207 }
0208 
0209 QList<int> History::indexesFromTimeRange(qint64 start, qint64 end)
0210 {
0211     QList<int> list;
0212 
0213     if (start < 0 || end < 0) {
0214         return list;
0215     }
0216 
0217     QSqlQuery query(SqlDatabase::instance()->database());
0218     query.prepare(QSL("SELECT id FROM history WHERE date BETWEEN ? AND ?"));
0219     query.addBindValue(end);
0220     query.addBindValue(start);
0221     query.exec();
0222 
0223     while (query.next()) {
0224         list.append(query.value(0).toInt());
0225     }
0226 
0227     return list;
0228 }
0229 
0230 QVector<HistoryEntry> History::mostVisited(int count)
0231 {
0232     QVector<HistoryEntry> list;
0233     QSqlQuery query(SqlDatabase::instance()->database());
0234     query.prepare(QSL("SELECT count, date, id, title, url FROM history ORDER BY count DESC LIMIT %1").arg(count));
0235     query.exec();
0236     while (query.next()) {
0237         HistoryEntry entry;
0238         entry.count = query.value(0).toInt();
0239         entry.date = query.value(1).toDateTime();
0240         entry.id = query.value(2).toInt();
0241         entry.title = query.value(3).toString();
0242         entry.url = query.value(4).toUrl();
0243         list.append(entry);
0244     }
0245     return list;
0246 }
0247 
0248 void History::clearHistory()
0249 {
0250     QSqlQuery query(SqlDatabase::instance()->database());
0251     query.exec(QSL("DELETE FROM history"));
0252     query.exec(QSL("VACUUM"));
0253 
0254     mApp->webProfile()->clearAllVisitedLinks();
0255 
0256     Q_EMIT resetHistory();
0257 }
0258 
0259 void History::setSaving(bool state)
0260 {
0261     m_isSaving = state;
0262 }
0263 
0264 bool History::isSaving()
0265 {
0266     return m_isSaving;
0267 }
0268 
0269 QString History::titleCaseLocalizedMonth(int month)
0270 {
0271     switch (month) {
0272     case 1:
0273         return tr("January");
0274     case 2:
0275         return tr("February");
0276     case 3:
0277         return tr("March");
0278     case 4:
0279         return tr("April");
0280     case 5:
0281         return tr("May");
0282     case 6:
0283         return tr("June");
0284     case 7:
0285         return tr("July");
0286     case 8:
0287         return tr("August");
0288     case 9:
0289         return tr("September");
0290     case 10:
0291         return tr("October");
0292     case 11:
0293         return tr("November");
0294     case 12:
0295         return tr("December");
0296     default:
0297         qWarning("Month number out of range!");
0298         return {};
0299     }
0300 }
0301 
0302 QList<HistoryEntry> History::searchHistoryEntry(const QString &text)
0303 {
0304     QList<HistoryEntry> list;
0305     QSqlQuery query(SqlDatabase::instance()->database());
0306     query.prepare(QSL("SELECT count, date, id, title, url FROM history WHERE title LIKE ? OR url LIKE ?"));
0307     query.bindValue(0, QSL("%%1%").arg(text));
0308     query.bindValue(1, QSL("%%1%").arg(text));
0309     query.exec();
0310     while (query.next()) {
0311         HistoryEntry entry;
0312         entry.count = query.value(0).toInt();
0313         entry.date = query.value(1).toDateTime();
0314         entry.id = query.value(2).toInt();
0315         entry.title = query.value(3).toString();
0316         entry.url = query.value(4).toUrl();
0317         list.append(entry);
0318     }
0319     return list;
0320 }
0321 
0322 HistoryEntry History::getHistoryEntry(const QString &text)
0323 {
0324     QSqlQuery query(SqlDatabase::instance()->database());
0325     query.prepare(QSL("SELECT count, date, id, title, url FROM history WHERE url = ?"));
0326     query.bindValue(0, text);
0327     query.exec();
0328 
0329     HistoryEntry entry;
0330     if (query.next()) {
0331         entry.count = query.value(0).toInt();
0332         entry.date = query.value(1).toDateTime();
0333         entry.id = query.value(2).toInt();
0334         entry.title = query.value(3).toString();
0335         entry.url = query.value(4).toUrl();
0336     }
0337     return entry;
0338 }