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