Changeset View
Changeset View
Standalone View
Standalone View
kcms/componentchooser/componentchooseremail.cpp
1 | /*************************************************************************** | 1 | /*************************************************************************** | ||
---|---|---|---|---|---|
2 | componentchooseremail.cpp | 2 | componentchooseremail.cpp | ||
3 | ------------------- | 3 | ------------------- | ||
4 | copyright : (C) 2002 by Joseph Wenninger | 4 | copyright : (C) 2002 by Joseph Wenninger <jowenn@kde.org> | ||
5 | email : jowenn@kde.org | 5 | copyright : (C) 2020 by Méven Car <meven.car@enioka.com> | ||
6 | ***************************************************************************/ | 6 | ***************************************************************************/ | ||
7 | 7 | | |||
8 | /*************************************************************************** | 8 | /*************************************************************************** | ||
9 | * * | 9 | * * | ||
10 | * This program is free software; you can redistribute it and/or modify * | 10 | * This program is free software; you can redistribute it and/or modify * | ||
11 | * it under the terms of the GNU General Public License version 2 as * | 11 | * it under the terms of the GNU General Public License version 2 as * | ||
12 | * published by the Free Software Foundation * | 12 | * published by the Free Software Foundation * | ||
13 | * * | 13 | * * | ||
14 | ***************************************************************************/ | 14 | ***************************************************************************/ | ||
15 | 15 | | |||
16 | #include "componentchooseremail.h" | 16 | #include "componentchooseremail.h" | ||
17 | 17 | | |||
18 | #include <kemailsettings.h> | 18 | #include <kemailsettings.h> | ||
19 | #include <kopenwithdialog.h> | 19 | #include <kopenwithdialog.h> | ||
20 | 20 | | |||
21 | #include <KLocalizedString> | 21 | #include <KLocalizedString> | ||
22 | #include <KConfigGroup> | 22 | #include <KConfigGroup> | ||
23 | #include <KSharedConfig> | 23 | #include <KSharedConfig> | ||
24 | #include <KService> | 24 | #include <KService> | ||
25 | #include <KServiceTypeTrader> | ||||
26 | #include <KBuildSycocaProgressDialog> | ||||
27 | #include <KMimeTypeTrader> | ||||
28 | #include <KShell> | ||||
29 | | ||||
25 | #include <QDBusConnection> | 30 | #include <QDBusConnection> | ||
26 | #include <QDBusMessage> | 31 | #include <QDBusMessage> | ||
27 | #include <QUrl> | 32 | #include <QUrl> | ||
28 | #include <QFile> | 33 | #include <QFile> | ||
29 | #include <QCheckBox> | 34 | #include <QCheckBox> | ||
30 | 35 | | |||
31 | // for chmod: | 36 | namespace { | ||
32 | #include <sys/types.h> | 37 | static const char s_AddedAssociations[] = "Added Associations"; | ||
33 | #include <sys/stat.h> | 38 | static const auto s_mimetype = QStringLiteral("x-scheme-handler/mailto"); | ||
34 | #include <QStandardPaths> | 39 | } | ||
35 | | ||||
36 | 40 | | |||
37 | CfgEmailClient::CfgEmailClient(QWidget *parent) | 41 | CfgEmailClient::CfgEmailClient(QWidget *parent) | ||
38 | : QWidget(parent), Ui::EmailClientConfig_UI(), CfgPlugin() | 42 | : QWidget(parent), Ui::EmailClientConfig_UI(), CfgPlugin() | ||
39 | { | 43 | { | ||
40 | setupUi( this ); | 44 | setupUi( this ); | ||
41 | 45 | | |||
42 | pSettings = new KEMailSettings(); | 46 | pSettings = new KEMailSettings(); | ||
43 | 47 | | |||
44 | connect(kmailCB, &QRadioButton::toggled, this, &CfgEmailClient::configChanged); | 48 | connect(emailClientsCombo, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated), this, &CfgEmailClient::selectEmailClient); | ||
45 | connect(txtEMailClient, &KLineEdit::textChanged, this, &CfgEmailClient::configChanged); | | |||
46 | #ifdef Q_OS_UNIX | | |||
47 | connect(chkRunTerminal, &QCheckBox::clicked, this, &CfgEmailClient::configChanged); | | |||
48 | #else | | |||
49 | chkRunTerminal->hide(); | | |||
50 | #endif | | |||
51 | connect(btnSelectEmail, &QToolButton::clicked, this, &CfgEmailClient::selectEmailClient); | | |||
52 | } | 49 | } | ||
53 | 50 | | |||
54 | CfgEmailClient::~CfgEmailClient() { | 51 | CfgEmailClient::~CfgEmailClient() { | ||
55 | delete pSettings; | 52 | delete pSettings; | ||
56 | } | 53 | } | ||
57 | 54 | | |||
58 | void CfgEmailClient::defaults() | 55 | void CfgEmailClient::defaults() | ||
59 | { | 56 | { | ||
60 | kmailCB->setChecked(true); | 57 | // select kmail if installed | ||
61 | txtEMailClient->clear(); | 58 | if (m_kmailIndex != -1) { | ||
62 | chkRunTerminal->setChecked(false); | 59 | emailClientsCombo->setCurrentIndex(m_kmailIndex); | ||
60 | } | ||||
63 | } | 61 | } | ||
64 | 62 | | |||
65 | bool CfgEmailClient::isDefaults() const | 63 | bool CfgEmailClient::isDefaults() const | ||
66 | { | 64 | { | ||
67 | return kmailCB->isChecked(); | 65 | // if kmail is installed and is selected | ||
66 | if (m_kmailIndex != -1) { | ||||
67 | return emailClientsCombo->currentIndex() == m_kmailIndex; | ||||
68 | } | ||||
69 | | ||||
70 | return true; | ||||
68 | } | 71 | } | ||
69 | 72 | | |||
70 | void CfgEmailClient::load(KConfig *) | 73 | void CfgEmailClient::load(KConfig *) | ||
71 | { | 74 | { | ||
72 | QString emailClient = pSettings->getSetting(KEMailSettings::ClientProgram); | 75 | const KService::Ptr emailClientService = KMimeTypeTrader::self()->preferredService(s_mimetype); | ||
73 | bool useKMail = (emailClient.isEmpty()); | | |||
74 | 76 | | |||
75 | kmailCB->setChecked(useKMail); | 77 | const auto emailClients = KServiceTypeTrader::self()->query(QStringLiteral("Application"), | ||
76 | otherCB->setChecked(!useKMail); | 78 | QStringLiteral("'Email' in Categories and 'x-scheme-handler/mailto' in ServiceTypes")); | ||
77 | txtEMailClient->setText(emailClient); | | |||
78 | txtEMailClient->setFixedHeight(txtEMailClient->sizeHint().height()); | | |||
79 | chkRunTerminal->setChecked((pSettings->getSetting(KEMailSettings::ClientTerminal) == QLatin1String("true"))); | | |||
80 | 79 | | |||
81 | emit changed(false); | 80 | emailClientsCombo->clear(); | ||
81 | m_kmailIndex = -1; | ||||
82 | m_currentIndex = -1; | ||||
83 | | ||||
84 | for (const auto &service : emailClients) { | ||||
85 | | ||||
86 | emailClientsCombo->addItem(QIcon::fromTheme(service->icon()), service->name(), service->storageId()); | ||||
82 | 87 | | |||
88 | if (emailClientService && emailClientService->storageId() == service->storageId()) { | ||||
89 | emailClientsCombo->setCurrentIndex(emailClientsCombo->count() - 1); | ||||
90 | m_currentIndex = emailClientsCombo->count() - 1; | ||||
91 | } | ||||
92 | if (service->storageId() == QStringLiteral("org.kde.kmail2.desktop") || | ||||
93 | service->storageId() == QStringLiteral("org.kde.kmail.desktop")) { | ||||
94 | m_kmailIndex = emailClientsCombo->count() - 1; | ||||
95 | } | ||||
83 | } | 96 | } | ||
84 | 97 | | |||
85 | void CfgEmailClient::configChanged() | 98 | // add the Added association to x-scheme-handler/mailto from the mimeapps.list file | ||
86 | { | 99 | const KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::GenericConfigLocation); | ||
87 | emit changed(true); | 100 | const KConfigGroup addedApps(profile, s_AddedAssociations); | ||
101 | const auto addedList = addedApps.readXdgListEntry(s_mimetype); | ||||
102 | | ||||
103 | for (const auto &addedApp : addedList) { | ||||
104 | // without .desktop extension | ||||
105 | auto service = KService::serviceByStorageId(addedApp.mid(0, addedApp.length() -8)); | ||||
106 | if (!service) { | ||||
107 | service = KService::serviceByStorageId(addedApp); | ||||
108 | } | ||||
109 | if (!service) { | ||||
110 | continue; | ||||
88 | } | 111 | } | ||
112 | // avoid duplicates entry when email clients are present in mimeapps.list's Added Associations too | ||||
113 | const bool isServiceAlreadyInserted = std::none_of(emailClients.constBegin(), emailClients.constEnd(), [service] (const KService::Ptr &serv) { return service->storageId() == serv->storageId(); }); | ||||
114 | if (isServiceAlreadyInserted) { | ||||
115 | const auto icon = QIcon::fromTheme(!service->icon().isEmpty() ? service->icon() : QStringLiteral("application-x-shellscript")); | ||||
116 | emailClientsCombo->addItem(icon, service->name() + " (" + KShell::tildeCollapse(service->entryPath()) + ")", service->storageId()); | ||||
89 | 117 | | |||
90 | void CfgEmailClient::selectEmailClient() | 118 | if (emailClientService && emailClientService->storageId() == service->storageId()) { | ||
91 | { | 119 | emailClientsCombo->setCurrentIndex(emailClientsCombo->count() - 1); | ||
92 | QList<QUrl> urlList; | 120 | m_currentIndex = emailClientsCombo->count() - 1; | ||
93 | KOpenWithDialog dlg(urlList, i18n("Select preferred email client:"), QString(), this); | 121 | } | ||
94 | // hide "Do not &close when command exits" here, we don't need it for a mail client | | |||
95 | dlg.hideNoCloseOnExit(); | | |||
96 | if (dlg.exec() != QDialog::Accepted) return; | | |||
97 | QString client = dlg.text(); | | |||
98 | m_emailClientService = dlg.service(); | | |||
99 | | ||||
100 | // get the preferred Terminal Application | | |||
101 | KConfigGroup confGroup( KSharedConfig::openConfig(), QStringLiteral("General") ); | | |||
102 | QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QStringLiteral("konsole")); | | |||
103 | preferredTerminal += QLatin1String(" -e "); | | |||
104 | | ||||
105 | int len = preferredTerminal.length(); | | |||
106 | bool b = client.left(len) == preferredTerminal; | | |||
107 | if (b) client = client.mid(len); | | |||
108 | if (!client.isEmpty()) | | |||
109 | { | | |||
110 | chkRunTerminal->setChecked(b); | | |||
111 | txtEMailClient->setText(client); | | |||
112 | } | 122 | } | ||
113 | } | 123 | } | ||
114 | 124 | | |||
125 | // add a other option to add a new email client with KOpenWithDialog | ||||
126 | emailClientsCombo->addItem(QIcon::fromTheme(QStringLiteral("application-x-shellscript")), i18n("Other..."), QStringLiteral()); | ||||
115 | 127 | | |||
116 | void CfgEmailClient::save(KConfig *) | 128 | emit changed(false); | ||
129 | } | ||||
130 | | ||||
131 | void CfgEmailClient::selectEmailClient(int index) | ||||
117 | { | 132 | { | ||
118 | if (kmailCB->isChecked()) | 133 | if (index == emailClientsCombo->count() -1) { | ||
134 | // Other option | ||||
135 | | ||||
136 | KOpenWithDialog dlg(s_mimetype, QString(), this); | ||||
137 | dlg.setSaveNewApplications(true); | ||||
138 | | ||||
139 | if (dlg.exec() != QDialog::Accepted) { | ||||
140 | // restore previous setting | ||||
141 | emailClientsCombo->setCurrentIndex(m_currentIndex); | ||||
142 | emit changed(false); | ||||
143 | } else { | ||||
144 | const auto service = dlg.service(); | ||||
145 | | ||||
146 | const auto icon = QIcon::fromTheme(!service->icon().isEmpty() ? service->icon() : QStringLiteral("application-x-shellscript")); | ||||
147 | emailClientsCombo->insertItem(emailClientsCombo->count() - 1, icon, service->name() + " (" + KShell::tildeCollapse(service->entryPath()) + ")", service->storageId()); | ||||
148 | | ||||
149 | // select newly inserted email client | ||||
150 | emailClientsCombo->setCurrentIndex(emailClientsCombo->count() - 2); | ||||
151 | | ||||
152 | emit changed(true); | ||||
153 | return; | ||||
154 | } | ||||
155 | } else { | ||||
156 | emit changed(m_currentIndex != index); | ||||
157 | } | ||||
158 | } | ||||
159 | | ||||
160 | void CfgEmailClient::save(KConfig *) | ||||
119 | { | 161 | { | ||
162 | const QString &storageId = emailClientsCombo->currentData().toString(); | ||||
163 | const KService::Ptr emailClientService = KService::serviceByStorageId(storageId); | ||||
164 | | ||||
165 | const bool kmailSelected = m_kmailIndex != -1 && emailClientsCombo->currentIndex() == m_kmailIndex; | ||||
166 | if (kmailSelected) { | ||||
120 | pSettings->setSetting(KEMailSettings::ClientProgram, QString()); | 167 | pSettings->setSetting(KEMailSettings::ClientProgram, QString()); | ||
121 | pSettings->setSetting(KEMailSettings::ClientTerminal, QStringLiteral("false")); | 168 | pSettings->setSetting(KEMailSettings::ClientTerminal, QStringLiteral("false")); | ||
169 | } else { | ||||
170 | pSettings->setSetting(KEMailSettings::ClientProgram, emailClientService->storageId()); | ||||
171 | pSettings->setSetting(KEMailSettings::ClientTerminal, emailClientService->terminal() ? QStringLiteral("true") : QStringLiteral("false")); | ||||
122 | } | 172 | } | ||
123 | else | | |||
124 | { | | |||
125 | pSettings->setSetting(KEMailSettings::ClientProgram, txtEMailClient->text()); | | |||
126 | pSettings->setSetting(KEMailSettings::ClientTerminal, (chkRunTerminal->isChecked()) ? "true" : "false"); | | |||
127 | } | | |||
128 | 173 | | |||
129 | // Save the default email client in mimeapps.list into the group [Default Applications] | 174 | // Save the default email client in mimeapps.list | ||
175 | KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::GenericConfigLocation); | ||||
176 | if (profile->isConfigWritable(true) && emailClientService) { | ||||
177 | | ||||
130 | KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::GenericConfigLocation); | 178 | KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::GenericConfigLocation); | ||
131 | if (profile->isConfigWritable(true)) { | 179 | | ||
180 | // Save the default application according to mime-apps-spec 1.0 | ||||
132 | KConfigGroup defaultApp(profile, "Default Applications"); | 181 | KConfigGroup defaultApp(profile, "Default Applications"); | ||
133 | if (kmailCB->isChecked()) { | 182 | defaultApp.writeXdgListEntry(s_mimetype, {emailClientService->storageId()}); | ||
134 | QString kmailDesktop = QStringLiteral("org.kde.kmail.desktop"); | 183 | | ||
135 | if (KService::serviceByDesktopName(QStringLiteral("org.kde.kmail2"))) { | 184 | KConfigGroup addedApps(profile, "Added Associations"); | ||
136 | kmailDesktop = QStringLiteral("org.kde.kmail2.desktop"); | 185 | QStringList apps = addedApps.readXdgListEntry(s_mimetype); | ||
137 | } | 186 | apps.removeAll(emailClientService->storageId()); | ||
138 | defaultApp.writeXdgListEntry("x-scheme-handler/mailto", QStringList(kmailDesktop)); | 187 | apps.prepend(emailClientService->storageId()); // make it the preferred app, i.e first in list | ||
139 | } else if (m_emailClientService) { | 188 | addedApps.writeXdgListEntry(s_mimetype, apps); | ||
140 | defaultApp.writeXdgListEntry("x-scheme-handler/mailto", QStringList(m_emailClientService->storageId())); | 189 | | ||
141 | } | | |||
142 | profile->sync(); | 190 | profile->sync(); | ||
143 | } | | |||
144 | 191 | | |||
145 | // insure proper permissions -- contains sensitive data | 192 | m_currentIndex = emailClientsCombo->currentIndex(); | ||
146 | QString cfgName(QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("emails"))); | 193 | | ||
147 | if (!cfgName.isEmpty()) | 194 | // refresh cache | ||
148 | ::chmod(QFile::encodeName(cfgName), 0600); | 195 | KBuildSycocaProgressDialog::rebuildKSycoca(this); | ||
149 | QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/Component"), QStringLiteral("org.kde.Kcontrol"), QStringLiteral("KDE_emailSettingsChanged") ); | 196 | | ||
150 | QDBusConnection::sessionBus().send(message); | | |||
151 | emit changed(false); | 197 | emit changed(false); | ||
152 | } | 198 | } | ||
199 | } | ||||
153 | 200 | |