File indexing completed on 2024-05-12 17:08:47

0001 /*
0002     SPDX-FileCopyrightText: 2021 Kai Uwe Broulik <kde@broulik.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #include "fileinfo.h"
0008 #include "notifications_debug.h"
0009 
0010 #include <QAction>
0011 #include <QMimeDatabase>
0012 
0013 #include <KApplicationTrader>
0014 #include <KAuthorized>
0015 #include <KIO/ApplicationLauncherJob>
0016 #include <KIO/JobUiDelegateFactory>
0017 #include <KIO/MimeTypeFinderJob>
0018 #include <KIO/OpenUrlJob>
0019 #include <KLocalizedString>
0020 #include <KNotificationJobUiDelegate>
0021 
0022 FileInfo::FileInfo(QObject *parent)
0023     : QObject(parent)
0024 {
0025 }
0026 
0027 FileInfo::~FileInfo() = default;
0028 
0029 QUrl FileInfo::url() const
0030 {
0031     return m_url;
0032 }
0033 
0034 void FileInfo::setUrl(const QUrl &url)
0035 {
0036     if (m_url != url) {
0037         m_url = url;
0038         reload();
0039         Q_EMIT urlChanged(url);
0040     }
0041 }
0042 
0043 bool FileInfo::busy() const
0044 {
0045     return m_busy;
0046 }
0047 
0048 void FileInfo::setBusy(bool busy)
0049 {
0050     if (m_busy != busy) {
0051         m_busy = busy;
0052         Q_EMIT busyChanged(busy);
0053     }
0054 }
0055 
0056 int FileInfo::error() const
0057 {
0058     return m_error;
0059 }
0060 
0061 void FileInfo::setError(int error)
0062 {
0063     if (m_error != error) {
0064         m_error = error;
0065         Q_EMIT errorChanged(error);
0066     }
0067 }
0068 
0069 QString FileInfo::mimeType() const
0070 {
0071     return m_mimeType;
0072 }
0073 
0074 QString FileInfo::iconName() const
0075 {
0076     return m_iconName;
0077 }
0078 
0079 QAction *FileInfo::openAction() const
0080 {
0081     return m_openAction;
0082 }
0083 
0084 QString FileInfo::openActionIconName() const
0085 {
0086     return m_openAction ? m_openAction->icon().name() : QString();
0087 }
0088 
0089 void FileInfo::reload()
0090 {
0091     if (!m_url.isValid()) {
0092         return;
0093     }
0094 
0095     if (m_job) {
0096         m_job->kill();
0097     }
0098 
0099     setError(0);
0100 
0101     // Do a quick guess by file name while we wait for the job to find the mime type
0102     QString guessedMimeType;
0103 
0104     // NOTE using QUrl::path() for API that accepts local files is usually wrong
0105     // but here we really only care about the file name and its extension.
0106     const auto type = QMimeDatabase().mimeTypeForFile(m_url.path(), QMimeDatabase::MatchExtension);
0107     if (!type.isDefault()) {
0108         guessedMimeType = type.name();
0109     }
0110 
0111     mimeTypeFound(guessedMimeType);
0112 
0113     m_job = new KIO::MimeTypeFinderJob(m_url);
0114     m_job->setAuthenticationPromptEnabled(false);
0115 
0116     const QUrl url = m_url;
0117     connect(m_job, &KIO::MimeTypeFinderJob::result, this, [this, url] {
0118         setError(m_job->error());
0119         if (m_job->error()) {
0120             qCWarning(PLASMA_APPLET_NOTIFICATIONS_DEBUG) << "Failed to determine mime type for" << url << m_job->errorString();
0121         } else {
0122             mimeTypeFound(m_job->mimeType());
0123         }
0124         setBusy(false);
0125     });
0126 
0127     setBusy(true);
0128     m_job->start();
0129 }
0130 
0131 void FileInfo::mimeTypeFound(const QString &mimeType)
0132 {
0133     if (m_mimeType == mimeType) {
0134         return;
0135     }
0136 
0137     const QString oldOpenActionIconName = openActionIconName();
0138 
0139     bool emitOpenActionChanged = false;
0140     if (!m_openAction) {
0141         m_openAction = new QAction(this);
0142         connect(m_openAction, &QAction::triggered, this, [this] {
0143             auto *job = new KIO::ApplicationLauncherJob(m_preferredApplication);
0144             if (m_preferredApplication) {
0145                 job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoErrorHandlingEnabled));
0146             } else {
0147                 // needs KIO::JobUiDelegate for open with handler
0148                 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoErrorHandlingEnabled, nullptr /*widget*/));
0149             }
0150             job->setUrls({m_url});
0151             job->start();
0152         });
0153         emitOpenActionChanged = true;
0154     }
0155 
0156     m_mimeType = mimeType;
0157 
0158     m_preferredApplication.reset();
0159 
0160     if (!mimeType.isEmpty()) {
0161         const auto type = QMimeDatabase().mimeTypeForName(mimeType);
0162         m_iconName = type.iconName();
0163 
0164         m_preferredApplication = KApplicationTrader::preferredService(mimeType);
0165     } else {
0166         m_iconName.clear();
0167     }
0168 
0169     if (m_preferredApplication) {
0170         m_openAction->setText(i18n("Open with %1", m_preferredApplication->name()));
0171         m_openAction->setIcon(QIcon::fromTheme(m_preferredApplication->icon()));
0172         m_openAction->setEnabled(true);
0173     } else {
0174         m_openAction->setText(i18n("Open with…"));
0175         m_openAction->setIcon(QIcon::fromTheme(QStringLiteral("system-run")));
0176         m_openAction->setEnabled(KAuthorized::authorizeAction(KAuthorized::OPEN_WITH));
0177     }
0178 
0179     Q_EMIT mimeTypeChanged();
0180 
0181     if (emitOpenActionChanged) {
0182         Q_EMIT openActionChanged();
0183     }
0184     if (oldOpenActionIconName != openActionIconName()) {
0185         Q_EMIT openActionIconNameChanged();
0186     }
0187 }
0188 
0189 #include "moc_fileinfo.cpp"