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 | |
18 | bool KFileMetaPreview::s_tryAudioPreview = true; |
19 | |
20 | KFileMetaPreview::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 | |
34 | KFileMetaPreview::~KFileMetaPreview() |
35 | { |
36 | } |
37 | |
38 | void 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 | |
58 | KPreviewWidgetBase *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 | |
88 | KPreviewWidgetBase *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 | |
137 | void 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 | |
156 | void KFileMetaPreview::clearPreview() |
157 | { |
158 | if (m_stack->currentWidget()) { |
159 | static_cast<KPreviewWidgetBase *>(m_stack->currentWidget())->clearPreview(); |
160 | } |
161 | } |
162 | |
163 | void KFileMetaPreview::addPreviewProvider(const QString &mimeType, KPreviewWidgetBase *provider) |
164 | { |
165 | m_previewProviders.insert(key: mimeType, value: provider); |
166 | } |
167 | |
168 | void 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 |
178 | KPreviewWidgetBase *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 | |