diff --git a/kcms/componentchooser/componentchooser.cpp b/kcms/componentchooser/componentchooser.cpp --- a/kcms/componentchooser/componentchooser.cpp +++ b/kcms/componentchooser/componentchooser.cpp @@ -203,6 +203,7 @@ if (configWidget) { configContainer->setCurrentWidget(configWidget); const auto plugin = dynamic_cast(configWidget); + headerGroupBox->setTitle(it->text()); plugin->load(&cfg); emit defaulted(plugin->isDefaults()); } diff --git a/kcms/componentchooser/componentchooser_ui.ui b/kcms/componentchooser/componentchooser_ui.ui --- a/kcms/componentchooser/componentchooser_ui.ui +++ b/kcms/componentchooser/componentchooser_ui.ui @@ -15,7 +15,7 @@ 0 - + 0 diff --git a/kcms/componentchooser/componentchooseremail.h b/kcms/componentchooser/componentchooseremail.h --- a/kcms/componentchooser/componentchooseremail.h +++ b/kcms/componentchooser/componentchooseremail.h @@ -34,11 +34,11 @@ private: KEMailSettings *pSettings; - KService::Ptr m_emailClientService; + int m_currentIndex = -1; + int m_kmailIndex = -1; protected Q_SLOTS: - void selectEmailClient(); - void configChanged(); + void selectEmailClient(int index); Q_SIGNALS: void changed(bool); }; diff --git a/kcms/componentchooser/componentchooseremail.cpp b/kcms/componentchooser/componentchooseremail.cpp --- a/kcms/componentchooser/componentchooseremail.cpp +++ b/kcms/componentchooser/componentchooseremail.cpp @@ -1,8 +1,8 @@ /*************************************************************************** componentchooseremail.cpp ------------------- - copyright : (C) 2002 by Joseph Wenninger - email : jowenn@kde.org + copyright : (C) 2002 by Joseph Wenninger + copyright : (C) 2020 by Méven Car ***************************************************************************/ /*************************************************************************** @@ -22,132 +22,178 @@ #include #include #include +#include +#include +#include +#include + #include #include #include #include #include -// for chmod: -#include -#include -#include - +namespace { + static const char s_AddedAssociations[] = "Added Associations"; + static const auto s_mimetype = QStringLiteral("x-scheme-handler/mailto"); +} CfgEmailClient::CfgEmailClient(QWidget *parent) : QWidget(parent), Ui::EmailClientConfig_UI(), CfgPlugin() { setupUi( this ); pSettings = new KEMailSettings(); - connect(kmailCB, &QRadioButton::toggled, this, &CfgEmailClient::configChanged); - connect(txtEMailClient, &KLineEdit::textChanged, this, &CfgEmailClient::configChanged); -#ifdef Q_OS_UNIX - connect(chkRunTerminal, &QCheckBox::clicked, this, &CfgEmailClient::configChanged); -#else - chkRunTerminal->hide(); -#endif - connect(btnSelectEmail, &QToolButton::clicked, this, &CfgEmailClient::selectEmailClient); + connect(emailClientsCombo, static_cast(&QComboBox::activated), this, &CfgEmailClient::selectEmailClient); } CfgEmailClient::~CfgEmailClient() { delete pSettings; } void CfgEmailClient::defaults() { - kmailCB->setChecked(true); - txtEMailClient->clear(); - chkRunTerminal->setChecked(false); + // select kmail if installed + if (m_kmailIndex != -1) { + emailClientsCombo->setCurrentIndex(m_kmailIndex); + } } bool CfgEmailClient::isDefaults() const { - return kmailCB->isChecked(); + // if kmail is installed and is selected + if (m_kmailIndex != -1) { + return emailClientsCombo->currentIndex() == m_kmailIndex; + } + + return true; } void CfgEmailClient::load(KConfig *) { - QString emailClient = pSettings->getSetting(KEMailSettings::ClientProgram); - bool useKMail = (emailClient.isEmpty()); + const KService::Ptr emailClientService = KMimeTypeTrader::self()->preferredService(s_mimetype); - kmailCB->setChecked(useKMail); - otherCB->setChecked(!useKMail); - txtEMailClient->setText(emailClient); - txtEMailClient->setFixedHeight(txtEMailClient->sizeHint().height()); - chkRunTerminal->setChecked((pSettings->getSetting(KEMailSettings::ClientTerminal) == QLatin1String("true"))); + const auto emailClients = KServiceTypeTrader::self()->query(QStringLiteral("Application"), + QStringLiteral("'Email' in Categories and 'x-scheme-handler/mailto' in ServiceTypes")); - emit changed(false); + emailClientsCombo->clear(); + m_kmailIndex = -1; + m_currentIndex = -1; -} + for (const auto &service : emailClients) { -void CfgEmailClient::configChanged() -{ - emit changed(true); + emailClientsCombo->addItem(QIcon::fromTheme(service->icon()), service->name(), service->storageId()); + + if (emailClientService && emailClientService->storageId() == service->storageId()) { + emailClientsCombo->setCurrentIndex(emailClientsCombo->count() - 1); + m_currentIndex = emailClientsCombo->count() - 1; + } + if (service->storageId() == QStringLiteral("org.kde.kmail2.desktop") || + service->storageId() == QStringLiteral("org.kde.kmail.desktop")) { + m_kmailIndex = emailClientsCombo->count() - 1; + } + } + + // add the Added association to x-scheme-handler/mailto from the mimeapps.list file + const KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::GenericConfigLocation); + const KConfigGroup addedApps(profile, s_AddedAssociations); + const auto addedList = addedApps.readXdgListEntry(s_mimetype); + + for (const auto &addedApp : addedList) { + // without .desktop extension + auto service = KService::serviceByStorageId(addedApp.mid(0, addedApp.length() -8)); + if (!service) { + service = KService::serviceByStorageId(addedApp); + } + if (service) { + // avoid duplicates entry when email clients are present in mimeapps.list's Added Associations too + const bool isServiceAlreadyInserted = std::none_of(emailClients.constBegin(), emailClients.constEnd(), [service] (const KService::Ptr &serv) { return service->storageId() == serv->storageId(); }); + if (isServiceAlreadyInserted) { + const auto icon = QIcon::fromTheme(!service->icon().isEmpty() ? service->icon() : QStringLiteral("application-x-shellscript")); + emailClientsCombo->addItem(icon, service->name() + " (" + KShell::tildeCollapse(service->entryPath()) + ")", service->storageId()); + + if (emailClientService && emailClientService->storageId() == service->storageId()) { + emailClientsCombo->setCurrentIndex(emailClientsCombo->count() - 1); + m_currentIndex = emailClientsCombo->count() - 1; + } + } + } + } + + // add a other option to add a new email client with KOpenWithDialog + emailClientsCombo->addItem(QIcon::fromTheme(QStringLiteral("application-x-shellscript")), i18n("Other..."), QStringLiteral()); + + emit changed(false); } -void CfgEmailClient::selectEmailClient() +void CfgEmailClient::selectEmailClient(int index) { - QList urlList; - KOpenWithDialog dlg(urlList, i18n("Select preferred email client:"), QString(), this); - // hide "Do not &close when command exits" here, we don't need it for a mail client - dlg.hideNoCloseOnExit(); - if (dlg.exec() != QDialog::Accepted) return; - QString client = dlg.text(); - m_emailClientService = dlg.service(); - - // get the preferred Terminal Application - KConfigGroup confGroup( KSharedConfig::openConfig(), QStringLiteral("General") ); - QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QStringLiteral("konsole")); - preferredTerminal += QLatin1String(" -e "); - - int len = preferredTerminal.length(); - bool b = client.left(len) == preferredTerminal; - if (b) client = client.mid(len); - if (!client.isEmpty()) - { - chkRunTerminal->setChecked(b); - txtEMailClient->setText(client); + if (index == emailClientsCombo->count() -1) { + // Other option + + KOpenWithDialog dlg(s_mimetype, QString(), this); + dlg.setSaveNewApplications(true); + + if (dlg.exec() != QDialog::Accepted) { + // restore previous setting + emailClientsCombo->setCurrentIndex(m_currentIndex); + emit changed(false); + } else { + const auto service = dlg.service(); + + const auto icon = QIcon::fromTheme(!service->icon().isEmpty() ? service->icon() : QStringLiteral("application-x-shellscript")); + emailClientsCombo->insertItem(emailClientsCombo->count() - 1, icon, service->name() + " (" + KShell::tildeCollapse(service->entryPath()) + ")", service->storageId()); + + // select newly inserted email client + emailClientsCombo->setCurrentIndex(emailClientsCombo->count() - 2); + + emit changed(true); + return; + } + } else { + emit changed(m_currentIndex != index); } } - void CfgEmailClient::save(KConfig *) { - if (kmailCB->isChecked()) - { + const QString &storageId = emailClientsCombo->currentData().toString(); + const KService::Ptr emailClientService = KService::serviceByStorageId(storageId); + + const bool kmailSelected = m_kmailIndex != -1 && emailClientsCombo->currentIndex() == m_kmailIndex; + if (kmailSelected) { pSettings->setSetting(KEMailSettings::ClientProgram, QString()); pSettings->setSetting(KEMailSettings::ClientTerminal, QStringLiteral("false")); - } - else - { - pSettings->setSetting(KEMailSettings::ClientProgram, txtEMailClient->text()); - pSettings->setSetting(KEMailSettings::ClientTerminal, (chkRunTerminal->isChecked()) ? "true" : "false"); + } else { + pSettings->setSetting(KEMailSettings::ClientProgram, emailClientService->storageId()); + pSettings->setSetting(KEMailSettings::ClientTerminal, emailClientService->terminal() ? QStringLiteral("true") : QStringLiteral("false")); } - // Save the default email client in mimeapps.list into the group [Default Applications] + // Save the default email client in mimeapps.list KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::GenericConfigLocation); - if (profile->isConfigWritable(true)) { + if (profile->isConfigWritable(true) && emailClientService) { + + KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::GenericConfigLocation); + + // Save the default application according to mime-apps-spec 1.0 KConfigGroup defaultApp(profile, "Default Applications"); - if (kmailCB->isChecked()) { - QString kmailDesktop = QStringLiteral("org.kde.kmail.desktop"); - if (KService::serviceByDesktopName(QStringLiteral("org.kde.kmail2"))) { - kmailDesktop = QStringLiteral("org.kde.kmail2.desktop"); - } - defaultApp.writeXdgListEntry("x-scheme-handler/mailto", QStringList(kmailDesktop)); - } else if (m_emailClientService) { - defaultApp.writeXdgListEntry("x-scheme-handler/mailto", QStringList(m_emailClientService->storageId())); - } + defaultApp.writeXdgListEntry(s_mimetype, {emailClientService->storageId()}); + + KConfigGroup addedApps(profile, "Added Associations"); + QStringList apps = addedApps.readXdgListEntry(s_mimetype); + apps.removeAll(emailClientService->storageId()); + apps.prepend(emailClientService->storageId()); // make it the preferred app, i.e first in list + addedApps.writeXdgListEntry(s_mimetype, apps); + profile->sync(); - } - // insure proper permissions -- contains sensitive data - QString cfgName(QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("emails"))); - if (!cfgName.isEmpty()) - ::chmod(QFile::encodeName(cfgName), 0600); - QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/Component"), QStringLiteral("org.kde.Kcontrol"), QStringLiteral("KDE_emailSettingsChanged") ); - QDBusConnection::sessionBus().send(message); - emit changed(false); + m_currentIndex = emailClientsCombo->currentIndex(); + + // refresh cache + KBuildSycocaProgressDialog::rebuildKSycoca(this); + + emit changed(false); + } } diff --git a/kcms/componentchooser/emailclientconfig_ui.ui b/kcms/componentchooser/emailclientconfig_ui.ui --- a/kcms/componentchooser/emailclientconfig_ui.ui +++ b/kcms/componentchooser/emailclientconfig_ui.ui @@ -2,76 +2,27 @@ EmailClientConfig_UI + + + 0 + 0 + 240 + 148 + + - + + 0 + + + 0 + + + 0 + + 0 - - - - Kmail is the standard Mail program for the Plasma desktop. - - - &Use KMail as preferred email client - - - - - - - Select this option if you want to use any other mail program. - - - Use a different &email client: - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 0 - - - - - - - - false - - - Optional placeholders: <ul> <li>%t: Recipient's address</li> <li>%s: Subject</li> <li>%c: Carbon Copy (CC)</li> <li>%b: Blind Carbon Copy (BCC)</li> <li>%B: Template body text</li> <li>%A: Attachment </li> <li>%u: Full mailto: URL </li></ul> - - - Press this button to select your favorite email client. Please note that the file you select has to have the executable attribute set in order to be accepted.<br/> You can also use several placeholders which will be replaced with the actual values when the email client is called:<ul> <li>%t: Recipient's address</li> <li>%s: Subject</li> <li>%c: Carbon Copy (CC)</li> <li>%b: Blind Carbon Copy (BCC)</li> <li>%B: Template body text</li> <li>%A: Attachment </li> </ul> - - - - - - - false - - - Click here to browse for the mail program file. - - - ... - - - - - @@ -91,17 +42,7 @@ - - - false - - - Activate this option if you want the selected email client to be executed in a terminal (e.g. <em>Konsole</em>). - - - &Run in terminal - - + @@ -123,62 +64,6 @@ - - - KLineEdit - QLineEdit -
KLineEdit
-
-
- - - otherCB - toggled(bool) - chkRunTerminal - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - otherCB - toggled(bool) - txtEMailClient - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - otherCB - toggled(bool) - btnSelectEmail - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - +