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 }