1/*
2 This file is part of the KDE project.
3 SPDX-FileCopyrightText: 2003 Carsten Pfeiffer <pfeiffer@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6*/
7
8#include "kfilemetapreview_p.h"
9
10#include <QLayout>
11#include <QMimeDatabase>
12
13#include <KPluginFactory>
14#include <QDebug>
15#include <kimagefilepreview.h>
16#include <kio/previewjob.h>
17
18bool KFileMetaPreview::s_tryAudioPreview = true;
19
20KFileMetaPreview::KFileMetaPreview(QWidget *parent)
21 : KPreviewWidgetBase(parent)
22 , haveAudioPreview(false)
23{
24 QHBoxLayout *layout = new QHBoxLayout(this);
25 layout->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
26 m_stack = new QStackedWidget(this);
27 layout->addWidget(m_stack);
28
29 // ###
30 // m_previewProviders.setAutoDelete( true );
31 initPreviewProviders();
32}
33
34KFileMetaPreview::~KFileMetaPreview()
35{
36}
37
38void KFileMetaPreview::initPreviewProviders()
39{
40 qDeleteAll(c: m_previewProviders);
41 m_previewProviders.clear();
42 // hardcoded so far
43
44 // image previews
45 KImageFilePreview *imagePreview = new KImageFilePreview(m_stack);
46 (void)m_stack->addWidget(w: imagePreview);
47 m_stack->setCurrentWidget(imagePreview);
48 resize(imagePreview->sizeHint());
49
50 const QStringList mimeTypes = imagePreview->supportedMimeTypes();
51 QStringList::ConstIterator it = mimeTypes.begin();
52 for (; it != mimeTypes.end(); ++it) {
53 // qDebug(".... %s", (*it).toLatin1().constData());
54 m_previewProviders.insert(key: *it, value: imagePreview);
55 }
56}
57
58KPreviewWidgetBase *KFileMetaPreview::findExistingProvider(const QString &mimeType, const QMimeType &mimeInfo) const
59{
60 KPreviewWidgetBase *provider = m_previewProviders.value(key: mimeType);
61 if (provider) {
62 return provider;
63 }
64
65 if (mimeInfo.isValid()) {
66 // check MIME type inheritance
67 const QStringList parentMimeTypes = mimeInfo.allAncestors();
68 for (const QString &parentMimeType : parentMimeTypes) {
69 provider = m_previewProviders.value(key: parentMimeType);
70 if (provider) {
71 return provider;
72 }
73 }
74 }
75
76 // ### MIME type may be image/* for example, try that
77 const int index = mimeType.indexOf(c: QLatin1Char('/'));
78 if (index > 0) {
79 provider = m_previewProviders.value(key: QStringView(mimeType).left(n: index + 1) + QLatin1Char('*'));
80 if (provider) {
81 return provider;
82 }
83 }
84
85 return nullptr;
86}
87
88KPreviewWidgetBase *KFileMetaPreview::previewProviderFor(const QString &mimeType)
89{
90 QMimeDatabase db;
91 QMimeType mimeInfo = db.mimeTypeForName(nameOrAlias: mimeType);
92
93 // qDebug("### looking for: %s", mimeType.toLatin1().constData());
94 // often the first highlighted item, where we can be sure, there is no plugin
95 // (this "folders reflect icons" is a konq-specific thing, right?)
96 if (mimeInfo.inherits(QStringLiteral("inode/directory"))) {
97 return nullptr;
98 }
99
100 KPreviewWidgetBase *provider = findExistingProvider(mimeType, mimeInfo);
101 if (provider) {
102 return provider;
103 }
104
105 // qDebug("#### didn't find anything for: %s", mimeType.toLatin1().constData());
106
107 if (s_tryAudioPreview && !mimeType.startsWith(s: QLatin1String("text/")) && !mimeType.startsWith(s: QLatin1String("image/"))) {
108 if (!haveAudioPreview) {
109 KPreviewWidgetBase *audioPreview = createAudioPreview(parent: m_stack);
110 if (audioPreview) {
111 haveAudioPreview = true;
112 (void)m_stack->addWidget(w: audioPreview);
113 const QStringList mimeTypes = audioPreview->supportedMimeTypes();
114 QStringList::ConstIterator it = mimeTypes.begin();
115 for (; it != mimeTypes.end(); ++it) {
116 // only add non already handled MIME types
117 if (m_previewProviders.constFind(key: *it) == m_previewProviders.constEnd()) {
118 m_previewProviders.insert(key: *it, value: audioPreview);
119 }
120 }
121 }
122 }
123 }
124
125 // with the new MIME types from the audio-preview, try again
126 provider = findExistingProvider(mimeType, mimeInfo);
127 if (provider) {
128 return provider;
129 }
130
131 // The logic in this code duplicates the logic in PreviewJob.
132 // But why do we need multiple KPreviewWidgetBase instances anyway?
133
134 return nullptr;
135}
136
137void KFileMetaPreview::showPreview(const QUrl &url)
138{
139 QMimeDatabase db;
140 QMimeType mt = db.mimeTypeForUrl(url);
141 KPreviewWidgetBase *provider = previewProviderFor(mimeType: mt.name());
142 if (provider) {
143 if (provider != m_stack->currentWidget()) { // stop the previous preview
144 clearPreview();
145 }
146
147 m_stack->setEnabled(true);
148 m_stack->setCurrentWidget(provider);
149 provider->showPreview(url);
150 } else {
151 clearPreview();
152 m_stack->setEnabled(false);
153 }
154}
155
156void KFileMetaPreview::clearPreview()
157{
158 if (m_stack->currentWidget()) {
159 static_cast<KPreviewWidgetBase *>(m_stack->currentWidget())->clearPreview();
160 }
161}
162
163void KFileMetaPreview::addPreviewProvider(const QString &mimeType, KPreviewWidgetBase *provider)
164{
165 m_previewProviders.insert(key: mimeType, value: provider);
166}
167
168void KFileMetaPreview::clearPreviewProviders()
169{
170 for (auto it = m_previewProviders.cbegin(); it != m_previewProviders.cend(); ++it) {
171 m_stack->removeWidget(w: it.value());
172 }
173 qDeleteAll(c: m_previewProviders);
174 m_previewProviders.clear();
175}
176
177// static
178KPreviewWidgetBase *KFileMetaPreview::createAudioPreview(QWidget *parent)
179{
180 KPluginMetaData data(QStringLiteral("kfileaudiopreview"));
181 if (auto plugin = KPluginFactory::instantiatePlugin<KPreviewWidgetBase>(data, parent).plugin) {
182 plugin->setObjectName(QStringLiteral("kfileaudiopreview"));
183 return plugin;
184 } else {
185 s_tryAudioPreview = false;
186 return nullptr;
187 }
188}
189
190#include "moc_kfilemetapreview_p.cpp"
191

source code of kio/src/filewidgets/kfilemetapreview.cpp