diff --git a/src/lib/tools/iconprovider.cpp b/src/lib/tools/iconprovider.cpp index 8c4be7d9..88739290 100644 --- a/src/lib/tools/iconprovider.cpp +++ b/src/lib/tools/iconprovider.cpp @@ -1,277 +1,287 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2018 David Rosca * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ============================================================ */ #include "iconprovider.h" #include "mainapplication.h" #include "networkmanager.h" #include "sqldatabase.h" #include "autosaver.h" #include "webview.h" #include "qztools.h" #include #include #include #include Q_GLOBAL_STATIC(IconProvider, qz_icon_provider) static QByteArray encodeUrl(const QUrl &url) { return url.toEncoded(QUrl::RemoveFragment | QUrl::StripTrailingSlash); } IconProvider::IconProvider() : QWidget() { m_autoSaver = new AutoSaver(this); connect(m_autoSaver, SIGNAL(save()), this, SLOT(saveIconsToDatabase())); } void IconProvider::saveIcon(WebView* view) { // Don't save icons in private mode. if (mApp->isPrivate()) { return; } const QIcon icon = view->icon(true); if (icon.isNull()) { return; } const QStringList ignoredSchemes = { QStringLiteral("falkon"), QStringLiteral("ftp"), QStringLiteral("file"), QStringLiteral("view-source"), QStringLiteral("data"), QStringLiteral("about") }; if (ignoredSchemes.contains(view->url().scheme())) { return; } for (int i = 0; i < m_iconBuffer.size(); ++i) { if (m_iconBuffer[i].first == view->url()) { m_iconBuffer.removeAt(i); break; } } BufferedIcon item; item.first = view->url(); item.second = icon.pixmap(16).toImage(); m_autoSaver->changeOccurred(); m_iconBuffer.append(item); } QIcon IconProvider::bookmarkIcon() const { return QIcon::fromTheme(QSL("bookmarks"), m_bookmarkIcon); } void IconProvider::setBookmarkIcon(const QIcon &icon) { m_bookmarkIcon = icon; } QIcon IconProvider::standardIcon(QStyle::StandardPixmap icon) { switch (icon) { case QStyle::SP_MessageBoxCritical: return QIcon::fromTheme(QSL("dialog-error"), QApplication::style()->standardIcon(icon)); case QStyle::SP_MessageBoxInformation: return QIcon::fromTheme(QSL("dialog-information"), QApplication::style()->standardIcon(icon)); case QStyle::SP_MessageBoxQuestion: return QIcon::fromTheme(QSL("dialog-question"), QApplication::style()->standardIcon(icon)); case QStyle::SP_MessageBoxWarning: return QIcon::fromTheme(QSL("dialog-warning"), QApplication::style()->standardIcon(icon)); case QStyle::SP_DialogCloseButton: return QIcon::fromTheme(QSL("dialog-close"), QApplication::style()->standardIcon(icon)); case QStyle::SP_BrowserStop: return QIcon::fromTheme(QSL("process-stop"), QApplication::style()->standardIcon(icon)); case QStyle::SP_BrowserReload: return QIcon::fromTheme(QSL("view-refresh"), QApplication::style()->standardIcon(icon)); case QStyle::SP_FileDialogToParent: return QIcon::fromTheme(QSL("go-up"), QApplication::style()->standardIcon(icon)); case QStyle::SP_ArrowUp: return QIcon::fromTheme(QSL("go-up"), QApplication::style()->standardIcon(icon)); case QStyle::SP_ArrowDown: return QIcon::fromTheme(QSL("go-down"), QApplication::style()->standardIcon(icon)); case QStyle::SP_ArrowForward: if (QApplication::layoutDirection() == Qt::RightToLeft) { return QIcon::fromTheme(QSL("go-previous"), QApplication::style()->standardIcon(icon)); } return QIcon::fromTheme(QSL("go-next"), QApplication::style()->standardIcon(icon)); case QStyle::SP_ArrowBack: if (QApplication::layoutDirection() == Qt::RightToLeft) { return QIcon::fromTheme(QSL("go-next"), QApplication::style()->standardIcon(icon)); } return QIcon::fromTheme(QSL("go-previous"), QApplication::style()->standardIcon(icon)); default: return QApplication::style()->standardIcon(icon); } } QIcon IconProvider::newTabIcon() { return QIcon::fromTheme(QSL("tab-new"), QIcon(QSL(":/icons/menu/tab-new.svg"))); } QIcon IconProvider::newWindowIcon() { return QIcon::fromTheme(QSL("window-new"), QIcon(QSL(":/icons/menu/window-new.svg"))); } QIcon IconProvider::privateBrowsingIcon() { return QIcon(QSL(":/icons/menu/privatebrowsing.png")); } QIcon IconProvider::settingsIcon() { return QIcon::fromTheme(QSL("configure"), QIcon(QSL(":/icons/menu/settings.svg"))); } QIcon IconProvider::emptyWebIcon() { return QPixmap::fromImage(instance()->emptyWebImage()); } QImage IconProvider::emptyWebImage() { if (instance()->m_emptyWebImage.isNull()) { instance()->m_emptyWebImage = QIcon(QSL(":icons/other/webpage.svg")).pixmap(16).toImage(); } return instance()->m_emptyWebImage; } QIcon IconProvider::iconForUrl(const QUrl &url, bool allowNull) { return instance()->iconFromImage(imageForUrl(url, allowNull)); } QImage IconProvider::imageForUrl(const QUrl &url, bool allowNull) { if (url.path().isEmpty()) { return allowNull ? QImage() : IconProvider::emptyWebImage(); } const QByteArray encodedUrl = encodeUrl(url); + if (QImage *img = instance()->m_urlImageCache.object(encodedUrl)) { + return img->isNull() && !allowNull ? IconProvider::emptyWebImage() : *img; + } + foreach (const BufferedIcon &ic, instance()->m_iconBuffer) { if (encodeUrl(ic.first) == encodedUrl) { return ic.second; } } QSqlQuery query(SqlDatabase::instance()->database()); query.prepare(QSL("SELECT icon FROM icons WHERE url GLOB ? LIMIT 1")); query.addBindValue(QString("%1*").arg(QzTools::escapeSqlGlobString(QString::fromUtf8(encodedUrl)))); query.exec(); + QImage *img = new QImage; if (query.next()) { - return QImage::fromData(query.value(0).toByteArray()); + img->loadFromData(query.value(0).toByteArray()); } + instance()->m_urlImageCache.insert(encodedUrl, img); - return allowNull ? QImage() : IconProvider::emptyWebImage(); + return img->isNull() && !allowNull ? IconProvider::emptyWebImage() : *img; } QIcon IconProvider::iconForDomain(const QUrl &url, bool allowNull) { return instance()->iconFromImage(imageForDomain(url, allowNull)); } QImage IconProvider::imageForDomain(const QUrl &url, bool allowNull) { if (url.host().isEmpty()) { return allowNull ? QImage() : IconProvider::emptyWebImage(); } foreach (const BufferedIcon &ic, instance()->m_iconBuffer) { if (ic.first.host() == url.host()) { return ic.second; } } QSqlQuery query(SqlDatabase::instance()->database()); query.prepare(QSL("SELECT icon FROM icons WHERE url GLOB ? LIMIT 1")); query.addBindValue(QString("*%1*").arg(QzTools::escapeSqlGlobString(url.host()))); query.exec(); if (query.next()) { return QImage::fromData(query.value(0).toByteArray()); } return allowNull ? QImage() : IconProvider::emptyWebImage(); } IconProvider* IconProvider::instance() { return qz_icon_provider(); } void IconProvider::saveIconsToDatabase() { foreach (const BufferedIcon &ic, m_iconBuffer) { QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); ic.second.save(&buffer, "PNG"); + + const QByteArray encodedUrl = encodeUrl(ic.first); + m_urlImageCache.remove(encodedUrl); + auto job = new SqlQueryJob(QSL("INSERT OR REPLACE INTO icons (icon, url) VALUES (?,?)"), this); job->addBindValue(buffer.data()); - job->addBindValue(QString::fromUtf8(encodeUrl(ic.first))); + job->addBindValue(QString::fromUtf8(encodedUrl)); job->start(); } m_iconBuffer.clear(); } void IconProvider::clearOldIconsInDatabase() { // Delete icons for entries older than 6 months const QDateTime date = QDateTime::currentDateTime().addMonths(-6); QSqlQuery query(SqlDatabase::instance()->database()); query.prepare(QSL("DELETE FROM icons WHERE url IN (SELECT url FROM history WHERE date < ?)")); query.addBindValue(date.toMSecsSinceEpoch()); query.exec(); query.clear(); query.exec(QSL("VACUUM")); } QIcon IconProvider::iconFromImage(const QImage &image) { return QIcon(QPixmap::fromImage(image)); } diff --git a/src/lib/tools/iconprovider.h b/src/lib/tools/iconprovider.h index 6731660e..f033f290 100644 --- a/src/lib/tools/iconprovider.h +++ b/src/lib/tools/iconprovider.h @@ -1,87 +1,89 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2014 David Rosca * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ============================================================ */ #ifndef ICONPROVIDER_H #define ICONPROVIDER_H #include #include #include #include +#include #include #include "qzcommon.h" class QIcon; class WebView; class AutoSaver; // Needs to be QWidget subclass, otherwise qproperty- setting won't work class FALKON_EXPORT IconProvider : public QWidget { Q_OBJECT Q_PROPERTY(QIcon bookmarkIcon READ bookmarkIcon WRITE setBookmarkIcon) public: explicit IconProvider(); void saveIcon(WebView* view); QIcon bookmarkIcon() const; void setBookmarkIcon(const QIcon &icon); // QStyle equivalent static QIcon standardIcon(QStyle::StandardPixmap icon); static QIcon newTabIcon(); static QIcon newWindowIcon(); static QIcon privateBrowsingIcon(); static QIcon settingsIcon(); // Icon for empty page static QIcon emptyWebIcon(); static QImage emptyWebImage(); // Icon for url (only available for urls in history) static QIcon iconForUrl(const QUrl &url, bool allowNull = false); static QImage imageForUrl(const QUrl &url, bool allowNull = false); // Icon for domain (only available for urls in history) static QIcon iconForDomain(const QUrl &url, bool allowNull = false); static QImage imageForDomain(const QUrl &url, bool allowNull = false); static IconProvider* instance(); public Q_SLOTS: void saveIconsToDatabase(); void clearOldIconsInDatabase(); private: typedef QPair BufferedIcon; QIcon iconFromImage(const QImage &image); QImage m_emptyWebImage; QIcon m_bookmarkIcon; QVector m_iconBuffer; + QCache m_urlImageCache; AutoSaver* m_autoSaver; }; #endif // ICONPROVIDER_H