1 /* This file is part of the KDE project
2 SPDX-FileCopyrightText: 2000 Carsten Pfeiffer <pfeiffer@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "konqpixmapprovider.h"
8
9 #include <QMimeDatabase>
10 #include <QMimeType>
11 #include <QIcon>
12 #include "konqdebug.h"
13
14 #include <KIO/FavIconRequestJob>
15 #include <kio/global.h>
16 #include <kprotocolinfo.h>
17 #include <kconfiggroup.h>
18 #include <KIconLoader>
19
20 class KonqPixmapProviderSingleton
21 {
22 public:
23 KonqPixmapProvider self;
24 };
Q_GLOBAL_STATIC(KonqPixmapProviderSingleton,globalPixmapProvider)25 Q_GLOBAL_STATIC(KonqPixmapProviderSingleton, globalPixmapProvider)
26
27 KonqPixmapProvider *KonqPixmapProvider::self()
28 {
29 return &globalPixmapProvider->self;
30 }
31
KonqPixmapProvider()32 KonqPixmapProvider::KonqPixmapProvider()
33 : QObject()
34 {
35 }
36
~KonqPixmapProvider()37 KonqPixmapProvider::~KonqPixmapProvider()
38 {
39 }
40
downloadHostIcon(const QUrl & hostUrl)41 void KonqPixmapProvider::downloadHostIcon(const QUrl &hostUrl)
42 {
43 //Only attempt to download icon for http(s) URLs
44 if (!hostUrl.scheme().startsWith(QLatin1String("http"))) {
45 return;
46 }
47 KIO::FavIconRequestJob *job = new KIO::FavIconRequestJob(hostUrl);
48 connect(job, &KIO::FavIconRequestJob::result, this, [job, this](KJob *) {
49 bool modified = false;
50 const QUrl _hostUrl = job->hostUrl();
51 QMap<QUrl, QString>::iterator itEnd = iconMap.end();
52 for (QMap<QUrl, QString>::iterator it = iconMap.begin(); it != itEnd; ++it) {
53 const QUrl url(it.key());
54 if (url.host() == _hostUrl.host()) {
55 // For host default-icons still query the favicon manager to get
56 // the correct icon for pages that have an own one.
57 const QString icon = KIO::favIconForUrl(url);
58 if (!icon.isEmpty() && *it != icon) {
59 *it = icon;
60 modified = true;
61 }
62 }
63 }
64 if (modified) {
65 emit changed();
66 }
67 });
68 }
69
setIconForUrl(const QUrl & hostUrl,const QUrl & iconUrl)70 void KonqPixmapProvider::setIconForUrl(const QUrl &hostUrl, const QUrl &iconUrl)
71 {
72 KIO::FavIconRequestJob *job = new KIO::FavIconRequestJob(hostUrl);
73 job->setIconUrl(iconUrl);
74 connect(job, &KIO::FavIconRequestJob::result, this, [job, this](KJob *) {
75 bool modified = false;
76 const QUrl _hostUrl = job->hostUrl();
77 QMap<QUrl, QString>::iterator itEnd = iconMap.end();
78 for (QMap<QUrl, QString>::iterator it = iconMap.begin(); it != itEnd; ++it) {
79 const QUrl url(it.key());
80 if (url.host() == _hostUrl.host() && url.path() == _hostUrl.path()) {
81 const QString icon = job->iconFile();
82 if (!icon.isEmpty() && *it != icon) {
83 *it = icon;
84 modified = true;
85 }
86 }
87 }
88 if (modified) {
89 emit changed();
90 }
91 });
92 }
93
94 // at first, tries to find the iconname in the cache
95 // if not available, tries to find the pixmap for the mimetype of url
96 // if that fails, gets the icon for the protocol
97 // finally, inserts the url/icon pair into the cache
iconNameFor(const QUrl & url)98 QString KonqPixmapProvider::iconNameFor(const QUrl &url)
99 {
100 QMap<QUrl, QString>::iterator it = iconMap.find(url);
101 QString icon;
102 if (it != iconMap.end()) {
103 icon = it.value();
104 if (!icon.isEmpty()) {
105 return icon;
106 }
107 }
108
109 if (url.url().isEmpty()) {
110 // Use the folder icon for the empty URL
111 QMimeDatabase db;
112 const QMimeType directoryType = db.mimeTypeForName(QStringLiteral("inode/directory"));
113 icon = directoryType.iconName();
114 Q_ASSERT(!icon.isEmpty());
115 } else {
116 icon = KIO::iconNameForUrl(url);
117 Q_ASSERT(!icon.isEmpty());
118 }
119
120 // cache the icon found for url
121 iconMap.insert(url, icon);
122
123 return icon;
124 }
125
pixmapFor(const QString & url,int size)126 QPixmap KonqPixmapProvider::pixmapFor(const QString &url, int size)
127 {
128 return loadIcon(iconNameFor(QUrl::fromUserInput(url)), size);
129 }
130
load(KConfigGroup & kc,const QString & key)131 void KonqPixmapProvider::load(KConfigGroup &kc, const QString &key)
132 {
133 iconMap.clear();
134 const QStringList list = kc.readPathEntry(key, QStringList());
135 QStringList::const_iterator it = list.begin();
136 QStringList::const_iterator itEnd = list.end();
137 while (it != itEnd) {
138 const QString url(*it);
139 if ((++it) == itEnd) {
140 break;
141 }
142 const QString icon(*it);
143 iconMap.insert(QUrl::fromUserInput(url), icon);
144 ++it;
145 }
146 }
147
148 // only saves the cache for the given list of items to prevent the cache
149 // from growing forever.
save(KConfigGroup & kc,const QString & key,const QStringList & items)150 void KonqPixmapProvider::save(KConfigGroup &kc, const QString &key,
151 const QStringList &items)
152 {
153 QStringList list;
154 QStringList::const_iterator itEnd = items.end();
155 for (QStringList::const_iterator it = items.begin(); it != itEnd; ++it) {
156 QMap<QUrl, QString>::const_iterator mit = iconMap.constFind(QUrl::fromUserInput(*it));
157 if (mit != iconMap.constEnd()) {
158 list.append(mit.key().url());
159 list.append(mit.value());
160 }
161 }
162 kc.writePathEntry(key, list);
163 }
164
clear()165 void KonqPixmapProvider::clear()
166 {
167 iconMap.clear();
168 }
169
loadIcon(const QString & icon,int size)170 QPixmap KonqPixmapProvider::loadIcon(const QString &icon, int size)
171 {
172 if (size == 0) {
173 size = KIconLoader::SizeSmall;
174 }
175 return QIcon::fromTheme(icon).pixmap(size);
176 }
177
iconForUrl(const QUrl & url)178 QIcon KonqPixmapProvider::iconForUrl(const QUrl &url)
179 {
180 return QIcon::fromTheme(iconNameFor(url));
181 }
182
iconForUrl(const QString & url_str)183 QIcon KonqPixmapProvider::iconForUrl(const QString &url_str)
184 {
185 return iconForUrl(QUrl::fromUserInput(url_str));
186 }
187
188