28#include <QFutureWatcher>
29#include <QtConcurrent/QtConcurrentRun>
33static QByteArray encodeUrl(
const QUrl &url)
35 return url.toEncoded(QUrl::RemoveFragment | QUrl::StripTrailingSlash);
48 if (
mApp->isPrivate()) {
52 const QIcon icon = view->
icon(
true);
57 const QStringList ignoredSchemes = {
58 QStringLiteral(
"falkon"),
59 QStringLiteral(
"ftp"),
60 QStringLiteral(
"file"),
61 QStringLiteral(
"view-source"),
62 QStringLiteral(
"data"),
63 QStringLiteral(
"about")
66 if (ignoredSchemes.contains(view->url().scheme())) {
70 for (
int i = 0;
i < m_iconBuffer.size(); ++
i) {
71 if (m_iconBuffer[
i].first == view->url()) {
72 m_iconBuffer.removeAt(
i);
78 item.first = view->url();
79 item.second = icon.pixmap(16).toImage();
82 m_iconBuffer.append(item);
87 return QIcon::fromTheme(
QSL(
"bookmarks"), m_bookmarkIcon);
92 m_bookmarkIcon = icon;
98 case QStyle::SP_MessageBoxCritical:
99 return QIcon::fromTheme(
QSL(
"dialog-error"), QApplication::style()->
standardIcon(icon));
101 case QStyle::SP_MessageBoxInformation:
102 return QIcon::fromTheme(
QSL(
"dialog-information"), QApplication::style()->
standardIcon(icon));
104 case QStyle::SP_MessageBoxQuestion:
105 return QIcon::fromTheme(
QSL(
"dialog-question"), QApplication::style()->
standardIcon(icon));
107 case QStyle::SP_MessageBoxWarning:
108 return QIcon::fromTheme(
QSL(
"dialog-warning"), QApplication::style()->
standardIcon(icon));
110 case QStyle::SP_DialogCloseButton:
111 return QIcon::fromTheme(
QSL(
"dialog-close"), QApplication::style()->
standardIcon(icon));
113 case QStyle::SP_BrowserStop:
114 return QIcon::fromTheme(
QSL(
"process-stop"), QApplication::style()->
standardIcon(icon));
116 case QStyle::SP_BrowserReload:
117 return QIcon::fromTheme(
QSL(
"view-refresh"), QApplication::style()->
standardIcon(icon));
119 case QStyle::SP_FileDialogToParent:
120 return QIcon::fromTheme(
QSL(
"go-up"), QApplication::style()->
standardIcon(icon));
122 case QStyle::SP_ArrowUp:
123 return QIcon::fromTheme(
QSL(
"go-up"), QApplication::style()->
standardIcon(icon));
125 case QStyle::SP_ArrowDown:
126 return QIcon::fromTheme(
QSL(
"go-down"), QApplication::style()->
standardIcon(icon));
128 case QStyle::SP_ArrowForward:
129 if (QApplication::layoutDirection() == Qt::RightToLeft) {
130 return QIcon::fromTheme(
QSL(
"go-previous"), QApplication::style()->
standardIcon(icon));
132 return QIcon::fromTheme(
QSL(
"go-next"), QApplication::style()->
standardIcon(icon));
134 case QStyle::SP_ArrowBack:
135 if (QApplication::layoutDirection() == Qt::RightToLeft) {
136 return QIcon::fromTheme(
QSL(
"go-next"), QApplication::style()->
standardIcon(icon));
138 return QIcon::fromTheme(
QSL(
"go-previous"), QApplication::style()->
standardIcon(icon));
141 return QApplication::style()->standardIcon(icon);
147 return QIcon::fromTheme(
QSL(
"tab-new"), QIcon(
QSL(
":/icons/menu/tab-new.svg")));
152 return QIcon::fromTheme(
QSL(
"window-new"), QIcon(
QSL(
":/icons/menu/window-new.svg")));
157 return QIcon::fromTheme(
QSL(
"view-private-symbolic"), QIcon(
QSL(
":/icons/menu/privatebrowsing.png")));
162 return QIcon::fromTheme(
QSL(
"configure"), QIcon(
QSL(
":/icons/menu/settings.svg")));
172 if (
instance()->m_emptyWebImage.isNull()) {
173 instance()->m_emptyWebImage = QIcon(
QSL(
":icons/other/webpage.svg")).pixmap(16).toImage();
186 if (url.path().isEmpty()) {
190 QMutexLocker locker(&
instance()->m_iconCacheMutex);
192 const QByteArray encodedUrl = encodeUrl(url);
194 if (QImage *img =
instance()->m_urlImageCache.object(encodedUrl)) {
198 const auto iconBuffer =
instance()->m_iconBuffer;
199 for (
const BufferedIcon &ic : iconBuffer) {
200 if (encodeUrl(ic.first) == encodedUrl) {
206 query.prepare(
QSL(
"SELECT icon FROM icons WHERE url GLOB ? LIMIT 1"));
210 auto *img =
new QImage;
212 img->loadFromData(query.value(0).toByteArray());
214 instance()->m_urlImageCache.insert(encodedUrl, img);
226 if (url.host().isEmpty()) {
230 QMutexLocker locker(&
instance()->m_iconCacheMutex);
232 const auto iconBuffer =
instance()->m_iconBuffer;
233 for (
const BufferedIcon &ic : iconBuffer) {
234 if (ic.first.host() == url.host()) {
240 query.prepare(
QSL(
"SELECT icon FROM icons WHERE url GLOB ? LIMIT 1"));
245 return QImage::fromData(query.value(0).toByteArray());
253 return qz_icon_provider();
258 QMutexLocker locker(&
instance()->m_iconCacheMutex);
260 for (
const BufferedIcon &ic : std::as_const(m_iconBuffer)) {
263 buffer.open(QIODevice::WriteOnly);
264 ic.second.save(&buffer,
"PNG");
266 const QByteArray encodedUrl = encodeUrl(ic.first);
267 m_urlImageCache.remove(encodedUrl);
269 auto job =
new SqlQueryJob(
QSL(
"INSERT OR REPLACE INTO icons (icon, url) VALUES (?,?)"),
this);
270 job->addBindValue(buffer.data());
271 job->addBindValue(QString::fromUtf8(encodedUrl));
275 m_iconBuffer.clear();
281 const QDateTime date = QDateTime::currentDateTime().addMonths(-6);
284 query.prepare(
QSL(
"DELETE FROM icons WHERE url IN (SELECT url FROM history WHERE date < ?)"));
285 query.addBindValue(date.toMSecsSinceEpoch());
289 query.exec(
QSL(
"VACUUM"));
292QIcon IconProvider::iconFromImage(
const QImage &image)
294 return QIcon(QPixmap::fromImage(image));
static QImage imageForUrl(const QUrl &url, bool allowNull=false)
void saveIcon(WebView *view)
static QIcon settingsIcon()
static QIcon iconForUrl(const QUrl &url, bool allowNull=false)
static QIcon privateBrowsingIcon()
void setBookmarkIcon(const QIcon &icon)
static IconProvider * instance()
static QIcon iconForDomain(const QUrl &url, bool allowNull=false)
static QImage imageForDomain(const QUrl &url, bool allowNull=false)
static QIcon emptyWebIcon()
static QIcon newWindowIcon()
void clearOldIconsInDatabase()
static QIcon newTabIcon()
void saveIconsToDatabase()
static QIcon standardIcon(QStyle::StandardPixmap icon)
static QImage emptyWebImage()
static SqlDatabase * instance()
QIcon icon(bool allowNull=false) const