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

0001 /*
0002     SPDX-FileCopyrightText: 2002 Joseph Wenninger <jowenn@kde.org>
0003     SPDX-FileCopyrightText: 2020 Méven Car <meven.car@kdemail.net>
0004     SPDX-FileCopyrightText: 2020 Tobias Fella <fella@posteo.de>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "componentchooser.h"
0010 
0011 #include <QApplication>
0012 #include <QDBusConnection>
0013 #include <QDBusMessage>
0014 
0015 #include <KApplicationTrader>
0016 #include <KConfigGroup>
0017 #include <KOpenWithDialog>
0018 #include <KQuickAddons/ConfigModule>
0019 #include <KService>
0020 #include <KSharedConfig>
0021 
0022 ComponentChooser::ComponentChooser(QObject *parent, const QString &mimeType, const QString &type, const QString &defaultApplication, const QString &dialogText)
0023     : QObject(parent)
0024     , m_mimeType(mimeType)
0025     , m_type(type)
0026     , m_defaultApplication(defaultApplication)
0027     , m_dialogText(dialogText)
0028 {
0029 }
0030 
0031 void ComponentChooser::defaults()
0032 {
0033     if (m_defaultIndex) {
0034         select(*m_defaultIndex);
0035     }
0036 }
0037 
0038 void ComponentChooser::load()
0039 {
0040     m_applications.clear();
0041 
0042     bool preferredServiceAdded = false;
0043 
0044     KService::Ptr preferredService = KApplicationTrader::preferredService(m_mimeType);
0045 
0046     KApplicationTrader::query([&preferredServiceAdded, preferredService, this](const KService::Ptr &service) {
0047         if (service->exec().isEmpty() || (!m_type.isEmpty() && !service->categories().contains(m_type)) || (!service->serviceTypes().contains(m_mimeType))) {
0048             return false;
0049         }
0050         QVariantMap application;
0051         application[QStringLiteral("name")] = service->name();
0052         application[QStringLiteral("icon")] = service->icon();
0053         application[QStringLiteral("storageId")] = service->storageId();
0054         m_applications += application;
0055         if ((preferredService && preferredService->storageId() == service->storageId())) {
0056             m_index = m_applications.length() - 1;
0057             preferredServiceAdded = true;
0058         }
0059         if (service->storageId() == m_defaultApplication) {
0060             m_defaultIndex = m_applications.length() - 1;
0061         }
0062         return false;
0063     });
0064     if (preferredService && !preferredServiceAdded) {
0065         // standard application was specified by the user
0066         QVariantMap application;
0067         application["name"] = preferredService->name();
0068         application["icon"] = preferredService->icon();
0069         application["storageId"] = preferredService->storageId();
0070         m_applications += application;
0071         m_index = m_applications.length() - 1;
0072     }
0073     QVariantMap application;
0074     application["name"] = i18n("Other…");
0075     application["icon"] = QStringLiteral("application-x-shellscript");
0076     application["storageId"] = QString();
0077     m_applications += application;
0078     if (m_index == -1) {
0079         m_index = 0;
0080     }
0081 
0082     m_previousApplication = m_applications[m_index].toMap()["storageId"].toString();
0083     Q_EMIT applicationsChanged();
0084     Q_EMIT indexChanged();
0085     Q_EMIT isDefaultsChanged();
0086 }
0087 
0088 void ComponentChooser::select(int index)
0089 {
0090     if (m_index == index && m_applications.size() != 1) {
0091         return;
0092     }
0093     if (index == m_applications.length() - 1) {
0094         KOpenWithDialog *dialog = new KOpenWithDialog(QList<QUrl>(), m_mimeType, m_dialogText, QString(), QApplication::activeWindow());
0095         dialog->setSaveNewApplications(true);
0096         dialog->setAttribute(Qt::WA_DeleteOnClose);
0097         connect(dialog, &KOpenWithDialog::finished, this, [this, dialog](int result) {
0098             if (result == QDialog::Rejected) {
0099                 Q_EMIT indexChanged();
0100                 Q_EMIT isDefaultsChanged();
0101                 return;
0102             }
0103 
0104             const KService::Ptr service = dialog->service();
0105             // Check if the selected application is already in the list
0106             for (int i = 0; i < m_applications.length(); i++) {
0107                 if (m_applications[i].toMap()["storageId"] == service->storageId()) {
0108                     m_index = i;
0109                     Q_EMIT indexChanged();
0110                     Q_EMIT isDefaultsChanged();
0111                     return;
0112                 }
0113             }
0114             const QString icon = !service->icon().isEmpty() ? service->icon() : QStringLiteral("application-x-shellscript");
0115             QVariantMap application;
0116             application["name"] = service->name();
0117             application["icon"] = icon;
0118             application["storageId"] = service->storageId();
0119             application["execLine"] = service->exec();
0120             m_applications.insert(m_applications.length() - 1, application);
0121             m_index = m_applications.length() - 2;
0122             Q_EMIT applicationsChanged();
0123             Q_EMIT indexChanged();
0124             Q_EMIT isDefaultsChanged();
0125         });
0126         dialog->open();
0127     } else {
0128         m_index = index;
0129     }
0130     Q_EMIT indexChanged();
0131     Q_EMIT isDefaultsChanged();
0132 }
0133 
0134 void ComponentChooser::saveMimeTypeAssociation(const QString &mime, const QString &storageId)
0135 {
0136     KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::GenericConfigLocation);
0137     if (profile->isConfigWritable(true)) {
0138         KConfigGroup defaultApp(profile, "Default Applications");
0139         defaultApp.writeXdgListEntry(mime, QStringList(storageId));
0140 
0141         KConfigGroup addedApps(profile, QStringLiteral("Added Associations"));
0142         QStringList apps = addedApps.readXdgListEntry(mime);
0143         apps.removeAll(storageId);
0144         apps.prepend(storageId); // make it the preferred app, i.e first in list
0145         addedApps.writeXdgListEntry(mime, apps);
0146         profile->sync();
0147 
0148         QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.klauncher5"),
0149                                                               QStringLiteral("/KLauncher"),
0150                                                               QStringLiteral("org.kde.KLauncher"),
0151                                                               QStringLiteral("reparseConfiguration"));
0152         QDBusConnection::sessionBus().send(message);
0153     }
0154     m_previousApplication = m_applications[m_index].toMap()["storageId"].toString();
0155 }
0156 
0157 bool ComponentChooser::isDefaults() const
0158 {
0159     return !m_defaultIndex.has_value() || *m_defaultIndex == m_index;
0160 }
0161 
0162 bool ComponentChooser::isSaveNeeded() const
0163 {
0164     return !m_applications.isEmpty() && (m_previousApplication != m_applications[m_index].toMap()["storageId"].toString());
0165 }