File indexing completed on 2024-04-21 03:55:19

0001 /*
0002     This file is part of the KDE project.
0003     SPDX-FileCopyrightText: 2003 Carsten Pfeiffer <pfeiffer@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "kfilemetapreview_p.h"
0009 
0010 #include <QLayout>
0011 #include <QMimeDatabase>
0012 
0013 #include <KPluginFactory>
0014 #include <QDebug>
0015 #include <kimagefilepreview.h>
0016 #include <kio/previewjob.h>
0017 
0018 bool KFileMetaPreview::s_tryAudioPreview = true;
0019 
0020 KFileMetaPreview::KFileMetaPreview(QWidget *parent)
0021     : KPreviewWidgetBase(parent)
0022     , haveAudioPreview(false)
0023 {
0024     QHBoxLayout *layout = new QHBoxLayout(this);
0025     layout->setContentsMargins(0, 0, 0, 0);
0026     m_stack = new QStackedWidget(this);
0027     layout->addWidget(m_stack);
0028 
0029     // ###
0030     //     m_previewProviders.setAutoDelete( true );
0031     initPreviewProviders();
0032 }
0033 
0034 KFileMetaPreview::~KFileMetaPreview()
0035 {
0036 }
0037 
0038 void KFileMetaPreview::initPreviewProviders()
0039 {
0040     qDeleteAll(m_previewProviders);
0041     m_previewProviders.clear();
0042     // hardcoded so far
0043 
0044     // image previews
0045     KImageFilePreview *imagePreview = new KImageFilePreview(m_stack);
0046     (void)m_stack->addWidget(imagePreview);
0047     m_stack->setCurrentWidget(imagePreview);
0048     resize(imagePreview->sizeHint());
0049 
0050     const QStringList mimeTypes = imagePreview->supportedMimeTypes();
0051     QStringList::ConstIterator it = mimeTypes.begin();
0052     for (; it != mimeTypes.end(); ++it) {
0053         //         qDebug(".... %s", (*it).toLatin1().constData());
0054         m_previewProviders.insert(*it, imagePreview);
0055     }
0056 }
0057 
0058 KPreviewWidgetBase *KFileMetaPreview::findExistingProvider(const QString &mimeType, const QMimeType &mimeInfo) const
0059 {
0060     KPreviewWidgetBase *provider = m_previewProviders.value(mimeType);
0061     if (provider) {
0062         return provider;
0063     }
0064 
0065     if (mimeInfo.isValid()) {
0066         // check MIME type inheritance
0067         const QStringList parentMimeTypes = mimeInfo.allAncestors();
0068         for (const QString &parentMimeType : parentMimeTypes) {
0069             provider = m_previewProviders.value(parentMimeType);
0070             if (provider) {
0071                 return provider;
0072             }
0073         }
0074     }
0075 
0076     // ### MIME type may be image/* for example, try that
0077     const int index = mimeType.indexOf(QLatin1Char('/'));
0078     if (index > 0) {
0079         provider = m_previewProviders.value(QStringView(mimeType).left(index + 1) + QLatin1Char('*'));
0080         if (provider) {
0081             return provider;
0082         }
0083     }
0084 
0085     return nullptr;
0086 }
0087 
0088 KPreviewWidgetBase *KFileMetaPreview::previewProviderFor(const QString &mimeType)
0089 {
0090     QMimeDatabase db;
0091     QMimeType mimeInfo = db.mimeTypeForName(mimeType);
0092 
0093     //     qDebug("### looking for: %s", mimeType.toLatin1().constData());
0094     // often the first highlighted item, where we can be sure, there is no plugin
0095     // (this "folders reflect icons" is a konq-specific thing, right?)
0096     if (mimeInfo.inherits(QStringLiteral("inode/directory"))) {
0097         return nullptr;
0098     }
0099 
0100     KPreviewWidgetBase *provider = findExistingProvider(mimeType, mimeInfo);
0101     if (provider) {
0102         return provider;
0103     }
0104 
0105     // qDebug("#### didn't find anything for: %s", mimeType.toLatin1().constData());
0106 
0107     if (s_tryAudioPreview && !mimeType.startsWith(QLatin1String("text/")) && !mimeType.startsWith(QLatin1String("image/"))) {
0108         if (!haveAudioPreview) {
0109             KPreviewWidgetBase *audioPreview = createAudioPreview(m_stack);
0110             if (audioPreview) {
0111                 haveAudioPreview = true;
0112                 (void)m_stack->addWidget(audioPreview);
0113                 const QStringList mimeTypes = audioPreview->supportedMimeTypes();
0114                 QStringList::ConstIterator it = mimeTypes.begin();
0115                 for (; it != mimeTypes.end(); ++it) {
0116                     // only add non already handled MIME types
0117                     if (m_previewProviders.constFind(*it) == m_previewProviders.constEnd()) {
0118                         m_previewProviders.insert(*it, audioPreview);
0119                     }
0120                 }
0121             }
0122         }
0123     }
0124 
0125     // with the new MIME types from the audio-preview, try again
0126     provider = findExistingProvider(mimeType, mimeInfo);
0127     if (provider) {
0128         return provider;
0129     }
0130 
0131     // The logic in this code duplicates the logic in PreviewJob.
0132     // But why do we need multiple KPreviewWidgetBase instances anyway?
0133 
0134     return nullptr;
0135 }
0136 
0137 void KFileMetaPreview::showPreview(const QUrl &url)
0138 {
0139     QMimeDatabase db;
0140     QMimeType mt = db.mimeTypeForUrl(url);
0141     KPreviewWidgetBase *provider = previewProviderFor(mt.name());
0142     if (provider) {
0143         if (provider != m_stack->currentWidget()) { // stop the previous preview
0144             clearPreview();
0145         }
0146 
0147         m_stack->setEnabled(true);
0148         m_stack->setCurrentWidget(provider);
0149         provider->showPreview(url);
0150     } else {
0151         clearPreview();
0152         m_stack->setEnabled(false);
0153     }
0154 }
0155 
0156 void KFileMetaPreview::clearPreview()
0157 {
0158     if (m_stack->currentWidget()) {
0159         static_cast<KPreviewWidgetBase *>(m_stack->currentWidget())->clearPreview();
0160     }
0161 }
0162 
0163 void KFileMetaPreview::addPreviewProvider(const QString &mimeType, KPreviewWidgetBase *provider)
0164 {
0165     m_previewProviders.insert(mimeType, provider);
0166 }
0167 
0168 void KFileMetaPreview::clearPreviewProviders()
0169 {
0170     for (auto it = m_previewProviders.cbegin(); it != m_previewProviders.cend(); ++it) {
0171         m_stack->removeWidget(it.value());
0172     }
0173     qDeleteAll(m_previewProviders);
0174     m_previewProviders.clear();
0175 }
0176 
0177 // static
0178 KPreviewWidgetBase *KFileMetaPreview::createAudioPreview(QWidget *parent)
0179 {
0180     KPluginMetaData data(QStringLiteral("kfileaudiopreview"));
0181     if (auto plugin = KPluginFactory::instantiatePlugin<KPreviewWidgetBase>(data, parent).plugin) {
0182         plugin->setObjectName(QStringLiteral("kfileaudiopreview"));
0183         return plugin;
0184     } else {
0185         s_tryAudioPreview = false;
0186         return nullptr;
0187     }
0188 }
0189 
0190 #include "moc_kfilemetapreview_p.cpp"