diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -14,8 +14,7 @@ .swp.* Doxyfile Makefile -avail -random_seed /build*/ +.cmake/ CMakeLists.txt.user* *.unc-backup* diff --git a/.krazy b/.krazy --- a/.krazy +++ b/.krazy @@ -1,2 +1 @@ SKIP /tests -EXTRA kdebug diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +1,15 @@ cmake_minimum_required(VERSION 3.5) -set(KDEPIM_VERSION_NUMBER "5.11.1") +set(PIM_VERSION "5.14.40") -project(kmail VERSION ${KDEPIM_VERSION_NUMBER}) +project(kmail VERSION ${PIM_VERSION}) include(CheckIncludeFiles) if (POLICY CMP0063) cmake_policy(SET CMP0063 NEW) endif() -set(KF5_MIN_VERSION "5.56.0") +set(KF5_MIN_VERSION "5.70.0") find_package(ECM ${KF5_MIN_VERSION} CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) @@ -32,52 +32,53 @@ include(ECMQtDeclareLoggingCategory) # Do NOT add quote -set(KDEPIM_DEV_VERSION ) +set(KDEPIM_DEV_VERSION alpha) +set(RELEASE_SERVICE_VERSION "20.07.40") # add an extra space if(DEFINED KDEPIM_DEV_VERSION) set(KDEPIM_DEV_VERSION " ${KDEPIM_DEV_VERSION}") endif() -set(KDEPIM_VERSION "${KDEPIM_VERSION_NUMBER}${KDEPIM_DEV_VERSION}") +set(KDEPIM_VERSION "${PIM_VERSION}${KDEPIM_DEV_VERSION} (${RELEASE_SERVICE_VERSION})") -set(AKONADI_MIMELIB_VERSION "5.11.1") -set(AKONADI_CONTACT_VERSION "5.11.1") -set(KCONTACTS_LIB_VERSION "5.11.1") -set(KCALENDARCORE_LIB_VERSION "5.11.1") -set(CALENDARUTILS_LIB_VERSION "5.11.1") -set(IDENTITYMANAGEMENT_LIB_VERSION "5.11.1") -set(KLDAP_LIB_VERSION "5.11.1") -set(KMAILTRANSPORT_LIB_VERSION "5.11.1") -set(KONTACTINTERFACE_LIB_VERSION "5.11.1") -set(KMIME_LIB_VERSION "5.11.1") -set(KPIMTEXTEDIT_LIB_VERSION "5.11.1") -set(AKONADI_VERSION "5.11.1") -set(KTNEF_LIB_VERSION "5.11.1") +set(AKONADI_MIMELIB_VERSION "5.14.43") +set(AKONADI_CONTACT_VERSION "5.14.40") +set(CALENDARUTILS_LIB_VERSION "5.14.40") +set(IDENTITYMANAGEMENT_LIB_VERSION "5.14.40") +set(KLDAP_LIB_VERSION "5.14.40") +set(KMAILTRANSPORT_LIB_VERSION "5.14.40") +set(KONTACTINTERFACE_LIB_VERSION "5.14.42") +set(KMIME_LIB_VERSION "5.14.40") +set(KPIMTEXTEDIT_LIB_VERSION "5.14.42") +set(AKONADI_VERSION "5.14.41") +set(KTNEF_LIB_VERSION "5.14.40") -set(KDEPIM_LIB_VERSION "${KDEPIM_VERSION_NUMBER}") +set(KDEPIM_LIB_VERSION "${PIM_VERSION}") set(KDEPIM_LIB_SOVERSION "5") -set(QT_REQUIRED_VERSION "5.10.0") +set(QT_REQUIRED_VERSION "5.12.0") option(KDEPIM_ENTERPRISE_BUILD "Enable features specific to the enterprise branch, which are normally disabled. Also, it disables many components not needed for Kontact such as the Kolab client." FALSE) +option(KDEPIM_RUN_AKONADI_TEST "Enable autotest based on Akonadi." TRUE) + find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED DBus Network Test Widgets WebEngine WebEngineWidgets) -set(LIBGRAVATAR_VERSION_LIB "5.11.1") -set(MAILCOMMON_LIB_VERSION_LIB "5.11.1") -set(KDEPIM_APPS_LIB_VERSION_LIB "5.11.1") -set(MESSAGELIB_LIB_VERSION_LIB "5.11.1") -set(LIBKLEO_LIB_VERSION_LIB "5.11.1") -set(PIMCOMMON_LIB_VERSION_LIB "5.11.1") -set(LIBKDEPIM_LIB_VERSION_LIB "5.11.1") -set(LIBKSIEVE_LIB_VERSION_LIB "5.11.1") +set(LIBGRAVATAR_VERSION_LIB "5.14.40") +set(MAILCOMMON_LIB_VERSION_LIB "5.14.42") +set(KDEPIM_APPS_LIB_VERSION_LIB "5.14.40") +set(MESSAGELIB_LIB_VERSION_LIB "5.14.44") +set(LIBKLEO_LIB_VERSION_LIB "5.14.40") +set(PIMCOMMON_LIB_VERSION_LIB "5.14.41") +set(LIBKDEPIM_LIB_VERSION_LIB "5.14.42") +set(LIBKSIEVE_LIB_VERSION_LIB "5.14.40") find_package(KF5WebEngineViewer ${MESSAGELIB_LIB_VERSION_LIB} CONFIG REQUIRED) -find_package(KF5AkonadiSearch "5.11.1" CONFIG REQUIRED) +find_package(KF5AkonadiSearch "5.14.40" CONFIG REQUIRED) set_package_properties(KF5AkonadiSearch PROPERTIES DESCRIPTION "The Akonadi Search libraries" URL "https://www.kde.org" TYPE REQUIRED PURPOSE "Provides search capabilities in KMail and Akonadi") -set(GPGMEPP_LIB_VERSION "1.8.0") +set(GPGMEPP_LIB_VERSION "1.11.1") find_package(Gpgmepp ${GPGMEPP_LIB_VERSION} CONFIG REQUIRED) # Find KF5 package @@ -104,13 +105,13 @@ find_package(KF5WindowSystem ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5XmlGui ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5IconThemes ${KF5_MIN_VERSION} CONFIG REQUIRED) +find_package(KF5Contacts ${KF5_MIN_VERSION} CONFIG REQUIRED) +find_package(KF5CalendarCore ${KF5_MIN_VERSION} CONFIG REQUIRED) # Find KdepimLibs Package find_package(KF5Akonadi ${AKONADI_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiContact ${AKONADI_CONTACT_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiMime ${AKONADI_MIMELIB_VERSION} CONFIG REQUIRED) -find_package(KF5Contacts ${KCONTACTS_LIB_VERSION} CONFIG REQUIRED) -find_package(KF5CalendarCore ${KCALENDARCORE_LIB_VERSION} CONFIG REQUIRED) find_package(KF5CalendarUtils ${CALENDARUTILS_LIB_VERSION} CONFIG REQUIRED) find_package(KF5IdentityManagement ${IDENTITYMANAGEMENT_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Ldap ${KLDAP_LIB_VERSION} CONFIG REQUIRED) @@ -122,7 +123,6 @@ find_package(KF5FollowupReminder ${KDEPIM_APPS_LIB_VERSION_LIB} CONFIG REQUIRED) find_package(KF5Gravatar ${LIBGRAVATAR_VERSION_LIB} CONFIG REQUIRED) -find_package(KF5KdepimDBusInterfaces ${KDEPIM_APPS_LIB_VERSION_LIB} CONFIG REQUIRED) find_package(KF5LibkdepimAkonadi ${LIBKDEPIM_LIB_VERSION_LIB} CONFIG REQUIRED) find_package(KF5Libkleo ${LIBKLEO_LIB_VERSION_LIB} CONFIG REQUIRED) find_package(KF5LibKSieve ${LIBKSIEVE_LIB_VERSION_LIB} CONFIG REQUIRED) @@ -141,22 +141,31 @@ include_directories(${kmail_SOURCE_DIR} ${kmail_BINARY_DIR}) configure_file(kmail-version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/kmail-version.h @ONLY) - -# workaround for https://bugreports.qt.io/browse/QTBUG-74665 (bug in qt5.13 reevaluate it) -if (${Qt5Widgets_VERSION} STRGREATER "5.13") - MESSAGE(STATUS "Qt version: ${Qt5Widgets_VERSION} DISABLE compile without deprecated methods. bug QTBUG-74665") -else() - add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000) +if(BUILD_TESTING) + add_definitions(-DBUILD_TESTING) endif() -if (${KF5Config_VERSION} STRGREATER "5.56.0") - add_definitions(-DQT_NO_FOREACH) - MESSAGE(STATUS "compile without foreach") + +if (EXISTS "${CMAKE_SOURCE_DIR}/.git") + add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050e00) + #add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x054600) #Need to find a convert method for KPluginInfo::fromServices endif() +add_definitions(-DQT_NO_FOREACH) +add_definitions(-DQT_NO_KEYWORDS) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(KUserFeedback 0.9.90 CONFIG) # Needs Provider::describeDataSources() +set_package_properties(KUserFeedback PROPERTIES DESCRIPTION "User Feedback lib" TYPE OPTIONAL PURPOSE "Allow to send Telemetry Information (optional). It can be disable in apps.") + add_subdirectory(src) add_subdirectory(agents) add_subdirectory(ktnef) - -install( FILES kmail.renamecategories kmail.categories DESTINATION ${KDE_INSTALL_CONFDIR} ) +add_subdirectory(kmail-refresh-settings) +ecm_qt_install_logging_categories( + EXPORT KMAIL + FILE kmail.categories + DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR} + ) add_subdirectory(doc) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1,2 +1 @@ Laurent Montel - diff --git a/agents/archivemailagent/CMakeLists.txt b/agents/archivemailagent/CMakeLists.txt --- a/agents/archivemailagent/CMakeLists.txt +++ b/agents/archivemailagent/CMakeLists.txt @@ -15,16 +15,20 @@ qt5_add_dbus_adaptor(libarchivemailagent_SRCS org.freedesktop.Akonadi.ArchiveMailAgent.xml archivemailagent.h ArchiveMailAgent) -ecm_qt_declare_logging_category(libarchivemailagent_SRCS HEADER archivemailagent_debug.h IDENTIFIER ARCHIVEMAILAGENT_LOG CATEGORY_NAME org.kde.pim.archivemailagent) +ecm_qt_declare_logging_category(libarchivemailagent_SRCS HEADER archivemailagent_debug.h IDENTIFIER ARCHIVEMAILAGENT_LOG CATEGORY_NAME org.kde.pim.archivemailagent + DESCRIPTION "kmail (archivemailagent)" + OLD_CATEGORY_NAMES log_archivemailagent + EXPORT KMAIL + ) + ki18n_wrap_ui(libarchivemailagent_SRCS ui/archivemailwidget.ui ) add_library(archivemailagent STATIC ${libarchivemailagent_SRCS}) target_link_libraries(archivemailagent KF5::MailCommon KF5::I18n KF5::Notifications - KF5::IconThemes KF5::KIOWidgets ) @@ -44,7 +48,6 @@ KF5::Notifications KF5::MailCommon KF5::Libkdepim - KF5::IconThemes KF5::I18n ) diff --git a/agents/archivemailagent/addarchivemaildialog.h b/agents/archivemailagent/addarchivemaildialog.h --- a/agents/archivemailagent/addarchivemaildialog.h +++ b/agents/archivemailagent/addarchivemaildialog.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -20,7 +20,7 @@ #ifndef ADDARCHIVEMAILDIALOG_H #define ADDARCHIVEMAILDIALOG_H -#include "MailCommon/BackupJob" +#include #include "archivemailinfo.h" #include #include @@ -47,19 +47,19 @@ MailCommon::BackupJob::ArchiveType archiveType() const; void setRecursive(bool b); - bool recursive() const; + Q_REQUIRED_RESULT bool recursive() const; void setSelectedFolder(const Akonadi::Collection &collection); Akonadi::Collection selectedFolder() const; - QUrl path() const; + Q_REQUIRED_RESULT QUrl path() const; void setPath(const QUrl &); ArchiveMailInfo *info(); void setMaximumArchiveCount(int); - int maximumArchiveCount() const; + Q_REQUIRED_RESULT int maximumArchiveCount() const; private: void slotFolderChanged(const Akonadi::Collection &); diff --git a/agents/archivemailagent/addarchivemaildialog.cpp b/agents/archivemailagent/addarchivemaildialog.cpp --- a/agents/archivemailagent/addarchivemaildialog.cpp +++ b/agents/archivemailagent/addarchivemaildialog.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -20,12 +20,12 @@ #include "addarchivemaildialog.h" #include "widgets/formatcombobox.h" #include "widgets/unitcombobox.h" -#include "MailCommon/FolderRequester" - +#include #include #include #include +#include #include #include #include @@ -42,9 +42,9 @@ , mInfo(info) { if (info) { - setWindowTitle(i18n("Modify Archive Mail")); + setWindowTitle(i18nc("@title:window", "Modify Archive Mail")); } else { - setWindowTitle(i18n("Add Archive Mail")); + setWindowTitle(i18nc("@title:window", "Add Archive Mail")); } setModal(true); setWindowIcon(QIcon::fromTheme(QStringLiteral("kmail"))); diff --git a/agents/archivemailagent/akonadi_archivemail_agent.notifyrc b/agents/archivemailagent/akonadi_archivemail_agent.notifyrc --- a/agents/archivemailagent/akonadi_archivemail_agent.notifyrc +++ b/agents/archivemailagent/akonadi_archivemail_agent.notifyrc @@ -12,6 +12,7 @@ Comment[en_GB]=Archive Mail Agent Comment[es]=Agente de archivado de correo Comment[et]=Kirjade arhiveerimise agent +Comment[eu]=Posta artxibatzeko agentea Comment[fi]=Postin arkistointiagentti Comment[fr]=Agent d'archivage de courriel Comment[gl]=Axente Arquivar o correo @@ -28,7 +29,7 @@ Comment[nl]=E-mailagent voor archiveren Comment[pl]=Usługa archiwizacji poczty Comment[pt]=Agente de Arquivo de E-Mail -Comment[pt_BR]=Agente de Arquivamento de E-mails +Comment[pt_BR]=Agente de arquivamento de e-mails Comment[ro]=Agent de arhivare a poștei Comment[ru]=Агент архивирования почты Comment[sk]=Archivovať agenta pošty @@ -43,7 +44,7 @@ Comment[wa]=Adjint d' årtchivaedje d' emiles Comment[x-test]=xxArchive Mail Agentxx Comment[zh_CN]=邮件归档代理 -Comment[zh_TW]=歸檔郵件代理程式 +Comment[zh_TW]=封存郵件代理程式 Name=Archive Mail Agent Name[ar]=وكيل أرشفة البريد Name[bs]=Arhiva poštanskih agenata @@ -56,6 +57,7 @@ Name[en_GB]=Archive Mail Agent Name[es]=Agente de archivado de correo Name[et]=Kirjade arhiveerimise agent +Name[eu]=Posta artxibatzeko agentea Name[fi]=Postin arkistointiagentti Name[fr]=Agent d'archivage de courriel Name[gl]=Axente Arquivar o correo @@ -87,7 +89,7 @@ Name[wa]=Adjint d' årtchivaedje d' emiles Name[x-test]=xxArchive Mail Agentxx Name[zh_CN]=邮件归档代理 -Name[zh_TW]=歸檔郵件代理程式 +Name[zh_TW]=封存郵件代理程式 [Event/archivemailfinished] Name=Archive Mail finished @@ -101,6 +103,7 @@ Name[en_GB]=Archive Mail finished Name[es]=Archivado de correo terminado Name[et]=Kirjad on arhiveeritud +Name[eu]=Posta artxibatzea amaitu da Name[fi]=Postin arkistointi valmis Name[fr]=Archivage du courriel terminé Name[gl]=Rematou Arquivar o correo @@ -132,7 +135,7 @@ Name[wa]=Årtchivaedje des emiles tot fwait Name[x-test]=xxArchive Mail finishedxx Name[zh_CN]=邮件归档完成 -Name[zh_TW]=歸檔郵件已完成 +Name[zh_TW]=封存郵件已完成 Action=Popup [Event/archivemailstarted] @@ -147,6 +150,7 @@ Name[en_GB]=Archive Mail started Name[es]=Archivado de correo iniciado Name[et]=Kirjade arhiveerimine algas +Name[eu]=Posta artxibatzea abiatu da Name[fi]=Postin arkistointi käynnistetty Name[fr]=Archivage du courriel démarré Name[gl]=Iniciouse Arquivar o correo @@ -178,7 +182,7 @@ Name[wa]=Årtchivaedje des emiles ataké Name[x-test]=xxArchive Mail startedxx Name[zh_CN]=邮件归档开始 -Name[zh_TW]=歸檔郵件已開始 +Name[zh_TW]=封存郵件已開始 Action=Popup [Event/archivemailfolderdoesntexist] @@ -192,13 +196,14 @@ Name[en_GB]=Directory does not exist Name[es]=El directorio no existe Name[et]=Kataloogi ei ole olemas +Name[eu]=Direktorio ez dago Name[fi]=Kansiota ei ole olemassa Name[fr]=Le dossier n'existe pas Name[gl]=O directorio non existe Name[hu]=A könyvtár nem létezik Name[ia]=Le directorio non existe Name[it]=La cartella non esiste -Name[ko]=디렉터리 서비스가 존재하지 않음 +Name[ko]=디렉터리가 없음 Name[nb]=Mappa finnes ikke Name[nds]=Gifft Orner nich Name[nl]=Map bestaat niet @@ -233,6 +238,7 @@ Name[en_GB]=Archive Mail Error Name[es]=Error de archivado de correo Name[et]=Kirjade arhiveerimise tõrge +Name[eu]=Posta artxibatzeko errorea Name[fi]=Postin arkistointivirhe Name[fr]=Erreur d'archivage du courriel Name[gl]=Erro de Arquivar o correo @@ -264,6 +270,6 @@ Name[wa]=Åk n' a nén stî come dj' årtchivéve les emiles Name[x-test]=xxArchive Mail Errorxx Name[zh_CN]=邮件归档发生错误 -Name[zh_TW]=歸檔郵件發生錯誤 +Name[zh_TW]=封存郵件發生錯誤 Action=Popup diff --git a/agents/archivemailagent/archivemailagent.h b/agents/archivemailagent/archivemailagent.h --- a/agents/archivemailagent/archivemailagent.h +++ b/agents/archivemailagent/archivemailagent.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -36,12 +36,12 @@ explicit ArchiveMailAgent(const QString &id); ~ArchiveMailAgent() override; - QString printArchiveListInfo(); + Q_REQUIRED_RESULT QString printArchiveListInfo() const; void setEnableAgent(bool b); - bool enabledAgent() const; + Q_REQUIRED_RESULT bool enabledAgent() const; - QString printCurrentListInfo(); + Q_REQUIRED_RESULT QString printCurrentListInfo() const; void archiveFolder(const QString &path, Akonadi::Collection::Id collectionId); Q_SIGNALS: void archiveNow(ArchiveMailInfo *info); diff --git a/agents/archivemailagent/archivemailagent.cpp b/agents/archivemailagent/archivemailagent.cpp --- a/agents/archivemailagent/archivemailagent.cpp +++ b/agents/archivemailagent/archivemailagent.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -24,15 +24,14 @@ #include #include -#include +#include #include #include #include #include #include -#include -#include +#include //#define DEBUG_ARCHIVEMAILAGENT 1 @@ -56,11 +55,11 @@ collectionMonitor->setMimeTypeMonitored(KMime::Message::mimeType()); new ArchiveMailAgentAdaptor(this); - KDBusConnectionPool::threadConnection().registerObject(QStringLiteral("/ArchiveMailAgent"), this, QDBusConnection::ExportAdaptors); + QDBusConnection::sessionBus().registerObject(QStringLiteral("/ArchiveMailAgent"), this, QDBusConnection::ExportAdaptors); const QString service = Akonadi::ServerManager::self()->agentServiceName(Akonadi::ServerManager::Agent, identifier()); - KDBusConnectionPool::threadConnection().registerService(service); + QDBusConnection::sessionBus().registerService(service); connect(collectionMonitor, &Akonadi::Monitor::collectionRemoved, this, &ArchiveMailAgent::mailCollectionRemoved); if (enabledAgent()) { @@ -135,12 +134,12 @@ } } -QString ArchiveMailAgent::printArchiveListInfo() +QString ArchiveMailAgent::printArchiveListInfo() const { return mArchiveManager->printArchiveListInfo(); } -QString ArchiveMailAgent::printCurrentListInfo() +QString ArchiveMailAgent::printCurrentListInfo() const { return mArchiveManager->printCurrentListInfo(); } diff --git a/agents/archivemailagent/archivemailagent.desktop b/agents/archivemailagent/archivemailagent.desktop --- a/agents/archivemailagent/archivemailagent.desktop +++ b/agents/archivemailagent/archivemailagent.desktop @@ -11,6 +11,7 @@ Name[en_GB]=Archive Mail Agent Name[es]=Agente de archivado de correo Name[et]=Kirjade arhiveerimise agent +Name[eu]=Posta artxibatzeko agentea Name[fi]=Postin arkistointiagentti Name[fr]=Agent d'archivage de courriel Name[gl]=Axente Arquivar o correo @@ -42,7 +43,7 @@ Name[wa]=Adjint d' årtchivaedje d' emiles Name[x-test]=xxArchive Mail Agentxx Name[zh_CN]=邮件归档代理 -Name[zh_TW]=歸檔郵件代理程式 +Name[zh_TW]=封存郵件代理程式 Comment=Archive Mail Agent Comment[ar]=وكيل أرشفة البريد Comment[bs]=Arhiva poštanskih agenata @@ -55,6 +56,7 @@ Comment[en_GB]=Archive Mail Agent Comment[es]=Agente de archivado de correo Comment[et]=Kirjade arhiveerimise agent +Comment[eu]=Posta artxibatzeko agentea Comment[fi]=Postin arkistointiagentti Comment[fr]=Agent d'archivage de courriel Comment[gl]=Axente Arquivar o correo @@ -71,7 +73,7 @@ Comment[nl]=E-mailagent voor archiveren Comment[pl]=Usługa archiwizacji poczty Comment[pt]=Agente de Arquivo de E-Mail -Comment[pt_BR]=Agente de Arquivamento de E-mails +Comment[pt_BR]=Agente de arquivamento de e-mails Comment[ro]=Agent de arhivare a poștei Comment[ru]=Агент архивирования почты Comment[sk]=Archivovať agenta pošty @@ -86,7 +88,7 @@ Comment[wa]=Adjint d' årtchivaedje d' emiles Comment[x-test]=xxArchive Mail Agentxx Comment[zh_CN]=邮件归档代理 -Comment[zh_TW]=歸檔郵件代理程式 +Comment[zh_TW]=封存郵件代理程式 Type=AkonadiAgent Exec=akonadi_archivemail_agent Icon=kmail diff --git a/agents/archivemailagent/archivemailagentutil.h b/agents/archivemailagent/archivemailagentutil.h --- a/agents/archivemailagent/archivemailagentutil.h +++ b/agents/archivemailagent/archivemailagentutil.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -25,8 +25,8 @@ namespace ArchiveMailAgentUtil { static QString archivePattern = QStringLiteral("ArchiveMailCollection %1"); -QDate diffDate(ArchiveMailInfo *info); -bool needToArchive(ArchiveMailInfo *info); +Q_REQUIRED_RESULT QDate diffDate(ArchiveMailInfo *info); +Q_REQUIRED_RESULT bool needToArchive(ArchiveMailInfo *info); } #endif // ARCHIVEMAILAGENTUTIL_H diff --git a/agents/archivemailagent/archivemailagentutil.cpp b/agents/archivemailagent/archivemailagentutil.cpp --- a/agents/archivemailagent/archivemailagentutil.cpp +++ b/agents/archivemailagent/archivemailagentutil.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/archivemailagent/archivemailinfo.h b/agents/archivemailagent/archivemailinfo.h --- a/agents/archivemailagent/archivemailinfo.h +++ b/agents/archivemailagent/archivemailinfo.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -19,7 +19,7 @@ #ifndef ARCHIVEMAILINFO_H #define ARCHIVEMAILINFO_H -#include "MailCommon/BackupJob" +#include #include #include #include @@ -42,43 +42,43 @@ ArchiveYears }; - QUrl realUrl(const QString &folderName, bool &dirExist) const; + Q_REQUIRED_RESULT QUrl realUrl(const QString &folderName, bool &dirExist) const; - bool isValid() const; + Q_REQUIRED_RESULT bool isValid() const; - Akonadi::Collection::Id saveCollectionId() const; + Q_REQUIRED_RESULT Akonadi::Collection::Id saveCollectionId() const; void setSaveCollectionId(Akonadi::Collection::Id collectionId); void setSaveSubCollection(bool b); - bool saveSubCollection() const; + Q_REQUIRED_RESULT bool saveSubCollection() const; void setUrl(const QUrl &url); - QUrl url() const; + Q_REQUIRED_RESULT QUrl url() const; void readConfig(const KConfigGroup &config); void writeConfig(KConfigGroup &config); void setArchiveType(MailCommon::BackupJob::ArchiveType type); - MailCommon::BackupJob::ArchiveType archiveType() const; + Q_REQUIRED_RESULT MailCommon::BackupJob::ArchiveType archiveType() const; void setArchiveUnit(ArchiveMailInfo::ArchiveUnit unit); - ArchiveMailInfo::ArchiveUnit archiveUnit() const; + Q_REQUIRED_RESULT ArchiveMailInfo::ArchiveUnit archiveUnit() const; void setArchiveAge(int age); - int archiveAge() const; + Q_REQUIRED_RESULT int archiveAge() const; void setLastDateSaved(const QDate &date); - QDate lastDateSaved() const; + Q_REQUIRED_RESULT QDate lastDateSaved() const; - int maximumArchiveCount() const; + Q_REQUIRED_RESULT int maximumArchiveCount() const; void setMaximumArchiveCount(int max); - QStringList listOfArchive(const QString &foldername, bool &dirExist) const; + Q_REQUIRED_RESULT QStringList listOfArchive(const QString &foldername, bool &dirExist) const; - bool isEnabled() const; + Q_REQUIRED_RESULT bool isEnabled() const; void setEnabled(bool b); - bool operator ==(const ArchiveMailInfo &other) const; + Q_REQUIRED_RESULT bool operator ==(const ArchiveMailInfo &other) const; private: QString dirArchive(bool &dirExit) const; diff --git a/agents/archivemailagent/archivemailinfo.cpp b/agents/archivemailagent/archivemailinfo.cpp --- a/agents/archivemailagent/archivemailinfo.cpp +++ b/agents/archivemailagent/archivemailinfo.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/archivemailagent/archivemailkernel.h b/agents/archivemailagent/archivemailkernel.h --- a/agents/archivemailagent/archivemailkernel.h +++ b/agents/archivemailagent/archivemailkernel.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -48,12 +48,12 @@ Akonadi::ChangeRecorder *folderCollectionMonitor() const override; void updateSystemTray() override; - qreal closeToQuotaThreshold() override; - bool excludeImportantMailFromExpiry() override; - QStringList customTemplates() override; - Akonadi::Collection::Id lastSelectedFolder() override; + Q_REQUIRED_RESULT qreal closeToQuotaThreshold() override; + Q_REQUIRED_RESULT bool excludeImportantMailFromExpiry() override; + Q_REQUIRED_RESULT QStringList customTemplates() override; + Q_REQUIRED_RESULT Akonadi::Collection::Id lastSelectedFolder() override; void setLastSelectedFolder(Akonadi::Collection::Id col) override; - bool showPopupAfterDnD() override; + Q_REQUIRED_RESULT bool showPopupAfterDnD() override; void expunge(Akonadi::Collection::Id col, bool sync) override; private: diff --git a/agents/archivemailagent/archivemailkernel.cpp b/agents/archivemailagent/archivemailkernel.cpp --- a/agents/archivemailagent/archivemailkernel.cpp +++ b/agents/archivemailagent/archivemailkernel.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/archivemailagent/archivemailmanager.h b/agents/archivemailagent/archivemailmanager.h --- a/agents/archivemailagent/archivemailmanager.h +++ b/agents/archivemailagent/archivemailmanager.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -39,10 +39,10 @@ void pause(); void resume(); - QString printArchiveListInfo(); + Q_REQUIRED_RESULT QString printArchiveListInfo() const; void collectionDoesntExist(ArchiveMailInfo *info); - QString printCurrentListInfo(); + Q_REQUIRED_RESULT QString printCurrentListInfo() const; void archiveFolder(const QString &path, Akonadi::Collection::Id collectionId); @@ -53,7 +53,6 @@ public Q_SLOTS: void load(); - void slotArchiveNow(ArchiveMailInfo *info); Q_SIGNALS: void needUpdateConfigDialogBox(); @@ -63,7 +62,7 @@ QString infoToStr(ArchiveMailInfo *info) const; void removeCollectionId(Akonadi::Collection::Id id); KSharedConfig::Ptr mConfig; - QList mListArchiveInfo; + QVector mListArchiveInfo; ArchiveMailKernel *mArchiveMailKernel = nullptr; }; diff --git a/agents/archivemailagent/archivemailmanager.cpp b/agents/archivemailagent/archivemailmanager.cpp --- a/agents/archivemailagent/archivemailmanager.cpp +++ b/agents/archivemailagent/archivemailmanager.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -49,17 +49,6 @@ qDeleteAll(mListArchiveInfo); } -void ArchiveMailManager::slotArchiveNow(ArchiveMailInfo *info) -{ - if (!info) { - return; - } - ArchiveMailInfo *stockInfo = new ArchiveMailInfo(*info); - mListArchiveInfo.append(stockInfo); - ScheduledArchiveTask *task = new ScheduledArchiveTask(this, stockInfo, Akonadi::Collection(stockInfo->saveCollectionId()), true /*immediat*/); - mArchiveMailKernel->jobScheduler()->registerTask(task); -} - void ArchiveMailManager::load() { qDeleteAll(mListArchiveInfo); @@ -132,7 +121,7 @@ if (lst.count() > info->maximumArchiveCount()) { const int diff = (lst.count() - info->maximumArchiveCount()); for (int i = 0; i < diff; ++i) { - const QString fileToRemove(info->url().path() + QDir::separator() + lst.at(i)); + const QString fileToRemove(info->url().path() + QLatin1Char('/') + lst.at(i)); qCDebug(ARCHIVEMAILAGENT_LOG) << " file to remove " << fileToRemove; QFile::remove(fileToRemove); } @@ -161,7 +150,7 @@ mArchiveMailKernel->jobScheduler()->resume(); } -QString ArchiveMailManager::printCurrentListInfo() +QString ArchiveMailManager::printCurrentListInfo() const { QString infoStr; if (mListArchiveInfo.isEmpty()) { @@ -188,7 +177,7 @@ return infoStr; } -QString ArchiveMailManager::printArchiveListInfo() +QString ArchiveMailManager::printArchiveListInfo() const { QString infoStr; const QStringList collectionList = mConfig->groupList().filter(QRegularExpression(QStringLiteral("ArchiveMailCollection \\d+"))); @@ -209,6 +198,7 @@ ArchiveMailInfo *info = new ArchiveMailInfo; info->setSaveCollectionId(collectionId); info->setUrl(QUrl::fromLocalFile(path)); - slotArchiveNow(info); - delete info; + mListArchiveInfo.append(info); + ScheduledArchiveTask *task = new ScheduledArchiveTask(this, info, Akonadi::Collection(info->saveCollectionId()), true /*immediat*/); + mArchiveMailKernel->jobScheduler()->registerTask(task); } diff --git a/agents/archivemailagent/archivemailwidget.h b/agents/archivemailagent/archivemailwidget.h --- a/agents/archivemailagent/archivemailwidget.h +++ b/agents/archivemailagent/archivemailwidget.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -53,17 +53,14 @@ StorageDirectory }; - bool save() const override; + Q_REQUIRED_RESULT bool save() const override; void load() override; void needReloadConfig(); QSize restoreDialogSize() const override; void saveDialogSize(const QSize &size) override; -Q_SIGNALS: - void archiveNow(ArchiveMailInfo *info); - private: void createOrUpdateItem(ArchiveMailInfo *info, ArchiveMailItem *item = nullptr); bool verifyExistingArchive(ArchiveMailInfo *info) const; @@ -75,7 +72,6 @@ void updateButtons(); void slotOpenFolder(); void slotCustomContextMenuRequested(const QPoint &); - void slotArchiveNow(); void slotItemChanged(QTreeWidgetItem *item, int); bool mChanged = false; diff --git a/agents/archivemailagent/archivemailwidget.cpp b/agents/archivemailagent/archivemailwidget.cpp --- a/agents/archivemailagent/archivemailwidget.cpp +++ b/agents/archivemailagent/archivemailwidget.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -20,10 +20,12 @@ #include "archivemailwidget.h" #include "addarchivemaildialog.h" #include "archivemailagentutil.h" +#include "archivemailkernel.h" #include "kmail-version.h" #include +#include #include #include @@ -67,6 +69,10 @@ : Akonadi::AgentConfigurationBase(config, parent, args) , mChanged(false) { + ArchiveMailKernel *archiveMailKernel = new ArchiveMailKernel(this); + CommonKernel->registerKernelIf(archiveMailKernel); //register KernelIf early, it is used by the Filter classes + CommonKernel->registerSettingsIf(archiveMailKernel); //SettingsIf is used in FolderTreeWidget + QWidget *w = new QWidget(parent); mWidget.setupUi(w); parent->layout()->addWidget(w); @@ -97,7 +103,7 @@ QStringLiteral(KDEPIM_VERSION), i18n("Archive emails automatically."), KAboutLicense::GPL_V2, - i18n("Copyright (C) 2014-2019 Laurent Montel")); + i18n("Copyright (C) 2014-2020 Laurent Montel")); aboutData.addAuthor(i18n("Laurent Montel"), i18n("Maintainer"), QStringLiteral("montel@kde.org")); @@ -118,8 +124,6 @@ if (!listItems.isEmpty()) { if (listItems.count() == 1) { menu.addAction(i18n("Open Containing Folder..."), this, &ArchiveMailWidget::slotOpenFolder); - menu.addSeparator(); - menu.addAction(i18n("Archive now"), this, &ArchiveMailWidget::slotArchiveNow); } menu.addSeparator(); menu.addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete"), this, &ArchiveMailWidget::slotRemoveItem); @@ -157,8 +161,8 @@ const QStringList collectionList = config()->groupList().filter(QRegularExpression(archiveMailCollectionPattern())); const int numberOfCollection = collectionList.count(); for (int i = 0; i < numberOfCollection; ++i) { - KConfigGroup group = config()->group(collectionList.at(i)); - ArchiveMailInfo *info = new ArchiveMailInfo(group); + KConfigGroup collectionGroup = config()->group(collectionList.at(i)); + ArchiveMailInfo *info = new ArchiveMailInfo(collectionGroup); if (info->isValid()) { createOrUpdateItem(info); } else { @@ -311,23 +315,6 @@ } } -void ArchiveMailWidget::slotArchiveNow() -{ - const QList listItems = mWidget.treeWidget->selectedItems(); - if (listItems.count() == 1) { - QTreeWidgetItem *item = listItems.first(); - if (!item) { - return; - } - ArchiveMailItem *archiveItem = static_cast(item); - ArchiveMailInfo *archiveItemInfo = archiveItem->info(); - save(); - if (archiveItemInfo) { - Q_EMIT archiveNow(archiveItemInfo); - } - } -} - void ArchiveMailWidget::slotItemChanged(QTreeWidgetItem *item, int col) { if (item) { diff --git a/agents/archivemailagent/autotests/CMakeLists.txt b/agents/archivemailagent/autotests/CMakeLists.txt --- a/agents/archivemailagent/autotests/CMakeLists.txt +++ b/agents/archivemailagent/autotests/CMakeLists.txt @@ -1,10 +1,12 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../.. ) +ecm_qt_declare_logging_category(autotest_categories_SRCS HEADER archivemailagent_debug.h IDENTIFIER ARCHIVEMAILAGENT_LOG CATEGORY_NAME org.kde.pim.archivemailagent) + + # Convenience macro to add unit tests. macro( archivemail_agent _source) - set( _test ${_source} ../archivemailwidget.cpp ../addarchivemaildialog.cpp ../widgets/formatcombobox.cpp ../widgets/unitcombobox.cpp) + set( _test ${_source} ../archivemailwidget.cpp ../addarchivemaildialog.cpp ../widgets/formatcombobox.cpp ../widgets/unitcombobox.cpp ${autotest_categories_SRCS}) ki18n_wrap_ui(_test ../ui/archivemailwidget.ui ) - ecm_qt_declare_logging_category(_test HEADER archivemailagent_debug.h IDENTIFIER ARCHIVEMAILAGENT_LOG CATEGORY_NAME org.kde.pim.archivemailagent) get_filename_component( _name ${_source} NAME_WE ) add_executable( ${_name} ${_test} ) add_test(NAME ${_name} COMMAND ${_name} ) diff --git a/agents/archivemailagent/autotests/archivemailinfotest.h b/agents/archivemailagent/autotests/archivemailinfotest.h --- a/agents/archivemailagent/autotests/archivemailinfotest.h +++ b/agents/archivemailagent/autotests/archivemailinfotest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/archivemailagent/autotests/archivemailinfotest.cpp b/agents/archivemailagent/autotests/archivemailinfotest.cpp --- a/agents/archivemailagent/autotests/archivemailinfotest.cpp +++ b/agents/archivemailagent/autotests/archivemailinfotest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/archivemailagent/autotests/archivemailwidgettest.h b/agents/archivemailagent/autotests/archivemailwidgettest.h --- a/agents/archivemailagent/autotests/archivemailwidgettest.h +++ b/agents/archivemailagent/autotests/archivemailwidgettest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/archivemailagent/autotests/archivemailwidgettest.cpp b/agents/archivemailagent/autotests/archivemailwidgettest.cpp --- a/agents/archivemailagent/autotests/archivemailwidgettest.cpp +++ b/agents/archivemailagent/autotests/archivemailwidgettest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/archivemailagent/autotests/formatcomboboxtest.h b/agents/archivemailagent/autotests/formatcomboboxtest.h --- a/agents/archivemailagent/autotests/formatcomboboxtest.h +++ b/agents/archivemailagent/autotests/formatcomboboxtest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/archivemailagent/autotests/formatcomboboxtest.cpp b/agents/archivemailagent/autotests/formatcomboboxtest.cpp --- a/agents/archivemailagent/autotests/formatcomboboxtest.cpp +++ b/agents/archivemailagent/autotests/formatcomboboxtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/archivemailagent/autotests/unitcomboboxtest.h b/agents/archivemailagent/autotests/unitcomboboxtest.h --- a/agents/archivemailagent/autotests/unitcomboboxtest.h +++ b/agents/archivemailagent/autotests/unitcomboboxtest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/archivemailagent/autotests/unitcomboboxtest.cpp b/agents/archivemailagent/autotests/unitcomboboxtest.cpp --- a/agents/archivemailagent/autotests/unitcomboboxtest.cpp +++ b/agents/archivemailagent/autotests/unitcomboboxtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/archivemailagent/job/archivejob.h b/agents/archivemailagent/job/archivejob.h --- a/agents/archivemailagent/job/archivejob.h +++ b/agents/archivemailagent/job/archivejob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -22,7 +22,6 @@ #include #include -#include class ArchiveMailInfo; class ArchiveMailManager; diff --git a/agents/archivemailagent/job/archivejob.cpp b/agents/archivemailagent/job/archivejob.cpp --- a/agents/archivemailagent/job/archivejob.cpp +++ b/agents/archivemailagent/job/archivejob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -30,8 +30,6 @@ #include #include -#include -#include ArchiveJob::ArchiveJob(ArchiveMailManager *manager, ArchiveMailInfo *info, const Akonadi::Collection &folder, bool immediate) : MailCommon::ScheduledJob(folder, immediate) diff --git a/agents/archivemailagent/widgets/formatcombobox.h b/agents/archivemailagent/widgets/formatcombobox.h --- a/agents/archivemailagent/widgets/formatcombobox.h +++ b/agents/archivemailagent/widgets/formatcombobox.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -19,7 +19,7 @@ #ifndef FORMATCOMBOBOX_H #define FORMATCOMBOBOX_H -#include "MailCommon/BackupJob" +#include #include diff --git a/agents/archivemailagent/widgets/formatcombobox.cpp b/agents/archivemailagent/widgets/formatcombobox.cpp --- a/agents/archivemailagent/widgets/formatcombobox.cpp +++ b/agents/archivemailagent/widgets/formatcombobox.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/archivemailagent/widgets/unitcombobox.h b/agents/archivemailagent/widgets/unitcombobox.h --- a/agents/archivemailagent/widgets/unitcombobox.h +++ b/agents/archivemailagent/widgets/unitcombobox.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/archivemailagent/widgets/unitcombobox.cpp b/agents/archivemailagent/widgets/unitcombobox.cpp --- a/agents/archivemailagent/widgets/unitcombobox.cpp +++ b/agents/archivemailagent/widgets/unitcombobox.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/followupreminderagent/CMakeLists.txt b/agents/followupreminderagent/CMakeLists.txt --- a/agents/followupreminderagent/CMakeLists.txt +++ b/agents/followupreminderagent/CMakeLists.txt @@ -13,9 +13,18 @@ ${followupreminderagent_job_SRCS} ) -ecm_qt_declare_logging_category(followupreminderagent_SRCS HEADER followupreminderagent_debug.h IDENTIFIER FOLLOWUPREMINDERAGENT_LOG CATEGORY_NAME org.kde.pim.followupreminderagent) +ecm_qt_declare_logging_category(followupreminderagent_SRCS HEADER followupreminderagent_debug.h IDENTIFIER FOLLOWUPREMINDERAGENT_LOG CATEGORY_NAME org.kde.pim.followupreminderagent + DESCRIPTION "kmail (followupreminderagent)" + OLD_CATEGORY_NAMES log_followupreminderagent + EXPORT KMAIL + ) + qt5_add_dbus_adaptor(followupreminderagent_SRCS org.freedesktop.Akonadi.FollowUpReminder.xml followupreminderagent.h FollowUpReminderAgent) +qt5_add_dbus_interface(followupreminderagent_SRCS org.freedesktop.Notifications.xml notifications_interface) +qt5_add_dbus_interface(followupreminderagent_SRCS org.freedesktop.DBus.Properties.xml dbusproperties) + + add_library(followupreminderagent STATIC ${followupreminderagent_SRCS}) target_link_libraries(followupreminderagent KF5::AkonadiCore @@ -28,7 +37,6 @@ KF5::Notifications KF5::MailCommon KF5::Libkdepim - KF5::IconThemes KF5::I18n KF5::CalendarCore ) @@ -52,7 +60,6 @@ Qt5::Widgets KF5::Notifications KF5::I18n - KF5::IconThemes KF5::XmlGui KF5::Service ) diff --git a/agents/followupreminderagent/akonadi_followupreminder_agent.notifyrc b/agents/followupreminderagent/akonadi_followupreminder_agent.notifyrc --- a/agents/followupreminderagent/akonadi_followupreminder_agent.notifyrc +++ b/agents/followupreminderagent/akonadi_followupreminder_agent.notifyrc @@ -11,6 +11,7 @@ Comment[en_GB]=Followup reminder agent Comment[es]=Seguimiento de agente de recordatorio Comment[et]=Vastamise meeldetuletuse agent +Comment[eu]=Jarraipen ohartarazpenen agentea Comment[fi]=Vastaamisen seurannasta muistuttaja Comment[fr]=Agent de rappel des messages suivis Comment[gl]=Axente de lembranzas de seguimento @@ -22,7 +23,7 @@ Comment[nb]=Agent for påminnelse om oppfølging Comment[nds]=Antwoortnaricht-Anstoothölper Comment[nl]=Agent voor herinneren aan vervolgactie -Comment[pl]=Usługa ponaglającego przypominania +Comment[pl]=Usługa przypominania Comment[pt]=Agente de recordação de seguimentos Comment[pt_BR]=Agente para acompanhar os lembretes Comment[ru]=Агент напоминания о продолжении @@ -49,6 +50,7 @@ Name[en_GB]=Mail Follow Up Received Name[es]=Recibido seguimiento de correo Name[et]=Saadi vastuskiri +Name[eu]=Jarraipen posta jaso da Name[fi]=Vastausposti vastaanotettu Name[fr]=Un message suivis a été reçu Name[gl]=Recibiuse un seguimento de correo diff --git a/agents/followupreminderagent/autotests/CMakeLists.txt b/agents/followupreminderagent/autotests/CMakeLists.txt --- a/agents/followupreminderagent/autotests/CMakeLists.txt +++ b/agents/followupreminderagent/autotests/CMakeLists.txt @@ -1,8 +1,13 @@ +set(followupreminderagent_test_SRCS) +qt5_add_dbus_interface(followupreminderagent_test_SRCS ../org.freedesktop.Notifications.xml notifications_interface) +qt5_add_dbus_interface(followupreminderagent_test_SRCS ../org.freedesktop.DBus.Properties.xml dbusproperties) + +set(autotest_categories_followupreminderagent_SRCS) +ecm_qt_declare_logging_category(autotest_categories_followupreminderagent_SRCS HEADER followupreminderagent_debug.h IDENTIFIER FOLLOWUPREMINDERAGENT_LOG CATEGORY_NAME org.kde.pim.followupreminderagent) # Convenience macro to add unit tests. macro( followupreminder_agent _source ) - set( _test ${_source} ../followupreminderinfowidget.cpp ../jobs/followupremindershowmessagejob.cpp ../followupremindernoanswerdialog.cpp) - ecm_qt_declare_logging_category(_test HEADER followupreminderagent_debug.h IDENTIFIER FOLLOWUPREMINDERAGENT_LOG CATEGORY_NAME org.kde.pim.followupreminderagent) + set( _test ${_source} ../followupreminderinfowidget.cpp ../jobs/followupremindershowmessagejob.cpp ../followupremindernoanswerdialog.cpp ${followupreminderagent_test_SRCS} ${autotest_categories_followupreminderagent_SRCS}) get_filename_component( _name ${_source} NAME_WE ) ecm_add_test(${_test} TEST_NAME ${_name} diff --git a/agents/followupreminderagent/autotests/followupreminderconfigtest.h b/agents/followupreminderagent/autotests/followupreminderconfigtest.h --- a/agents/followupreminderagent/autotests/followupreminderconfigtest.h +++ b/agents/followupreminderagent/autotests/followupreminderconfigtest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/followupreminderagent/autotests/followupreminderconfigtest.cpp b/agents/followupreminderagent/autotests/followupreminderconfigtest.cpp --- a/agents/followupreminderagent/autotests/followupreminderconfigtest.cpp +++ b/agents/followupreminderagent/autotests/followupreminderconfigtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -18,8 +18,8 @@ */ #include "followupreminderconfigtest.h" -#include "FollowupReminder/FollowUpReminderUtil" -#include "FollowupReminder/FollowUpReminderInfo" +#include +#include #include #include #include diff --git a/agents/followupreminderagent/autotests/followupreminderinfotest.h b/agents/followupreminderagent/autotests/followupreminderinfotest.h --- a/agents/followupreminderagent/autotests/followupreminderinfotest.h +++ b/agents/followupreminderagent/autotests/followupreminderinfotest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/followupreminderagent/autotests/followupreminderinfotest.cpp b/agents/followupreminderagent/autotests/followupreminderinfotest.cpp --- a/agents/followupreminderagent/autotests/followupreminderinfotest.cpp +++ b/agents/followupreminderagent/autotests/followupreminderinfotest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -18,7 +18,7 @@ */ #include "followupreminderinfotest.h" -#include "FollowupReminder/FollowUpReminderInfo" +#include #include #include #include diff --git a/agents/followupreminderagent/autotests/followupremindernoanswerdialogtest.h b/agents/followupreminderagent/autotests/followupremindernoanswerdialogtest.h --- a/agents/followupreminderagent/autotests/followupremindernoanswerdialogtest.h +++ b/agents/followupreminderagent/autotests/followupremindernoanswerdialogtest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/followupreminderagent/autotests/followupremindernoanswerdialogtest.cpp b/agents/followupreminderagent/autotests/followupremindernoanswerdialogtest.cpp --- a/agents/followupreminderagent/autotests/followupremindernoanswerdialogtest.cpp +++ b/agents/followupreminderagent/autotests/followupremindernoanswerdialogtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -20,7 +20,7 @@ #include "followupremindernoanswerdialogtest.h" #include "../followupremindernoanswerdialog.h" #include "../followupreminderinfowidget.h" -#include "FollowupReminder/FollowUpReminderInfo" +#include #include #include #include diff --git a/agents/followupreminderagent/followupreminder.desktop b/agents/followupreminderagent/followupreminder.desktop --- a/agents/followupreminderagent/followupreminder.desktop +++ b/agents/followupreminderagent/followupreminder.desktop @@ -10,6 +10,7 @@ Name[en_GB]=Followup Reminder Agent Name[es]=Seguimiento de agente de recordatorio Name[et]=Vastamise meeldetuletuse agent +Name[eu]=Jarraipen ohartarazpenen agentea Name[fi]=Vastaamisen seurannasta muistuttaja Name[fr]=Agent de rappel des messages suivis Name[gl]=Axente de lembranzas de seguimento @@ -21,7 +22,7 @@ Name[nb]=Agent for påminnelse om oppfølging Name[nds]=Antwoortnaricht-Anstoothölper Name[nl]=Agent voor herinneren aan vervolgactie -Name[pl]=Usługa ponaglającego przypominania +Name[pl]=Usługa przypominania Name[pt]=Agente de Recordação de Seguimentos Name[pt_BR]=Agente de Lembretes de Acompanhamento Name[ru]=Агент напоминания о продолжении @@ -48,6 +49,7 @@ Comment[en_GB]=Followup Reminder Agent allows to remind you when an email was not answered. Comment[es]=El seguimiento de agente de recordatorio le permite recordar cuando no se ha respondido a un correo. Comment[et]=Vastamise meeldetuletuse agent laseb meelde tuletada, kui sa pole kirjale vastust saanud. +Comment[eu]=Jarraipen ohartarazpenen agenteak e-posta bat erantzun gabe dagoela gogoratzen laguntzen dizu. Comment[fi]=Vastaamisen seurannasta muistuttaja voi muistuttaa sinua, kun sähköpostiin ei ole vastattu. Comment[fr]=L'agent de rappel des messages suivis permet de se rappeler lorsqu'il n'y a pas eu de réponse à un courriel. Comment[gl]=O Axente de lembranzas de seguimento permite lembrarlle cando non se respondeu a unha mensaxe de correo. @@ -60,7 +62,7 @@ Comment[nds]=De Antwoortnaricht-Anstoothölper stööt Di an, wenn Du op en Nettbreef noch nich antert hest. Comment[nl]=Agent voor herinneren aan vervolgactie stelt u in staat om u te herinneren aan een nog niet beantwoord e-mailbericht. Comment[nn]=Agenten for oppfølgingspåminning kan minna deg på å svara. -Comment[pl]=Usługa ponaglającego przypominania przypomina ci gdy nie odpowiedziano na wiadomość. +Comment[pl]=Usługa przypominania przypomina ci gdy nie odpowiedziano na wiadomość. Comment[pt]=O Agente de Recordação de Seguimentos permite-lhe lembrar que um dado e-mail não foi respondido. Comment[pt_BR]=O Agende de Lembretes de Acompanhamento permite lembrar-lhe quando um e-mail não foi respondido. Comment[ru]=Агент напоминания о продолжении будет напоминать вам о письмах, на которые вам не ответили. diff --git a/agents/followupreminderagent/followupreminderagent.h b/agents/followupreminderagent/followupreminderagent.h --- a/agents/followupreminderagent/followupreminderagent.h +++ b/agents/followupreminderagent/followupreminderagent.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -30,12 +30,13 @@ ~FollowUpReminderAgent() override; void setEnableAgent(bool b); - bool enabledAgent() const; + Q_REQUIRED_RESULT bool enabledAgent() const; - QString printDebugInfo(); + Q_REQUIRED_RESULT QString printDebugInfo() const; public Q_SLOTS: void reload(); + void addReminder(const QString &messageId, Akonadi::Item::Id messageItemId, const QString &to, const QString &subject, const QDate &followupDate, Akonadi::Item::Id todoId); protected: void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection) override; diff --git a/agents/followupreminderagent/followupreminderagent.cpp b/agents/followupreminderagent/followupreminderagent.cpp --- a/agents/followupreminderagent/followupreminderagent.cpp +++ b/agents/followupreminderagent/followupreminderagent.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -19,21 +19,22 @@ #include "followupreminderagent.h" #include "followupremindermanager.h" -#include "FollowupReminder/FollowUpReminderUtil" +#include #include "followupreminderadaptor.h" #include "followupreminderagentsettings.h" +#include + #include #include #include -#include +#include #include #include #include #include -#include #include "followupreminderagent_debug.h" #include @@ -45,9 +46,9 @@ migrate.migrate(); new FollowUpReminderAgentAdaptor(this); - KDBusConnectionPool::threadConnection().registerObject(QStringLiteral("/FollowUpReminder"), this, QDBusConnection::ExportAdaptors); + QDBusConnection::sessionBus().registerObject(QStringLiteral("/FollowUpReminder"), this, QDBusConnection::ExportAdaptors); const QString service = Akonadi::ServerManager::self()->agentServiceName(Akonadi::ServerManager::Agent, QStringLiteral("akonadi_followupreminder_agent")); - KDBusConnectionPool::threadConnection().registerService(service); + QDBusConnection::sessionBus().registerService(service); mManager = new FollowUpReminderManager(this); setNeedsNetwork(true); @@ -116,7 +117,20 @@ } } -QString FollowUpReminderAgent::printDebugInfo() +void FollowUpReminderAgent::addReminder(const QString &messageId, Akonadi::Item::Id messageItemId, const QString &to, const QString &subject, const QDate &followupDate, Akonadi::Item::Id todoId) +{ + auto info = new FollowUpReminder::FollowUpReminderInfo(); + info->setMessageId(messageId); + info->setOriginalMessageItemId(messageItemId); + info->setTo(to); + info->setSubject(subject); + info->setFollowUpReminderDate(followupDate); + info->setTodoId(todoId); + + mManager->addReminder(info); +} + +QString FollowUpReminderAgent::printDebugInfo() const { return mManager->printDebugInfo(); } diff --git a/agents/followupreminderagent/followupreminderinfoconfigwidget.h b/agents/followupreminderagent/followupreminderinfoconfigwidget.h --- a/agents/followupreminderagent/followupreminderinfoconfigwidget.h +++ b/agents/followupreminderagent/followupreminderinfoconfigwidget.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2018-2019 Montel Laurent + Copyright (C) 2018-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -21,8 +21,6 @@ #define FOLLOWUPREMINDERINFOCONFIGWIDGET_H #include -#include -#include #include #include #include diff --git a/agents/followupreminderagent/followupreminderinfoconfigwidget.cpp b/agents/followupreminderagent/followupreminderinfoconfigwidget.cpp --- a/agents/followupreminderagent/followupreminderinfoconfigwidget.cpp +++ b/agents/followupreminderagent/followupreminderinfoconfigwidget.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2018-2019 Montel Laurent + Copyright (C) 2018-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -19,15 +19,10 @@ #include "followupreminderinfoconfigwidget.h" #include "followupreminderinfowidget.h" #include "kmail-version.h" - -#include -#include +#include #include -#include -#include #include #include -#include namespace { static const char myConfigGroupName[] = "FollowUpReminderInfoDialog"; } @@ -44,7 +39,7 @@ QStringLiteral(KDEPIM_VERSION), i18n("Follow Up Reminder"), KAboutLicense::GPL_V2, - i18n("Copyright (C) 2014-2019 Laurent Montel")); + i18n("Copyright (C) 2014-2020 Laurent Montel")); aboutData.addAuthor(i18n("Laurent Montel"), i18n("Maintainer"), QStringLiteral("montel@kde.org")); diff --git a/agents/followupreminderagent/followupreminderinfowidget.h b/agents/followupreminderagent/followupreminderinfowidget.h --- a/agents/followupreminderagent/followupreminderinfowidget.h +++ b/agents/followupreminderagent/followupreminderinfowidget.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -23,7 +23,6 @@ #include #include #include -#include #include class QTreeWidget; namespace FollowUpReminder { @@ -58,7 +57,7 @@ bool save() const; void load(); - QList listRemoveId() const; + Q_REQUIRED_RESULT QList listRemoveId() const; private: void slotCustomContextMenuRequested(const QPoint &pos); diff --git a/agents/followupreminderagent/followupreminderinfowidget.cpp b/agents/followupreminderagent/followupreminderinfowidget.cpp --- a/agents/followupreminderagent/followupreminderinfowidget.cpp +++ b/agents/followupreminderagent/followupreminderinfowidget.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,15 +17,14 @@ Boston, MA 02110-1301, USA. */ #include "followupreminderinfowidget.h" -#include "FollowupReminder/FollowUpReminderInfo" -#include "FollowupReminder/FollowUpReminderUtil" +#include +#include #include "jobs/followupremindershowmessagejob.h" #include "followupreminderagent_debug.h" #include #include #include -#include #include #include #include diff --git a/agents/followupreminderagent/followupremindermanager.h b/agents/followupreminderagent/followupremindermanager.h --- a/agents/followupreminderagent/followupremindermanager.h +++ b/agents/followupreminderagent/followupremindermanager.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -36,18 +36,19 @@ ~FollowUpReminderManager(); void load(bool forceReloadConfig = false); + void addReminder(FollowUpReminder::FollowUpReminderInfo *reminder); // takes ownership void checkFollowUp(const Akonadi::Item &item, const Akonadi::Collection &col); - QString printDebugInfo(); + Q_REQUIRED_RESULT QString printDebugInfo() const; private: Q_DISABLE_COPY(FollowUpReminderManager) void slotCheckFollowUpFinished(const QString &messageId, Akonadi::Item::Id id); void slotFinishTaskDone(); void slotFinishTaskFailed(); void slotReparseConfiguration(); void answerReceived(const QString &from); - QString infoToStr(FollowUpReminder::FollowUpReminderInfo *info); + Q_REQUIRED_RESULT QString infoToStr(FollowUpReminder::FollowUpReminderInfo *info) const; KSharedConfig::Ptr mConfig; QList mFollowUpReminderInfoList; diff --git a/agents/followupreminderagent/followupremindermanager.cpp b/agents/followupreminderagent/followupremindermanager.cpp --- a/agents/followupreminderagent/followupremindermanager.cpp +++ b/agents/followupreminderagent/followupremindermanager.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -19,21 +19,18 @@ #include "followupremindermanager.h" #include "followupreminderagent_debug.h" -#include "FollowupReminder/FollowUpReminderInfo" -#include "FollowupReminder/FollowUpReminderUtil" +#include +#include #include "followupremindernoanswerdialog.h" #include "jobs/followupreminderjob.h" #include "jobs/followupreminderfinishtaskjob.h" #include -#include - #include #include #include -#include +#include #include -#include #include using namespace FollowUpReminder; @@ -84,7 +81,16 @@ connect(mNoAnswerDialog.data(), &FollowUpReminderNoAnswerDialog::needToReparseConfiguration, this, &FollowUpReminderManager::slotReparseConfiguration); } mNoAnswerDialog->setInfo(noAnswerList); - mNoAnswerDialog->show(); + mNoAnswerDialog->wakeUp(); + } +} + +void FollowUpReminderManager::addReminder(FollowUpReminder::FollowUpReminderInfo *info) +{ + if (info->isValid()) { + FollowUpReminderUtil::writeFollowupReminderInfo(FollowUpReminderUtil::defaultConfig(), info, true); + } else { + delete info; } } @@ -164,7 +170,7 @@ QStringLiteral("akonadi_followupreminder_agent")); } -QString FollowUpReminderManager::printDebugInfo() +QString FollowUpReminderManager::printDebugInfo() const { QString infoStr; if (mFollowUpReminderInfoList.isEmpty()) { @@ -180,7 +186,7 @@ return infoStr; } -QString FollowUpReminderManager::infoToStr(FollowUpReminder::FollowUpReminderInfo *info) +QString FollowUpReminderManager::infoToStr(FollowUpReminder::FollowUpReminderInfo *info) const { QString infoStr = QStringLiteral("****************************************"); infoStr += QStringLiteral("Akonadi Item id :%1\n").arg(info->originalMessageItemId()); diff --git a/agents/followupreminderagent/followupremindernoanswerdialog.h b/agents/followupreminderagent/followupremindernoanswerdialog.h --- a/agents/followupreminderagent/followupremindernoanswerdialog.h +++ b/agents/followupreminderagent/followupremindernoanswerdialog.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -34,10 +34,12 @@ void setInfo(const QList &info); + void wakeUp(); Q_SIGNALS: void needToReparseConfiguration(); private: + void slotDBusNotificationsPropertiesChanged(const QString &interface, const QVariantMap &changedProperties, const QStringList &invalidatedProperties); void slotSave(); void readConfig(); void writeConfig(); diff --git a/agents/followupreminderagent/followupremindernoanswerdialog.cpp b/agents/followupreminderagent/followupremindernoanswerdialog.cpp --- a/agents/followupreminderagent/followupremindernoanswerdialog.cpp +++ b/agents/followupreminderagent/followupremindernoanswerdialog.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -18,8 +18,10 @@ */ #include "followupremindernoanswerdialog.h" -#include "FollowupReminder/FollowUpReminderInfo" #include "followupreminderinfowidget.h" +#include "followupreminderagent_debug.h" + +#include #include #include @@ -30,10 +32,19 @@ #include #include +#include "notifications_interface.h" // DBUS-generated +#include "dbusproperties.h" // DBUS-generated + +namespace { +static constexpr const char s_fdo_notifications_service[] = "org.freedesktop.Notifications"; +static constexpr const char s_fdo_notifications_path[] = "/org/freedesktop/Notifications"; +static constexpr const char DialogGroup[] = "FollowUpReminderNoAnswerDialog"; +} + FollowUpReminderNoAnswerDialog::FollowUpReminderNoAnswerDialog(QWidget *parent) : QDialog(parent) { - setWindowTitle(i18n("Follow Up Reminder")); + setWindowTitle(i18nc("@title:window", "Follow Up Reminder")); setWindowIcon(QIcon::fromTheme(QStringLiteral("kmail"))); setAttribute(Qt::WA_DeleteOnClose); @@ -55,21 +66,62 @@ mainLayout->addWidget(buttonBox); readConfig(); + QDBusConnection dbusConn = QDBusConnection::sessionBus(); + if (dbusConn.interface()->isServiceRegistered(QString::fromLatin1(s_fdo_notifications_service))) { + OrgFreedesktopDBusPropertiesInterface *propsIface = new OrgFreedesktopDBusPropertiesInterface( + QString::fromLatin1(s_fdo_notifications_service), + QString::fromLatin1(s_fdo_notifications_path), + dbusConn, this); + connect(propsIface, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged, + this, &FollowUpReminderNoAnswerDialog::slotDBusNotificationsPropertiesChanged); + } } FollowUpReminderNoAnswerDialog::~FollowUpReminderNoAnswerDialog() { writeConfig(); } +void FollowUpReminderNoAnswerDialog::wakeUp() +{ + // Check if notifications are inhibited (e.x. plasma "do not disturb" mode. + // In that case, we'll wait until they are allowed again (see slotDBusNotificationsPropertiesChanged) + QDBusConnection dbusConn = QDBusConnection::sessionBus(); + if (dbusConn.interface()->isServiceRegistered(QString::fromLatin1(s_fdo_notifications_service))) { + OrgFreedesktopNotificationsInterface iface( + QString::fromLatin1(s_fdo_notifications_service), + QString::fromLatin1(s_fdo_notifications_path), + dbusConn); + if (iface.inhibited()) { + return; + } + } + show(); +} + +void FollowUpReminderNoAnswerDialog::slotDBusNotificationsPropertiesChanged( + const QString &interface, const QVariantMap &changedProperties, const QStringList &invalidatedProperties) +{ + Q_UNUSED(interface); // always "org.freedesktop.Notifications" + Q_UNUSED(invalidatedProperties); + const auto it = changedProperties.find(QStringLiteral("Inhibited")); + if (it != changedProperties.end()) { + const bool inhibited = it.value().toBool(); + qCDebug(FOLLOWUPREMINDERAGENT_LOG) << "Notifications inhibited:" << inhibited; + if (!inhibited) { + wakeUp(); + } + } +} + void FollowUpReminderNoAnswerDialog::setInfo(const QList &info) { mWidget->setInfo(info); } void FollowUpReminderNoAnswerDialog::readConfig() { - KConfigGroup group(KSharedConfig::openConfig(), "FollowUpReminderNoAnswerDialog"); + KConfigGroup group(KSharedConfig::openConfig(), DialogGroup); const QSize sizeDialog = group.readEntry("Size", QSize(800, 600)); if (sizeDialog.isValid()) { resize(sizeDialog); @@ -79,7 +131,7 @@ void FollowUpReminderNoAnswerDialog::writeConfig() { - KConfigGroup group(KSharedConfig::openConfig(), "FollowUpReminderNoAnswerDialog"); + KConfigGroup group(KSharedConfig::openConfig(), DialogGroup); group.writeEntry("Size", size()); mWidget->saveTreeWidgetHeader(group); } diff --git a/agents/followupreminderagent/jobs/followupreminderfinishtaskjob.h b/agents/followupreminderagent/jobs/followupreminderfinishtaskjob.h --- a/agents/followupreminderagent/jobs/followupreminderfinishtaskjob.h +++ b/agents/followupreminderagent/jobs/followupreminderfinishtaskjob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/followupreminderagent/jobs/followupreminderfinishtaskjob.cpp b/agents/followupreminderagent/jobs/followupreminderfinishtaskjob.cpp --- a/agents/followupreminderagent/jobs/followupreminderfinishtaskjob.cpp +++ b/agents/followupreminderagent/jobs/followupreminderfinishtaskjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -18,12 +18,12 @@ */ #include "followupreminderfinishtaskjob.h" -#include "FollowupReminder/FollowUpReminderInfo" +#include #include #include #include #include "followupreminderagent_debug.h" -#include +#include FollowUpReminderFinishTaskJob::FollowUpReminderFinishTaskJob(Akonadi::Item::Id id, QObject *parent) : QObject(parent) @@ -65,16 +65,16 @@ const Akonadi::Item::List lst = qobject_cast(job)->items(); if (lst.count() == 1) { const Akonadi::Item item = lst.first(); - if (!item.hasPayload()) { + if (!item.hasPayload()) { qCDebug(FOLLOWUPREMINDERAGENT_LOG) << "FollowUpReminderFinishTaskJob::slotItemFetchJobDone: item is not a todo."; Q_EMIT finishTaskFailed(); deleteLater(); return; } - KCalCore::Todo::Ptr todo = item.payload(); + KCalendarCore::Todo::Ptr todo = item.payload(); todo->setCompleted(true); Akonadi::Item updateItem = item; - updateItem.setPayload(todo); + updateItem.setPayload(todo); Akonadi::ItemModifyJob *job = new Akonadi::ItemModifyJob(updateItem); connect(job, &Akonadi::ItemModifyJob::result, this, &FollowUpReminderFinishTaskJob::slotItemModifiedResult); diff --git a/agents/followupreminderagent/jobs/followupreminderjob.h b/agents/followupreminderagent/jobs/followupreminderjob.h --- a/agents/followupreminderagent/jobs/followupreminderjob.h +++ b/agents/followupreminderagent/jobs/followupreminderjob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/followupreminderagent/jobs/followupreminderjob.cpp b/agents/followupreminderagent/jobs/followupreminderjob.cpp --- a/agents/followupreminderagent/jobs/followupreminderjob.cpp +++ b/agents/followupreminderagent/jobs/followupreminderjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/followupreminderagent/jobs/followupremindershowmessagejob.h b/agents/followupreminderagent/jobs/followupremindershowmessagejob.h --- a/agents/followupreminderagent/jobs/followupremindershowmessagejob.h +++ b/agents/followupreminderagent/jobs/followupremindershowmessagejob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/followupreminderagent/jobs/followupremindershowmessagejob.cpp b/agents/followupreminderagent/jobs/followupremindershowmessagejob.cpp --- a/agents/followupreminderagent/jobs/followupremindershowmessagejob.cpp +++ b/agents/followupreminderagent/jobs/followupremindershowmessagejob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -22,7 +22,7 @@ #include #include #include -#include +#include FollowUpReminderShowMessageJob::FollowUpReminderShowMessageJob(Akonadi::Item::Id id, QObject *parent) : QObject(parent) diff --git a/agents/followupreminderagent/org.freedesktop.Akonadi.FollowUpReminder.xml b/agents/followupreminderagent/org.freedesktop.Akonadi.FollowUpReminder.xml --- a/agents/followupreminderagent/org.freedesktop.Akonadi.FollowUpReminder.xml +++ b/agents/followupreminderagent/org.freedesktop.Akonadi.FollowUpReminder.xml @@ -11,5 +11,14 @@ + + + + + + + + + diff --git a/agents/followupreminderagent/org.freedesktop.DBus.Properties.xml b/agents/followupreminderagent/org.freedesktop.DBus.Properties.xml new file mode 100644 --- /dev/null +++ b/agents/followupreminderagent/org.freedesktop.DBus.Properties.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/agents/followupreminderagent/org.freedesktop.Notifications.xml b/agents/followupreminderagent/org.freedesktop.Notifications.xml new file mode 100644 --- /dev/null +++ b/agents/followupreminderagent/org.freedesktop.Notifications.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/agents/mailfilteragent/CMakeLists.txt b/agents/mailfilteragent/CMakeLists.txt --- a/agents/mailfilteragent/CMakeLists.txt +++ b/agents/mailfilteragent/CMakeLists.txt @@ -8,13 +8,17 @@ filterlogdialog.cpp filtermanager.cpp mailfilteragent.cpp - config/configurewidget.cpp mailfilterpurposemenuwidget.cpp ) qt5_add_dbus_adaptor(akonadi_mailfilter_agent_SRCS org.freedesktop.Akonadi.MailFilterAgent.xml mailfilteragent.h MailFilterAgent) -ecm_qt_declare_logging_category(akonadi_mailfilter_agent_SRCS HEADER mailfilteragent_debug.h IDENTIFIER MAILFILTERAGENT_LOG CATEGORY_NAME org.kde.pim.mailfilteragent) +ecm_qt_declare_logging_category(akonadi_mailfilter_agent_SRCS HEADER mailfilteragent_debug.h IDENTIFIER MAILFILTERAGENT_LOG CATEGORY_NAME org.kde.pim.mailfilteragent + DESCRIPTION "kmail (mailfilter agent)" + OLD_CATEGORY_NAMES log_mailfilteragent + EXPORT KMAIL + ) + add_executable(akonadi_mailfilter_agent ${akonadi_mailfilter_agent_SRCS}) @@ -37,16 +41,11 @@ KF5::DBusAddons KF5::Notifications KF5::WindowSystem - KF5::IconThemes KF5::Libkdepim KF5::I18n ) install(TARGETS akonadi_mailfilter_agent ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES mailfilteragent.desktop DESTINATION "${KDE_INSTALL_DATAROOTDIR}/akonadi/agents") install(FILES akonadi_mailfilter_agent.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFY5RCDIR} ) -if(BUILD_TESTING) - add_subdirectory(autotests) -endif() - diff --git a/agents/mailfilteragent/akonadi_mailfilter_agent.notifyrc b/agents/mailfilteragent/akonadi_mailfilter_agent.notifyrc --- a/agents/mailfilteragent/akonadi_mailfilter_agent.notifyrc +++ b/agents/mailfilteragent/akonadi_mailfilter_agent.notifyrc @@ -12,6 +12,7 @@ Comment[en_GB]=Mail Filter Agent Comment[es]=Agente de filtro de correo Comment[et]=Kirjade filtreerimise agent +Comment[eu]=Posta iragazteko agentea Comment[fi]=Sähköpostisuodatin Comment[fr]=Agent de filtrage de messages Comment[gl]=Axente de filtrado do correo @@ -56,6 +57,7 @@ Name[en_GB]=Mail Filter Agent Name[es]=Agente de filtro de correo Name[et]=Kirjade filtreerimise agent +Name[eu]=Posta iragazteko agentea Name[fi]=Sähköpostisuodatin Name[fr]=Agent de filtrage de messages Name[gl]=Axente de filtrado de correo @@ -102,6 +104,7 @@ Name[en_GB]=Mail filter log enabled Name[es]=Registro de filtro de correo activado Name[et]=Kirjade filtreerimise logi on lubatud +Name[eu]=Posta iragazte egunkaria gaituta dago Name[fi]=Sähköpostisuodatinloki käytössä Name[fr]=Journal de l'agent de filtrage activé Name[gl]=Activouse o rexistro do filtrado do correo @@ -146,6 +149,7 @@ Name[en_GB]=An error occurred during filtering Name[es]=Ocurrió un error durante el filtrado Name[et]=Filtreerimise käigus tekkis tõrge +Name[eu]=Errore bat gertatu da iragaztean Name[fi]=Suodattamisen aikana tapahtui virhe Name[fr]=Une erreur s'est produite lors du filtrage Name[gl]=Produciuse un erro ao filtrar diff --git a/agents/mailfilteragent/autotests/CMakeLists.txt b/agents/mailfilteragent/autotests/CMakeLists.txt deleted file mode 100644 --- a/agents/mailfilteragent/autotests/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -# Convenience macro to add unit tests. -macro(add_mailfilter_agent_test _source _extrasource) - set(_test ${_source} ${_extrasource}) - get_filename_component(_name ${_source} NAME_WE) - ecm_add_test(${_test} - TEST_NAME ${_name} - NAME_PREFIX "mailfilteragent-" - LINK_LIBRARIES Qt5::Test Qt5::Widgets KF5::I18n KF5::ConfigCore - ) -endmacro() - -add_mailfilter_agent_test(configurewidgettest.cpp "../config/configurewidget.cpp") diff --git a/agents/mailfilteragent/filterlogdialog.h b/agents/mailfilteragent/filterlogdialog.h --- a/agents/mailfilteragent/filterlogdialog.h +++ b/agents/mailfilteragent/filterlogdialog.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003 Andreas Gungl - Copyright (c) 2012-2019 Laurent Montel + Copyright (c) 2012-2020 Laurent Montel KMail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/agents/mailfilteragent/filterlogdialog.cpp b/agents/mailfilteragent/filterlogdialog.cpp --- a/agents/mailfilteragent/filterlogdialog.cpp +++ b/agents/mailfilteragent/filterlogdialog.cpp @@ -1,6 +1,6 @@ /* Copyright (c) 2003 Andreas Gungl - Copyright (C) 2012-2019 Laurent Montel + Copyright (C) 2012-2020 Laurent Montel KMail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -29,14 +29,14 @@ #include "filterlogdialog.h" #include -#include "kpimtextedit/plaintexteditorwidget.h" -#include "kpimtextedit/plaintexteditor.h" +#include +#include #include "mailfilterpurposemenuwidget.h" #include "mailfilteragent_debug.h" #include #include -#include +#include #include #include #include @@ -64,7 +64,7 @@ : QDialog(parent) , mIsInitialized(false) { - setWindowTitle(i18n("Filter Log Viewer")); + setWindowTitle(i18nc("@title:window", "Filter Log Viewer")); QVBoxLayout *mainLayout = new QVBoxLayout(this); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, this); mUser1Button = new QPushButton(this); @@ -98,15 +98,11 @@ } MailfilterPurposeMenuWidget *purposeMenu = new MailfilterPurposeMenuWidget(this, this); - if (purposeMenu->menu()) { - QPushButton *mShareButton = new QPushButton(i18n("Share..."), this); - mShareButton->setMenu(purposeMenu->menu()); - mShareButton->setIcon(QIcon::fromTheme(QStringLiteral("document-share"))); - purposeMenu->setEditorWidget(mTextEdit->editor()); - buttonBox->addButton(mShareButton, QDialogButtonBox::ActionRole); - } else { - delete purposeMenu; - } + QPushButton *mShareButton = new QPushButton(i18n("Share..."), this); + mShareButton->setMenu(purposeMenu->menu()); + mShareButton->setIcon(QIcon::fromTheme(QStringLiteral("document-share"))); + purposeMenu->setEditorWidget(mTextEdit->editor()); + buttonBox->addButton(mShareButton, QDialogButtonBox::ActionRole); mLogActiveBox = new QCheckBox(i18n("&Log filter activities"), page); pageVBoxLayout->addWidget(mLogActiveBox); @@ -180,7 +176,7 @@ mLogMemLimitSpin->setSuffix(i18n(" KB")); mLogMemLimitSpin->setSpecialValueText( i18nc("@label:spinbox Set the size of the logfile to unlimited.", "unlimited")); - connect(mLogMemLimitSpin, QOverload::of(&QSpinBox::valueChanged), this, &FilterLogDialog::slotChangeLogMemLimit); + connect(mLogMemLimitSpin, qOverload(&QSpinBox::valueChanged), this, &FilterLogDialog::slotChangeLogMemLimit); mLogMemLimitSpin->setWhatsThis( i18n("Collecting log data uses memory to temporarily store the " "log data; here you can limit the maximum amount of memory " diff --git a/agents/mailfilteragent/filtermanager.h b/agents/mailfilteragent/filtermanager.h --- a/agents/mailfilteragent/filtermanager.h +++ b/agents/mailfilteragent/filtermanager.h @@ -23,7 +23,7 @@ #include #include -#include "MailCommon/SearchPattern" +#include namespace MailCommon { class MailFilter; @@ -80,7 +80,7 @@ * Checks for existing filters with the @p name and extend the * "name" to "name (i)" until no match is found for i=1..n */ - QString createUniqueName(const QString &name) const; + Q_REQUIRED_RESULT QString createUniqueName(const QString &name) const; /** * Process given message item by applying the filter rules one by @@ -94,17 +94,17 @@ * * @return true if the filtering was successful, false in case of any error */ - bool process(const Akonadi::Item &item, bool needsFullPayload, FilterSet set = Inbound, bool account = false, const QString &accountId = QString()); + Q_REQUIRED_RESULT bool process(const Akonadi::Item &item, bool needsFullPayload, FilterSet set = Inbound, bool account = false, const QString &accountId = QString()); - bool process(const QList &mailFilters, const Akonadi::Item &item, bool needsFullPayload, FilterSet set = Inbound, bool account = false, const QString &accountId = QString()); + Q_REQUIRED_RESULT bool process(const QVector &mailFilters, const Akonadi::Item &item, bool needsFullPayload, FilterSet set = Inbound, bool account = false, const QString &accountId = QString()); /** * For ad-hoc filters. * * Applies @p filter to message @p item. * Return codes are as with the above method. */ - bool process(const Akonadi::Item &item, bool needsFullPayload, const MailCommon::MailFilter *filter); + Q_REQUIRED_RESULT bool process(const Akonadi::Item &item, bool needsFullPayload, const MailCommon::MailFilter *filter); void filter(const Akonadi::Item &item, FilterManager::FilterSet set, const QString &resourceId); void filter(const Akonadi::Item &item, const QString &filterId, const QString &resourceId); @@ -119,20 +119,20 @@ /** * Returns whether the configured filters need the full mail content. */ - MailCommon::SearchRule::RequiredPart requiredPart(const QString &id) const; + Q_REQUIRED_RESULT MailCommon::SearchRule::RequiredPart requiredPart(const QString &id) const; void mailCollectionRemoved(const Akonadi::Collection &collection); void agentRemoved(const QString &identifier); - bool hasAllFoldersFilter() const; + Q_REQUIRED_RESULT bool hasAllFoldersFilter() const; /** * Outputs all filter rules to console. Used for debugging. */ void dump() const; protected: - bool processContextItem(MailCommon::ItemContext context); + Q_REQUIRED_RESULT bool processContextItem(MailCommon::ItemContext context); Q_SIGNALS: /** diff --git a/agents/mailfilteragent/filtermanager.cpp b/agents/mailfilteragent/filtermanager.cpp --- a/agents/mailfilteragent/filtermanager.cpp +++ b/agents/mailfilteragent/filtermanager.cpp @@ -31,13 +31,12 @@ #include #include #include -#include -#include +#include +#include #include "mailfilteragent_debug.h" #include #include #include -#include #include #include #include @@ -62,7 +61,6 @@ , mCurrentProgressCount(0) , mInboundFiltersExist(false) { - pixmapNotification = QIcon::fromTheme(QStringLiteral("view-filter")).pixmap(KIconLoader::SizeSmall, KIconLoader::SizeSmall); } void itemsFetchJobForFilterDone(KJob *job); @@ -79,9 +77,8 @@ bool atLeastOneFilterAppliesTo(const QString &accountId) const; bool atLeastOneIncomingFilterAppliesTo(const QString &accountId) const; FilterManager *q; - QList mFilters; + QVector mFilters; QMap mRequiredParts; - QPixmap pixmapNotification; SearchRule::RequiredPart mRequiredPartsBasedOnAll; int mTotalProgressCount = 0; int mCurrentProgressCount = 0; @@ -96,7 +93,7 @@ filterSet = static_cast(q->sender()->property("filterSet").toInt()); } - QList listMailFilters; + QVector listMailFilters; if (q->sender()->property("listFilters").isValid()) { const QStringList listFilters = q->sender()->property("listFilters").toStringList(); //TODO improve it @@ -232,7 +229,7 @@ { KNotification *notify = new KNotification(QStringLiteral("mailfilterjoberror")); notify->setComponentName(QStringLiteral("akonadi_mailfilter_agent")); - notify->setPixmap(pixmapNotification); + notify->setIconName(QStringLiteral("view-filter")); notify->setText(errorMsg + QLatin1Char('\n') + jobErrorString); notify->sendEvent(); } @@ -363,17 +360,17 @@ void FilterManager::mailCollectionRemoved(const Akonadi::Collection &collection) { - QList::const_iterator end(d->mFilters.constEnd()); - for (QList::const_iterator it = d->mFilters.constBegin(); + QVector::const_iterator end(d->mFilters.constEnd()); + for (QVector::const_iterator it = d->mFilters.constBegin(); it != end; ++it) { (*it)->folderRemoved(collection, Akonadi::Collection()); } } void FilterManager::agentRemoved(const QString &identifier) { - QList::const_iterator end(d->mFilters.constEnd()); - for (QList::const_iterator it = d->mFilters.constBegin(); + QVector::const_iterator end(d->mFilters.constEnd()); + for (QVector::const_iterator it = d->mFilters.constBegin(); it != end; ++it) { (*it)->agentRemoved(identifier); } @@ -506,7 +503,7 @@ return true; } -bool FilterManager::process(const QList< MailFilter * > &mailFilters, const Akonadi::Item &item, bool needsFullPayload, FilterManager::FilterSet set, bool account, const QString &accountId) +bool FilterManager::process(const QVector< MailFilter * > &mailFilters, const Akonadi::Item &item, bool needsFullPayload, FilterManager::FilterSet set, bool account, const QString &accountId) { if (set == NoSet) { qCDebug(MAILFILTERAGENT_LOG) << "FilterManager: process() called with not filter set selected"; @@ -523,11 +520,11 @@ d->beginFiltering(item); ItemContext context(item, needsFullPayload); - QList::const_iterator end(mailFilters.constEnd()); + QVector::const_iterator end(mailFilters.constEnd()); const bool applyOnOutbound = ((set & Outbound) || (set & BeforeOutbound)); - for (QList::const_iterator it = mailFilters.constBegin(); + for (QVector::const_iterator it = mailFilters.constBegin(); !stopIt && it != end; ++it) { if ((*it)->isEnabled()) { const bool inboundOk = ((set & Inbound) && (*it)->applyOnInbound()); diff --git a/agents/mailfilteragent/mailfilteragent.h b/agents/mailfilteragent/mailfilteragent.h --- a/agents/mailfilteragent/mailfilteragent.h +++ b/agents/mailfilteragent/mailfilteragent.h @@ -22,7 +22,7 @@ #include -#include "MailCommon/SearchPattern" +#include #include #include @@ -45,7 +45,7 @@ explicit MailFilterAgent(const QString &id); ~MailFilterAgent() override; - QString createUniqueName(const QString &nameTemplate); + Q_REQUIRED_RESULT QString createUniqueName(const QString &nameTemplate); void filterItems(const QList< qint64 > &itemIds, int filterSet); void filterItem(qint64 item, int filterSet, const QString &resourceId); @@ -57,9 +57,7 @@ void reload(); void showFilterLogDialog(qlonglong windowId = 0); - QString printCollectionMonitored(); - - void showConfigureDialog(qlonglong windowId = 0); + Q_REQUIRED_RESULT QString printCollectionMonitored() const; void expunge(qint64 collectionId); protected: diff --git a/agents/mailfilteragent/mailfilteragent.cpp b/agents/mailfilteragent/mailfilteragent.cpp --- a/agents/mailfilteragent/mailfilteragent.cpp +++ b/agents/mailfilteragent/mailfilteragent.cpp @@ -19,27 +19,26 @@ #include "mailfilteragent.h" -#include "mailcommon/dbusoperators.h" +#include #include "dummykernel.h" #include "filterlogdialog.h" #include "filtermanager.h" #include "mailfilteragentadaptor.h" -#include #include #include #include #include -#include +#include #include #include #include +#include #include #include #include #include #include "mailfilteragent_debug.h" -#include #include #include #include @@ -51,7 +50,7 @@ #include #include -#include +#include bool MailFilterAgent::isFilterableCollection(const Akonadi::Collection &collection) const { @@ -90,7 +89,7 @@ collectionMonitor->setMimeTypeMonitored(KMime::Message::mimeType()); connect(collectionMonitor, &Akonadi::Monitor::collectionAdded, this, &MailFilterAgent::mailCollectionAdded); - connect(collectionMonitor, QOverload::of(&Akonadi::Monitor::collectionChanged), + connect(collectionMonitor, qOverload(&Akonadi::Monitor::collectionChanged), this, &MailFilterAgent::mailCollectionChanged); connect(collectionMonitor, &Akonadi::Monitor::collectionRemoved, this, &MailFilterAgent::mailCollectionRemoved); @@ -102,20 +101,19 @@ new MailFilterAgentAdaptor(this); - KDBusConnectionPool::threadConnection().registerObject(QStringLiteral("/MailFilterAgent"), this, QDBusConnection::ExportAdaptors); + QDBusConnection::sessionBus().registerObject(QStringLiteral("/MailFilterAgent"), this, QDBusConnection::ExportAdaptors); const QString service = Akonadi::ServerManager::self()->agentServiceName(Akonadi::ServerManager::Agent, QStringLiteral("akonadi_mailfilter_agent")); - KDBusConnectionPool::threadConnection().registerService(service); + QDBusConnection::sessionBus().registerService(service); //Enabled or not filterlogdialog KSharedConfig::Ptr config = KSharedConfig::openConfig(); if (config->hasGroup("FilterLog")) { KConfigGroup group(config, "FilterLog"); if (group.readEntry("Enabled", false)) { - const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("view-filter")).pixmap(KIconLoader::SizeSmall, KIconLoader::SizeSmall); KNotification *notify = new KNotification(QStringLiteral("mailfilterlogenabled")); notify->setComponentName(QApplication::applicationDisplayName()); - notify->setPixmap(pixmap); + notify->setIconName(QStringLiteral("view-filter")); notify->setText(i18nc("Notification when the filter log was enabled", "Mail Filter Log Enabled")); notify->sendEvent(); } @@ -273,7 +271,9 @@ } emitProgressMessage(i18n("Filtering in %1", Akonadi::AgentManager::self()->instance(resource).name())); - m_filterManager->process(item, m_filterManager->requiredPart(resource), FilterManager::Inbound, true, resource); + if (!m_filterManager->process(item, m_filterManager->requiredPart(resource), FilterManager::Inbound, true, resource)) { + qCWarning(MAILFILTERAGENT_LOG) << "Impossible to process mails"; + } emitProgress(++mProgressCounter); @@ -383,8 +383,9 @@ { if (!m_filterLogDialog) { m_filterLogDialog = new FilterLogDialog(nullptr); + m_filterLogDialog->setAttribute(Qt::WA_NativeWindow, true); } - KWindowSystem::setMainWindow(m_filterLogDialog, windowId); + KWindowSystem::setMainWindow(m_filterLogDialog->windowHandle(), windowId); m_filterLogDialog->show(); m_filterLogDialog->raise(); m_filterLogDialog->activateWindow(); @@ -406,7 +407,7 @@ Q_EMIT status(AgentBase::Running, message); } -QString MailFilterAgent::printCollectionMonitored() +QString MailFilterAgent::printCollectionMonitored() const { QString printDebugCollection; const Akonadi::Collection::List collections = changeRecorder()->collectionsMonitored(); @@ -424,12 +425,6 @@ return printDebugCollection; } -void MailFilterAgent::showConfigureDialog(qlonglong windowId) -{ - Q_UNUSED(windowId); - //TODO -} - void MailFilterAgent::expunge(qint64 collectionId) { mMailFilterKernel->expunge(collectionId, false); diff --git a/agents/mailfilteragent/mailfilteragent.desktop b/agents/mailfilteragent/mailfilteragent.desktop --- a/agents/mailfilteragent/mailfilteragent.desktop +++ b/agents/mailfilteragent/mailfilteragent.desktop @@ -11,6 +11,7 @@ Name[en_GB]=Mail Filter Agent Name[es]=Agente de filtro de correo Name[et]=Kirjade filtreerimise agent +Name[eu]=Posta iragazteko agentea Name[fi]=Sähköpostisuodatin Name[fr]=Agent de filtrage de messages Name[gl]=Axente de filtrado de correo @@ -54,6 +55,7 @@ Comment[en_GB]=Extension to filter emails Comment[es]=Extensión para filtrar correos Comment[et]=Laiendus e-kirjade filtreerimiseks +Comment[eu]=E-posta iragazteko luzapena Comment[fi]=Sähköpostien suodatuslaajennus Comment[fr]=Extension pour filtrer les courriels Comment[gl]=Extensión para filtrar correos diff --git a/agents/mailfilteragent/mailfilterpurposemenuwidget.h b/agents/mailfilteragent/mailfilterpurposemenuwidget.h --- a/agents/mailfilteragent/mailfilterpurposemenuwidget.h +++ b/agents/mailfilteragent/mailfilterpurposemenuwidget.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2018-2019 Laurent Montel + Copyright (C) 2018-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -31,7 +31,7 @@ explicit MailfilterPurposeMenuWidget(QWidget *parentWidget, QObject *parent = nullptr); ~MailfilterPurposeMenuWidget() override; - QByteArray text() override; + Q_REQUIRED_RESULT QByteArray text() override; void setEditorWidget(KPIMTextEdit::PlainTextEditor *editor); private: KPIMTextEdit::PlainTextEditor *mEditor = nullptr; diff --git a/agents/mailfilteragent/mailfilterpurposemenuwidget.cpp b/agents/mailfilteragent/mailfilterpurposemenuwidget.cpp --- a/agents/mailfilteragent/mailfilterpurposemenuwidget.cpp +++ b/agents/mailfilteragent/mailfilterpurposemenuwidget.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2018-2019 Laurent Montel + Copyright (C) 2018-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/agents/sendlateragent/CMakeLists.txt b/agents/sendlateragent/CMakeLists.txt --- a/agents/sendlateragent/CMakeLists.txt +++ b/agents/sendlateragent/CMakeLists.txt @@ -6,7 +6,12 @@ endif() set(sendlater_common_SRCS) -ecm_qt_declare_logging_category(sendlater_common_SRCS HEADER sendlateragent_debug.h IDENTIFIER SENDLATERAGENT_LOG CATEGORY_NAME org.kde.pim.sendlateragent) +ecm_qt_declare_logging_category(sendlater_common_SRCS HEADER sendlateragent_debug.h IDENTIFIER SENDLATERAGENT_LOG CATEGORY_NAME org.kde.pim.sendlateragent + DESCRIPTION "kmail (sendlateragent)" + OLD_CATEGORY_NAMES log_sendlateragent + EXPORT KMAIL + ) + set(sendlateragentconfig_SRCS sendlaterconfiguredialog.cpp @@ -43,7 +48,6 @@ KF5::WindowSystem KF5::XmlGui KF5::Notifications - KF5::IconThemes KF5::I18n ) diff --git a/agents/sendlateragent/akonadi_sendlater_agent.notifyrc b/agents/sendlateragent/akonadi_sendlater_agent.notifyrc --- a/agents/sendlateragent/akonadi_sendlater_agent.notifyrc +++ b/agents/sendlateragent/akonadi_sendlater_agent.notifyrc @@ -5,12 +5,14 @@ Comment[bs]=Agent za slanje kasnije Comment[ca]=Agent per enviar més tard Comment[ca@valencia]=Agent per enviar més tard +Comment[cs]=Agent pro odeslání později Comment[da]=Agent til send senere Comment[de]=Agent zum späteren Senden Comment[el]=Πράκτορας ετεροχρονισμένης αποστολής Comment[en_GB]=Send Later Agent Comment[es]=Agente de enviar más tarde Comment[et]=Hilisema saatmise agent +Comment[eu]=Beranduago bidaltzeko agentea Comment[fi]=Lähetä myöhemmin -agentti Comment[fr]=Agent d'envoi différé Comment[gl]=Axente para enviar máis tarde @@ -54,6 +56,7 @@ Name[en_GB]=Mail is sent Name[es]=Correo enviado Name[et]=Kiri on saadetud +Name[eu]=Posta bidali da Name[fi]=Posti on lähetetty Name[fr]=Courriel envoyé Name[gl]=Enviouse o correo @@ -98,6 +101,7 @@ Name[en_GB]=Send mail failed Name[es]=Falló el envío del correo Name[et]=Kirja saatmine nurjus +Name[eu]=Posta bidaltzea huts egin du Name[fi]=Postin lähetys epäonnistui Name[fr]=Erreur lors de l'envoi du courriel Name[gl]=O envío de correo fallou diff --git a/agents/sendlateragent/autotests/sendlaterconfigtest.h b/agents/sendlateragent/autotests/sendlaterconfigtest.h --- a/agents/sendlateragent/autotests/sendlaterconfigtest.h +++ b/agents/sendlateragent/autotests/sendlaterconfigtest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/sendlateragent/autotests/sendlaterconfigtest.cpp b/agents/sendlateragent/autotests/sendlaterconfigtest.cpp --- a/agents/sendlateragent/autotests/sendlaterconfigtest.cpp +++ b/agents/sendlateragent/autotests/sendlaterconfigtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -71,8 +71,13 @@ info.setRecurrenceEachValue(5); info.setRecurrenceUnit(SendLater::SendLaterInfo::Years); const QDate date(2014, 1, 1); +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) info.setDateTime(QDateTime(date)); info.setLastDateTimeSend(QDateTime(date)); +#else + info.setDateTime(QDateTime(date.startOfDay())); + info.setLastDateTimeSend(QDateTime(date.startOfDay())); +#endif SendLater::SendLaterUtil::writeSendLaterInfo(mConfig, &info, false); const QStringList itemList = mConfig->groupList().filter(mSendlaterRegExpFilter); diff --git a/agents/sendlateragent/autotests/sendlaterconfiguredialogtest.h b/agents/sendlateragent/autotests/sendlaterconfiguredialogtest.h --- a/agents/sendlateragent/autotests/sendlaterconfiguredialogtest.h +++ b/agents/sendlateragent/autotests/sendlaterconfiguredialogtest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/sendlateragent/autotests/sendlaterconfiguredialogtest.cpp b/agents/sendlateragent/autotests/sendlaterconfiguredialogtest.cpp --- a/agents/sendlateragent/autotests/sendlaterconfiguredialogtest.cpp +++ b/agents/sendlateragent/autotests/sendlaterconfiguredialogtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/sendlateragent/autotests/sendlaterdialogtest.h b/agents/sendlateragent/autotests/sendlaterdialogtest.h --- a/agents/sendlateragent/autotests/sendlaterdialogtest.h +++ b/agents/sendlateragent/autotests/sendlaterdialogtest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/sendlateragent/autotests/sendlaterdialogtest.cpp b/agents/sendlateragent/autotests/sendlaterdialogtest.cpp --- a/agents/sendlateragent/autotests/sendlaterdialogtest.cpp +++ b/agents/sendlateragent/autotests/sendlaterdialogtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/sendlateragent/autotests/sendlaterinfotest.h b/agents/sendlateragent/autotests/sendlaterinfotest.h --- a/agents/sendlateragent/autotests/sendlaterinfotest.h +++ b/agents/sendlateragent/autotests/sendlaterinfotest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/sendlateragent/autotests/sendlaterinfotest.cpp b/agents/sendlateragent/autotests/sendlaterinfotest.cpp --- a/agents/sendlateragent/autotests/sendlaterinfotest.cpp +++ b/agents/sendlateragent/autotests/sendlaterinfotest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -56,9 +56,13 @@ info.setRecurrenceEachValue(5); info.setRecurrenceUnit(SendLater::SendLaterInfo::Years); const QDate date(2014, 1, 1); +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) info.setDateTime(QDateTime(date)); info.setLastDateTimeSend(QDateTime(date)); - +#else + info.setDateTime(QDateTime(date.startOfDay())); + info.setLastDateTimeSend(QDateTime(date.startOfDay())); +#endif KConfigGroup grp(KSharedConfig::openConfig(), "testsettings"); info.writeConfig(grp); @@ -76,8 +80,13 @@ info.setRecurrenceEachValue(5); info.setRecurrenceUnit(SendLater::SendLaterInfo::Years); const QDate date(2014, 1, 1); +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) info.setDateTime(QDateTime(date)); info.setLastDateTimeSend(QDateTime(date)); +#else + info.setDateTime(QDateTime(date.startOfDay())); + info.setLastDateTimeSend(QDateTime(date.startOfDay())); +#endif QVERIFY(!info.isValid()); } @@ -92,7 +101,11 @@ info.setRecurrenceEachValue(5); info.setRecurrenceUnit(SendLater::SendLaterInfo::Years); const QDate date(2014, 1, 1); +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) info.setLastDateTimeSend(QDateTime(date)); +#else + info.setLastDateTimeSend(QDateTime(date.startOfDay())); +#endif QVERIFY(!info.isValid()); } @@ -107,9 +120,13 @@ info.setRecurrenceEachValue(5); info.setRecurrenceUnit(SendLater::SendLaterInfo::Years); const QDate date(2014, 1, 1); +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) info.setDateTime(QDateTime(date)); info.setLastDateTimeSend(QDateTime(date)); - +#else + info.setDateTime(QDateTime(date.startOfDay())); + info.setLastDateTimeSend(QDateTime(date.startOfDay())); +#endif SendLater::SendLaterInfo copyInfo(info); QCOMPARE(info, copyInfo); } diff --git a/agents/sendlateragent/org.freedesktop.Akonadi.SendLaterAgent.xml b/agents/sendlateragent/org.freedesktop.Akonadi.SendLaterAgent.xml --- a/agents/sendlateragent/org.freedesktop.Akonadi.SendLaterAgent.xml +++ b/agents/sendlateragent/org.freedesktop.Akonadi.SendLaterAgent.xml @@ -11,5 +11,8 @@ + + + diff --git a/agents/sendlateragent/sendlateragent.h b/agents/sendlateragent/sendlateragent.h --- a/agents/sendlateragent/sendlateragent.h +++ b/agents/sendlateragent/sendlateragent.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -32,17 +32,18 @@ explicit SendLaterAgent(const QString &id); ~SendLaterAgent() override; - QString printDebugInfo(); + Q_REQUIRED_RESULT QString printDebugInfo() const; void setEnableAgent(bool b); - bool enabledAgent() const; + Q_REQUIRED_RESULT bool enabledAgent() const; Q_SIGNALS: void needUpdateConfigDialogBox(); public Q_SLOTS: void reload(); void configure(WId windowId) override; + void removeItem(qint64 item); protected: void itemsRemoved(const Akonadi::Item::List &item) override; diff --git a/agents/sendlateragent/sendlateragent.cpp b/agents/sendlateragent/sendlateragent.cpp --- a/agents/sendlateragent/sendlateragent.cpp +++ b/agents/sendlateragent/sendlateragent.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include @@ -56,11 +56,11 @@ mManager = new SendLaterManager(this); connect(mManager, &SendLaterManager::needUpdateConfigDialogBox, this, &SendLaterAgent::needUpdateConfigDialogBox); new SendLaterAgentAdaptor(this); - KDBusConnectionPool::threadConnection().registerObject(QStringLiteral("/SendLaterAgent"), this, QDBusConnection::ExportAdaptors); + QDBusConnection::sessionBus().registerObject(QStringLiteral("/SendLaterAgent"), this, QDBusConnection::ExportAdaptors); const QString service = Akonadi::ServerManager::self()->agentServiceName(Akonadi::ServerManager::Agent, QStringLiteral("akonadi_sendlater_agent")); - KDBusConnectionPool::threadConnection().registerService(service); + QDBusConnection::sessionBus().registerService(service); changeRecorder()->setMimeTypeMonitored(KMime::Message::mimeType()); changeRecorder()->itemFetchScope().setCacheOnly(true); @@ -138,13 +138,14 @@ { QPointer dialog = new SendLaterConfigureDialog(); if (windowId) { - KWindowSystem::setMainWindow(dialog, windowId); + dialog->setAttribute(Qt::WA_NativeWindow, true); + KWindowSystem::setMainWindow(dialog->windowHandle(), windowId); } connect(this, &SendLaterAgent::needUpdateConfigDialogBox, dialog.data(), &SendLaterConfigureDialog::slotNeedToReloadConfig); connect(dialog.data(), &SendLaterConfigureDialog::sendNow, this, &SendLaterAgent::slotSendNow); if (dialog->exec()) { mManager->load(); - QList listMessage = dialog->messagesToRemove(); + const QVector listMessage = dialog->messagesToRemove(); if (!listMessage.isEmpty()) { //Will delete in specific job when done. SendLaterRemoveMessageJob *sendlaterremovejob = new SendLaterRemoveMessageJob(listMessage, this); @@ -154,15 +155,28 @@ delete dialog; } +void SendLaterAgent::removeItem(qint64 item) +{ + if (mManager->itemRemoved(item)) { + reload(); + } +} + void SendLaterAgent::slotSendNow(Akonadi::Item::Id id) { mManager->sendNow(id); } void SendLaterAgent::itemsRemoved(const Akonadi::Item::List &items) { + bool needToReload = false; for (const Akonadi::Item &item : items) { - mManager->itemRemoved(item.id()); + if (mManager->itemRemoved(item.id())) { + needToReload = true; + } + } + if (needToReload) { + reload(); } } @@ -174,7 +188,7 @@ itemsRemoved(items); } -QString SendLaterAgent::printDebugInfo() +QString SendLaterAgent::printDebugInfo() const { return mManager->printDebugInfo(); } diff --git a/agents/sendlateragent/sendlateragent.desktop b/agents/sendlateragent/sendlateragent.desktop --- a/agents/sendlateragent/sendlateragent.desktop +++ b/agents/sendlateragent/sendlateragent.desktop @@ -4,12 +4,14 @@ Name[bs]=Agent za kasnije slanje Name[ca]=Agent per enviar més tard Name[ca@valencia]=Agent per enviar més tard +Name[cs]=Agent pro odeslání později Name[da]=Agent til send senere Name[de]=Agent zum späteren Senden Name[el]=Πράκτορας ετεροχρονισμένης αποστολής Name[en_GB]=Send Later Agent Name[es]=Agente de enviar después Name[et]=Hilisema saatmise agent +Name[eu]=Beranduago bidaltzeko agentea Name[fi]=Lähetä myöhemmin -agentti Name[fr]=Agent d'envoi différé Name[gl]=Axente para enviar máis tarde @@ -44,12 +46,14 @@ Comment[bs]=Agent za slanje kasnije Comment[ca]=Agent per enviar més tard Comment[ca@valencia]=Agent per enviar més tard +Comment[cs]=Agent pro odeslání později Comment[da]=Agent til send senere Comment[de]=Agent zum späteren Senden Comment[el]=Πράκτορας ετεροχρονισμένης αποστολής Comment[en_GB]=Send Later Agent Comment[es]=Agente de enviar más tarde Comment[et]=Hilisema saatmise agent +Comment[eu]=Beranduago bidaltzeko agentea Comment[fi]=Lähetä myöhemmin -agentti Comment[fr]=Agent d'envoi différé Comment[gl]=Axente para enviar máis tarde diff --git a/agents/sendlateragent/sendlaterconfiguredialog.h b/agents/sendlateragent/sendlaterconfiguredialog.h --- a/agents/sendlateragent/sendlaterconfiguredialog.h +++ b/agents/sendlateragent/sendlaterconfiguredialog.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -30,7 +30,7 @@ explicit SendLaterConfigureDialog(QWidget *parent = nullptr); ~SendLaterConfigureDialog(); - QList messagesToRemove() const; + Q_REQUIRED_RESULT QVector messagesToRemove() const; public Q_SLOTS: void slotNeedToReloadConfig(); diff --git a/agents/sendlateragent/sendlaterconfiguredialog.cpp b/agents/sendlateragent/sendlaterconfiguredialog.cpp --- a/agents/sendlateragent/sendlaterconfiguredialog.cpp +++ b/agents/sendlateragent/sendlaterconfiguredialog.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -26,15 +26,15 @@ #include #include #include -#include +#include #include #include #include SendLaterConfigureDialog::SendLaterConfigureDialog(QWidget *parent) : QDialog(parent) { - setWindowTitle(i18n("Configure")); + setWindowTitle(i18nc("@title:window", "Configure")); setWindowIcon(QIcon::fromTheme(QStringLiteral("kmail"))); QVBoxLayout *mainLayout = new QVBoxLayout(this); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help, this); @@ -58,7 +58,7 @@ QStringLiteral(KDEPIM_VERSION), i18n("Send emails later agent."), KAboutLicense::GPL_V2, - i18n("Copyright (C) 2013-2019 Laurent Montel")); + i18n("Copyright (C) 2013-2020 Laurent Montel")); aboutData.addAuthor(i18n("Laurent Montel"), i18n("Maintainer"), QStringLiteral("montel@kde.org")); @@ -79,7 +79,7 @@ writeConfig(); } -QList SendLaterConfigureDialog::messagesToRemove() const +QVector SendLaterConfigureDialog::messagesToRemove() const { return mWidget->messagesToRemove(); } diff --git a/agents/sendlateragent/sendlaterconfigurewidget.h b/agents/sendlateragent/sendlaterconfigurewidget.h --- a/agents/sendlateragent/sendlaterconfigurewidget.h +++ b/agents/sendlateragent/sendlaterconfigurewidget.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -62,7 +62,7 @@ void saveTreeWidgetHeader(KConfigGroup &group); void restoreTreeWidgetHeader(const QByteArray &group); void needToReload(); - QList messagesToRemove() const; + QVector messagesToRemove() const; Q_SIGNALS: void sendNow(Akonadi::Item::Id); @@ -75,8 +75,8 @@ void slotSendNow(); void createOrUpdateItem(SendLater::SendLaterInfo *info, SendLaterItem *item = nullptr); void load(); - QList mListMessagesToRemove; - bool mChanged; + QVector mListMessagesToRemove; + bool mChanged = false; Ui::SendLaterConfigureWidget *mWidget = nullptr; }; diff --git a/agents/sendlateragent/sendlaterconfigurewidget.cpp b/agents/sendlateragent/sendlaterconfigurewidget.cpp --- a/agents/sendlateragent/sendlaterconfigurewidget.cpp +++ b/agents/sendlateragent/sendlaterconfigurewidget.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -40,7 +40,6 @@ SendLaterItem::SendLaterItem(QTreeWidget *parent) : QTreeWidgetItem(parent) - , mInfo(nullptr) { } @@ -61,7 +60,6 @@ SendLaterWidget::SendLaterWidget(QWidget *parent) : QWidget(parent) - , mChanged(false) { mWidget = new Ui::SendLaterConfigureWidget; mWidget->setupUi(this); @@ -268,7 +266,7 @@ load(); } -QList SendLaterWidget::messagesToRemove() const +QVector SendLaterWidget::messagesToRemove() const { return mListMessagesToRemove; } diff --git a/agents/sendlateragent/sendlaterjob.h b/agents/sendlateragent/sendlaterjob.h --- a/agents/sendlateragent/sendlaterjob.h +++ b/agents/sendlateragent/sendlaterjob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/sendlateragent/sendlaterjob.cpp b/agents/sendlateragent/sendlaterjob.cpp --- a/agents/sendlateragent/sendlaterjob.cpp +++ b/agents/sendlateragent/sendlaterjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -20,22 +20,20 @@ #include "sendlaterjob.h" #include "sendlaterinfo.h" -#include "MessageComposer/AkonadiSender" +#include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include #include -#include -#include #include "sendlateragent_debug.h" SendLaterJob::SendLaterJob(SendLaterManager *manager, SendLater::SendLaterInfo *info, QObject *parent) diff --git a/agents/sendlateragent/sendlatermanager.h b/agents/sendlateragent/sendlatermanager.h --- a/agents/sendlateragent/sendlatermanager.h +++ b/agents/sendlateragent/sendlatermanager.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -55,10 +55,10 @@ void sendDone(SendLater::SendLaterInfo *info); void sendError(SendLater::SendLaterInfo *info, ErrorType type); - QString printDebugInfo(); + Q_REQUIRED_RESULT QString printDebugInfo() const; void stopAll(); - void itemRemoved(Akonadi::Item::Id id); + Q_REQUIRED_RESULT bool itemRemoved(Akonadi::Item::Id id); MessageComposer::AkonadiSender *sender() const; @@ -74,7 +74,7 @@ Q_DISABLE_COPY(SendLaterManager) void slotCreateJob(); void createSendInfoList(); - QString infoToStr(SendLater::SendLaterInfo *info); + QString infoToStr(SendLater::SendLaterInfo *info) const; void removeLaterInfo(SendLater::SendLaterInfo *info); SendLater::SendLaterInfo *searchInfo(Akonadi::Item::Id id); void recreateSendList(); diff --git a/agents/sendlateragent/sendlatermanager.cpp b/agents/sendlateragent/sendlatermanager.cpp --- a/agents/sendlateragent/sendlatermanager.cpp +++ b/agents/sendlateragent/sendlatermanager.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -22,7 +22,7 @@ #include "sendlaterutil.h" #include "sendlaterjob.h" -#include "MessageComposer/AkonadiSender" +#include #include #include @@ -37,8 +37,6 @@ SendLaterManager::SendLaterManager(QObject *parent) : QObject(parent) - , mCurrentInfo(nullptr) - , mCurrentJob(nullptr) , mSender(new MessageComposer::AkonadiSender) { mConfig = KSharedConfig::openConfig(); @@ -58,6 +56,7 @@ qDeleteAll(mListSendLaterInfo); mListSendLaterInfo.clear(); mCurrentJob = nullptr; + mCurrentInfo = nullptr; } void SendLaterManager::load(bool forcereload) @@ -140,7 +139,9 @@ slotCreateJob(); } else { qCDebug(SENDLATERAGENT_LOG) << " can't find info about current id: " << id; - itemRemoved(id); + if (!itemRemoved(id)) { + qCWarning(SENDLATERAGENT_LOG) << "Impossible to remove id" << id; + } } } else { //Add to QQueue @@ -158,13 +159,15 @@ mCurrentJob->start(); } -void SendLaterManager::itemRemoved(Akonadi::Item::Id id) +bool SendLaterManager::itemRemoved(Akonadi::Item::Id id) { if (mConfig->hasGroup(SendLater::SendLaterUtil::sendLaterPattern().arg(id))) { removeInfo(id); mConfig->reparseConfiguration(); Q_EMIT needUpdateConfigDialogBox(); + return true; } + return false; } void SendLaterManager::removeInfo(Akonadi::Item::Id id) @@ -176,6 +179,7 @@ void SendLaterManager::sendError(SendLater::SendLaterInfo *info, ErrorType type) { + mCurrentJob = nullptr; if (info) { switch (type) { case UnknownError: @@ -186,13 +190,17 @@ case MailDispatchDoesntWork: //Force to make online maildispatcher //Don't remove it. - MessageComposer::Util::sendMailDispatcherIsOnline(nullptr); + if (!MessageComposer::Util::sendMailDispatcherIsOnline(nullptr)) { + qCWarning(SENDLATERAGENT_LOG) << " Impossible to make online send dispatcher"; + } //Remove item which create error ? if (!info->isRecurrence()) { removeLaterInfo(info); } break; - default: + case TooManyItemFound: + case CanNotFetchItem: + case CanNotCreateTransport: if (KMessageBox::No == KMessageBox::questionYesNo(nullptr, i18n("An error was found. Do you want to resend it?"), i18n("Error found"))) { removeLaterInfo(info); } @@ -206,7 +214,7 @@ { mCurrentJob = nullptr; Q_EMIT needUpdateConfigDialogBox(); - QTimer::singleShot(1000 * 60, this, &SendLaterManager::createSendInfoList); + QTimer::singleShot(0, this, &SendLaterManager::createSendInfoList); } void SendLaterManager::sendDone(SendLater::SendLaterInfo *info) @@ -224,10 +232,11 @@ void SendLaterManager::removeLaterInfo(SendLater::SendLaterInfo *info) { mListSendLaterInfo.removeAll(mCurrentInfo); + mCurrentInfo = nullptr; removeInfo(info->itemId()); } -QString SendLaterManager::printDebugInfo() +QString SendLaterManager::printDebugInfo() const { QString infoStr; if (mListSendLaterInfo.isEmpty()) { @@ -243,7 +252,7 @@ return infoStr; } -QString SendLaterManager::infoToStr(SendLater::SendLaterInfo *info) +QString SendLaterManager::infoToStr(SendLater::SendLaterInfo *info) const { QString infoStr = QLatin1String("Recusive ") + (info->isRecurrence() ? QStringLiteral("true") : QStringLiteral("false")); infoStr += QLatin1String("Item id :") + QString::number(info->itemId()); diff --git a/agents/sendlateragent/sendlaterremovemessagejob.h b/agents/sendlateragent/sendlaterremovemessagejob.h --- a/agents/sendlateragent/sendlaterremovemessagejob.h +++ b/agents/sendlateragent/sendlaterremovemessagejob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -29,16 +29,16 @@ { Q_OBJECT public: - explicit SendLaterRemoveMessageJob(const QList &listItem, QObject *parent = nullptr); + explicit SendLaterRemoveMessageJob(const QVector &listItem, QObject *parent = nullptr); ~SendLaterRemoveMessageJob(); void start(); private: Q_DISABLE_COPY(SendLaterRemoveMessageJob) void slotItemDeleteDone(KJob *job); void deleteItem(); - QList mListItems; + QVector mListItems; int mIndex; }; diff --git a/agents/sendlateragent/sendlaterremovemessagejob.cpp b/agents/sendlateragent/sendlaterremovemessagejob.cpp --- a/agents/sendlateragent/sendlaterremovemessagejob.cpp +++ b/agents/sendlateragent/sendlaterremovemessagejob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -21,7 +21,7 @@ #include #include "sendlateragent_debug.h" -SendLaterRemoveMessageJob::SendLaterRemoveMessageJob(const QList &listItem, QObject *parent) +SendLaterRemoveMessageJob::SendLaterRemoveMessageJob(const QVector &listItem, QObject *parent) : QObject(parent) , mListItems(listItem) , mIndex(0) diff --git a/agents/sendlateragent/tests/sendlaterinfo_gui.cpp b/agents/sendlateragent/tests/sendlaterinfo_gui.cpp --- a/agents/sendlateragent/tests/sendlaterinfo_gui.cpp +++ b/agents/sendlateragent/tests/sendlaterinfo_gui.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/agents/unifiedmailboxagent/CMakeLists.txt b/agents/unifiedmailboxagent/CMakeLists.txt --- a/agents/unifiedmailboxagent/CMakeLists.txt +++ b/agents/unifiedmailboxagent/CMakeLists.txt @@ -1,7 +1,5 @@ add_definitions(-DTRANSLATION_DOMAIN=\"akonadi_unifiedmailbox_agent\") -set(CMAKE_CXX_STANDARD 14) - if(BUILD_TESTING) add_subdirectory(autotests) endif() @@ -15,7 +13,11 @@ settingsdialog.cpp mailkernel.cpp ) -ecm_qt_declare_logging_category(unifiedmailbox_agent_SRCS HEADER unifiedmailboxagent_debug.h IDENTIFIER UNIFIEDMAILBOXAGENT_LOG CATEGORY_NAME org.kde.pim.unifiedmailboxagent) +ecm_qt_declare_logging_category(unifiedmailbox_agent_SRCS HEADER unifiedmailboxagent_debug.h IDENTIFIER UNIFIEDMAILBOXAGENT_LOG CATEGORY_NAME org.kde.pim.unifiedmailboxagent + DESCRIPTION "kmail (unifiedmailboxagent)" + EXPORT KMAIL + ) + kconfig_add_kcfg_files(unifiedmailbox_agent_SRCS settings.kcfgc ) diff --git a/agents/unifiedmailboxagent/autotests/CMakeLists.txt b/agents/unifiedmailboxagent/autotests/CMakeLists.txt --- a/agents/unifiedmailboxagent/autotests/CMakeLists.txt +++ b/agents/unifiedmailboxagent/autotests/CMakeLists.txt @@ -7,8 +7,9 @@ kconfig_add_kcfg_files(unifiedmailbox_agent_autotest_SRCS ../settings.kcfgc ) - +if (KDEPIM_RUN_AKONADI_TEST) add_akonadi_isolated_test(SOURCE unifiedmailboxmanagertest.cpp ADDITIONAL_SOURCES ${common_SRCS} ../unifiedmailboxmanager.cpp ../unifiedmailbox.cpp ${unifiedmailbox_agent_autotest_SRCS} LINK_LIBRARIES KF5::I18n KF5::AkonadiMime KF5::ConfigGui ) +endif() diff --git a/agents/unifiedmailboxagent/autotests/unifiedmailboxmanagertest.cpp b/agents/unifiedmailboxagent/autotests/unifiedmailboxmanagertest.cpp --- a/agents/unifiedmailboxagent/autotests/unifiedmailboxmanagertest.cpp +++ b/agents/unifiedmailboxagent/autotests/unifiedmailboxmanagertest.cpp @@ -224,7 +224,7 @@ auto mailbox = createUnifiedMailbox(QStringLiteral("Test1"), QStringLiteral("Test 1"), { QStringLiteral("res1_inbox") }); QVERIFY(mailbox); - const auto sourceCol = mailbox->sourceCollections().toList().first(); + const auto sourceCol = mailbox->sourceCollections().values().first(); manager.insertBox(std::move(mailbox)); // Now manager should have one unified mailbox and monitor all of its @@ -270,7 +270,7 @@ // Now the box should be loaded and its source collections monitored QCOMPARE(std::distance(manager.begin(), manager.end()), 1l); QCOMPARE(recorder.collectionsMonitored().count(), 2); - const auto srcCols = mailbox->sourceCollections().toList(); + const auto srcCols = mailbox->sourceCollections().values(); QCOMPARE(srcCols.count(), 2); QVERIFY(recorder.collectionsMonitored().contains(Akonadi::Collection(srcCols[0]))); QVERIFY(recorder.collectionsMonitored().contains(Akonadi::Collection(srcCols[1]))); diff --git a/agents/unifiedmailboxagent/unifiedmailbox.h b/agents/unifiedmailboxagent/unifiedmailbox.h --- a/agents/unifiedmailboxagent/unifiedmailbox.h +++ b/agents/unifiedmailboxagent/unifiedmailbox.h @@ -46,22 +46,22 @@ bool isSpecial() const; - qint64 collectionId() const; + Q_REQUIRED_RESULT qint64 collectionId() const; void setCollectionId(qint64 id); - QString id() const; + Q_REQUIRED_RESULT QString id() const; void setId(const QString &id); - QString name() const; + Q_REQUIRED_RESULT QString name() const; void setName(const QString &name); - QString icon() const; + Q_REQUIRED_RESULT QString icon() const; void setIcon(const QString &icon); void addSourceCollection(qint64 source); void removeSourceCollection(qint64 source); void setSourceCollections(const QSet &sources); - QSet sourceCollections() const; + Q_REQUIRED_RESULT QSet sourceCollections() const; private: void attachManager(UnifiedMailboxManager *manager); diff --git a/agents/unifiedmailboxagent/unifiedmailbox.cpp b/agents/unifiedmailboxagent/unifiedmailbox.cpp --- a/agents/unifiedmailboxagent/unifiedmailbox.cpp +++ b/agents/unifiedmailboxagent/unifiedmailbox.cpp @@ -138,7 +138,7 @@ manager->mSourceToBoxMap.insert({ source, this }); } } else { - for (const auto source : qAsConst(mSources)) { + for (const auto &source : qAsConst(mSources)) { mManager->mMonitor.setCollectionMonitored(Akonadi::Collection{source}, false); mManager->mSourceToBoxMap.erase(source); } diff --git a/agents/unifiedmailboxagent/unifiedmailboxagent.h b/agents/unifiedmailboxagent/unifiedmailboxagent.h --- a/agents/unifiedmailboxagent/unifiedmailboxagent.h +++ b/agents/unifiedmailboxagent/unifiedmailboxagent.h @@ -26,7 +26,6 @@ #include "unifiedmailboxmanager.h" #include -#include /* Despite its name, this is actually a Resource, but it acts as an Agent: it * listens to notifications about Items that belong to other resources and acts @@ -46,11 +45,11 @@ void configure(WId windowId) override; void setEnableAgent(bool enable); - bool enabledAgent() const; + Q_REQUIRED_RESULT bool enabledAgent() const; void retrieveCollections() override; void retrieveItems(const Akonadi::Collection &collection) override; - bool retrieveItem(const Akonadi::Item &item, const QSet &parts) override; + Q_REQUIRED_RESULT bool retrieveItem(const Akonadi::Item &item, const QSet &parts) override; private: void delayedInit(); diff --git a/agents/unifiedmailboxagent/unifiedmailboxagent.cpp b/agents/unifiedmailboxagent/unifiedmailboxagent.cpp --- a/agents/unifiedmailboxagent/unifiedmailboxagent.cpp +++ b/agents/unifiedmailboxagent/unifiedmailboxagent.cpp @@ -43,7 +43,7 @@ #include #include -#include +#include #include #include @@ -59,9 +59,9 @@ setAgentName(i18n("Unified Mailboxes")); new UnifiedMailboxAgentAdaptor(this); - KDBusConnectionPool::threadConnection().registerObject(QStringLiteral("/UnifiedMailboxAgent"), this, QDBusConnection::ExportAdaptors); + QDBusConnection::sessionBus().registerObject(QStringLiteral("/UnifiedMailboxAgent"), this, QDBusConnection::ExportAdaptors); const auto service = Akonadi::ServerManager::agentServiceName(Akonadi::ServerManager::Resource, identifier()); - KDBusConnectionPool::threadConnection().registerService(service); + QDBusConnection::sessionBus().registerService(service); connect(&mBoxManager, &UnifiedMailboxManager::updateBox, this, [this](const UnifiedMailbox *box) { @@ -147,9 +147,9 @@ topLevel.setParentCollection(Akonadi::Collection::root()); topLevel.setContentMimeTypes({Akonadi::Collection::mimeType()}); topLevel.setRights(Akonadi::Collection::ReadOnly); - auto displayAttr = topLevel.attribute(Akonadi::Collection::AddIfMissing); - displayAttr->setDisplayName(i18n("Unified Mailboxes")); - displayAttr->setActiveIconName(QStringLiteral("globe")); + auto topLevelDisplayAttr = topLevel.attribute(Akonadi::Collection::AddIfMissing); + topLevelDisplayAttr->setDisplayName(i18n("Unified Mailboxes")); + topLevelDisplayAttr->setActiveIconName(QStringLiteral("globe")); collections.push_back(topLevel); for (const auto &boxIt : mBoxManager) { diff --git a/agents/unifiedmailboxagent/unifiedmailboxagent.desktop b/agents/unifiedmailboxagent/unifiedmailboxagent.desktop --- a/agents/unifiedmailboxagent/unifiedmailboxagent.desktop +++ b/agents/unifiedmailboxagent/unifiedmailboxagent.desktop @@ -2,38 +2,52 @@ Name=Unified Mailbox Agent Name[ca]=Agent de la bústia unificada Name[ca@valencia]=Agent de la bústia unificada +Name[cs]=Agent sjednocené schránky Name[de]=Agent für einheitliches Postfach Name[en_GB]=Unified Mailbox Agent Name[es]=Agente de bandeja de correo unificada +Name[et]=Ühendpostkasti agent +Name[eu]=Postontzi bateratuaren agentea Name[fi]=Yhdistetty postiagentti Name[fr]=Agent de boîte aux lettres unifiée Name[gl]=Axente de caixa de correo unificada +Name[ia]=Agente de cassa de posta unificate Name[it]=Agente per la casella di posta unificata Name[ko]=통합 받은 편지함 에이전트 Name[nl]=Geünificeerde e-mailboxagent Name[pl]=Usługa połączonej skrzynki pocztowej Name[pt]=Agente de Caixas de Correio Unificadas Name[pt_BR]=Agente de Caixas de Mensagens Unificadas +Name[ru]=Агент объединённых папок +Name[sk]=Agent zlúčenej poštovej schránky +Name[sl]=Enotni poštni posrednik Name[sv]=Förenad brevlådemodul Name[uk]=Агент уніфікованої поштової скриньки Name[x-test]=xxUnified Mailbox Agentxx Name[zh_CN]=聚合邮箱代理 Name[zh_TW]=整合信箱代理程式 Comment=Unified Mailbox Agent Comment[ca]=Agent de la bústia unificada Comment[ca@valencia]=Agent de la bústia unificada +Comment[cs]=Agent sjednocené schránky Comment[de]=Agent für einheitliches Postfach Comment[en_GB]=Unified Mailbox Agent Comment[es]=Agente de bandeja de correo unificada +Comment[et]=Ühendpostkasti agent +Comment[eu]=Postontzi bateratuaren agentea Comment[fi]=Yhdistetty postiagentti Comment[fr]=Agent de boîte aux lettres unifiée Comment[gl]=Axente de caixa de correo unificada +Comment[ia]=Agente de cassa de posta unificate Comment[it]=Agente per la casella di posta unificata Comment[ko]=통합 받은 편지함 에이전트 Comment[nl]=Geünificeerde e-mailboxagent Comment[pl]=Usługa połączonej skrzynki pocztowej Comment[pt]=Agente de Caixas de Correio Unificadas Comment[pt_BR]=Agente de Caixas de Mensagens Unificadas +Comment[ru]=Агент объединённых папок +Comment[sk]=Agent zlúčenej poštovej schránky +Comment[sl]=Enotni poštni posrednik Comment[sv]=Förenad brevlådemodul Comment[uk]=Агент уніфікованої поштової скриньки Comment[x-test]=xxUnified Mailbox Agentxx diff --git a/agents/unifiedmailboxagent/unifiedmailboxeditor.cpp b/agents/unifiedmailboxagent/unifiedmailboxeditor.cpp --- a/agents/unifiedmailboxagent/unifiedmailboxeditor.cpp +++ b/agents/unifiedmailboxagent/unifiedmailboxeditor.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -93,7 +92,7 @@ , mMailbox(mailbox) , mConfig(config) { - setWindowTitle(i18n("Add an Unified MailBox")); + setWindowTitle(i18nc("@title:window", "Add an Unified MailBox")); setWindowIcon(QIcon::fromTheme(QStringLiteral("kmail"))); auto l = new QVBoxLayout(this); diff --git a/agents/unifiedmailboxagent/unifiedmailboxmanager.cpp b/agents/unifiedmailboxagent/unifiedmailboxmanager.cpp --- a/agents/unifiedmailboxagent/unifiedmailboxmanager.cpp +++ b/agents/unifiedmailboxagent/unifiedmailboxmanager.cpp @@ -25,7 +25,6 @@ #include "settings.h" #include -#include #include #include @@ -36,7 +35,6 @@ #include #include -#include #include namespace { diff --git a/agents/unifiedmailboxagent/utils.h b/agents/unifiedmailboxagent/utils.h --- a/agents/unifiedmailboxagent/utils.h +++ b/agents/unifiedmailboxagent/utils.h @@ -53,6 +53,7 @@ return rv; } +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) namespace std { template<> struct hash { @@ -62,5 +63,6 @@ } }; } +#endif #endif diff --git a/doc/akonadi_archivemail_agent/add-archive-mail.png b/doc/akonadi_archivemail_agent/add-archive-mail.png index 638166bbfc141922c207e73d8afb9e32cf52703c..495d34fe0f0229ffdcac39076b54d011f72d4fa0 GIT binary patch literal 18288 zc$|HF2Q=03|92Ep$llx6wJCe=aliJK6>^cRTq9c{vhV#~BP-$}gzW4{>Y8O#vcfHt zk!xi?>i2t|^Zd_w&ht61&-;Gv_k8wypYJ)}L{nou$}6l_E?l@k3Bt9_FI*soE?giQ zxqR{b2|IyB=fZ`H7fcN;&wu~_h4jJ&rVAIW&OuBJCnZ&3WtC)SXXoS;<@#H$b8$)V z@Cftr3iJIfVtjle{~AKTe~SnoAjk^{o>Lw`fEN%tr~LddE`EM)ei1%?A%I_mmtT)Vqzi^lGm?am;6^)B_&0q6y)XQ#S|126&2Og)C{d1JGx$X_q;jB z>)yV#wT)pi{$cBXU~_Bh_y5M`{}aEr zHa7oZK{4Z91{#^Zs<(1X%%PULx@81@e=H|Z5 z%+7zEp7}iWb@KDn#HY{y!Pvy)=*RJ)kq?;RpXbOL`Aczw!~O3E9=!k6+t=^gx7O3! zcYgMse`xRQZtdu5ZR+4Ds{}bocVR?cse3amUWZ z!^-*2IV^8^SUP%`J0dI`-EACP%pDMB=dgD*wYzO%>uhq<*~sRWxwXB4m7~6;J!oO4 zZ+=tH)JE6T=A7ynm}=@7s%Yvds%gn7t4k}W+>liwzFTd3F6Q=u=EfF8L_~i@{+tjI zUA%aSWojBufSQq$MS_eC)lJ@zL=KQ@Jbqg$r7Jptgo($k(+o4TcBY7f4=4 zL&;lfg>PwJAFX7$v=${ng5>(efM6n2gr7fe#z2A!sTXo@W=6|dE(Yw47Z>O9|KCztu7n~3SR~n(-gKQAIq`}_r#FI-;oXDBU zx0MUoi5c{1MVvJ-VBWo4aohf=)H&pR=MC{m0dlnV)Un~!hhq~U{I;k^2p479E#(ul zJ-!3pw4P1+oUX^EO1L?8DXM6yF2RxpIRhu?JEzP$3p3`a>qixVfb9lNS~++_-(}Bi z)ujF&=Y7|RXlXhzUcs?wDY*E^Jw z;gsP`>7=@Y3p&z&L<>j_J2P!Fjxa;9jViug((I?45$I_Ieh^GtBXNN6YzJ1sG)8#bPn+OGWoKDTmz|~Gneh}5if(BA5+W_VF}Ckws?(m& zDsF~58FBK9h7R2?(xzwiFYz;Li)BBz6lBqlhCcWX*a#Mj$~gKGg=^e&8sf)YbAn8YLFq8$UHR8)wND*Vb?iHF+x_- zrNWX`kY(T$P|+r)O}{teJj9&O-YCcyc#$sa`6V|$3>83AApj-MhQ#r)1{`;BJr{gO zpZ(I?64||LdV8!8%a~&baJzAD39>Wv(?&WuH9haEh!GMs6S5%JSIKy?BjA}#kK#4I zh7F-lt#%ZBaQ~!Ihveo%p+p0-igI(qD+7Jli@2Cn1TRtIJAO`ve#VZ9yYw8-D=HsZ z^=N;m{d=nLO~g~gEqp1X5cjWlO{$YkI)d?COV2;HidhtH9kPfEHsK83VAXJzSV|~z zg8glA*(>Hd=rSQm8H46AUC+E7fhm4k6#H7gYc)-Z`my{s-h0Fi!HEMu9>mrUV!3d~ zx&zwvsA2V_cW*UMIc0dZ90TcH0ww}Gee0+*2`#q&eS6=+bYdJFP}WW5#_6br8o>XsJe-^p-;c}hUYW|~m5 z6nf|SL$&4o4Rl|YRU|0^5ZS0Fm+op|R*sRZC$A-A# zj~z9C*sS$0cPp!sp}ZYF+_h;3AMF9{EAJ=Y6s}N&-z3*((Kkf4AGA(q<2z|_7Du7H zLYwG%v<+{4l%tKw z$0_T{+Iu%b`IT_{p!--dR&{!sSB}j#I?=&0-NSw--BIeY5n#*p=cLQq`94oWIP+=1 z;7AZRGqd~YT0!SEoaRP?;ty1QU$Um1k>caS%ZFjybUZ0cC4Pw4AFj<8drc?JR{u2S z&H3VJIl4AI-nE}u>XS{UbCU9S44GWTH1$|fkfd%#%eKoKm+ZwL&xfSj5+ z_%v`54!Tk6?fJ-$XOBKchaV{TztiCpA&tG=?B5daL{1b8A{Ep$kz5V%;&48MKG26C-a&S|>E!(H9X(1KsvE)>9 zP*Y}@dAu}lbH+F0@4q0UWuQ)_Imqy;WshG)VYvWn&%Qr)BBW1HCFl~*oI53S;QfZf zJMwSM2-#=H8u8IAxS!8kwfpah7Y}^Zjto&sI&k3%N@&pqUs|g$&r!WMCOg2a4w6Nk zJ)GeRdrghH+Vezrqk8Ow(n-M4VE=5}7#U)QOhc#Vp!d0QEapu43%ett;8(vtYBgPS z@pz30ns9j5j5BRP1dy7!`G8Wj7Z1XJhsOvTr<+S@QLT&8&V}6@GPrM{r7xDX~tXA|P{!ei7yx@>WQJiM}ER(8MnO49Mv4-!U-8 zwPx^!{}$2Xb&wFm3G7rN_*D?rRzvnBBPlaj;YHU=?5>sW0Gu!Sw% zI3lVyUYQeK#^YtElx{2!V(;@$1y4^+AHQY*|Clqut{-xa?NgiFDYGb-a8e;-J2N(L z(;xf2_~mn0uR?!Yw>v^p#v$!)7;%%WA^Kk3rE2EM;lUY=!RNtsugX_&qWy`AszS~) zvp>J(W7*89($%YH#YZd`8N4kimUKv$ZgUovYz&u(D820oRWg;7CJ||8>1-SCPi6M? zyMJTE&0p_%Q>LSAh1BYc2dU3ldtQy*{d}J?mxFYHE^A*#g}lXV-mlq-i=yt8A4R&$ zr!B=(X7TUW)wbPD-I(saOjIb+v*P)wsqHFIfu{dRuCnuxxMT_Wr#V{$qb9G!-u#!B z-Lqvn$QrcB{35wk29_Tp(%%paak&%DT<+4*OWxn9PWi5qSx!J-U*<*Pha|~M_X7=S zddwIU>4dFIigbwgPgGK-d+MODGD+&NBA}FxS!AmHoNa-L{${-w9ImNzkYvP_B~`=e zn67?^=5^HvC5u1VJ`@IV1JX(qy#mV5U1nmY;ih_f(xO=l&D!wii|Oi2bcYFxt+`Vd z<~cNnK+Pv;L3~`7W6m!?40BvI-41PBS9& zX%h0!c$+4p?z78F261q=KYZ42hzd}gKdJR4J_yKP;V9OB%*cJA{S%2Mt#Ip=RX~i6 zBXx!5%GhKEFFNEA#nq2uafjHO+!rs;$%m)Sm(A1^sg8c9~ zS{WH)3;lTN+f&IT;yhH$aXSmLF^`KC8`8AGy%gKs4Bd%-eHoRRm3nwBGf*=<%jS#6 zauMFO5|CFgr_B%Kx)f>yRZov#fbQus-5N7Kn<8EDqZxfwdnOa7lO_5%WtEwm^UpCl z5Bcn;r>B)vc&)zGhWPA6hpJlF$8a}WU7}=*TcP7;OM`%bPxGEym*~i_d79=tTf%6% z_$e*NY=}czXGynKfSrG8m&Ri3_q8Me<2a#EZ9HC;h`%;&p!O9iAR~}JUoi1vuGFt| zn|cCYYrO7DqO;2;$$KyFjISQwTX-tGY9FuIs#)ORYK(06UG}66B-CKH0bB-x%l-o| z`Jk)}BsM*$nhiDWdW=5xNxzHVo=r_1Hp&!DvhKS8S(yt`-@YP4TSDUh0-+!OgqC01 zo0i~iFF^k)IO9cflYHtOUw-hDT9H0yHV>Tzfp*uIy}cRqs4cY>MYOqeacU3--pXZXkVGj1I{`aVdSn)ocFF)P3%cRVL=b`I~LA4AMd z96+1pYX_SmV>SerJ;yK*H`V~Gfv07!H_6<^)5_3hGzv_760%Qt{pklx)4sA(u-^92 z-gqkBnL4!H-G=t!_T`{Ee)p@ccHjKqT}RH;`s7p1uI}eH=V|gMcq?w07WU=*nsl-# z&zMhu^Ym8b$sq|R)@)RqaZO~RJ9Heq2yIl>jDd~zpBcLH25J}clj z>&+Jmu1DH$Cu*;DK(^ z<8zuTeDG_yBsN}MWMjUHpwGJUM7I&EcI-NBMtgzZho5yAPxz<1efP4g5_;BiSLO$8 zM_%m4uBUWfcTXD_-?PN|MW}vo_H@e>n?0s_7bJ_z->CtZSFH)Fwe+sU$L`bpR9n|BUT{47^d47@`Vg|2s?>JZ#sr}P`zT#I{=vaG zes+q}lwTvR^k@Pn^Am7_sTqNn1BR4A>K&%Z5v|Grnjx3)_BBi zj0JC^j6yK9BHIsSYhy1#AWbDT^u&QRPy0=eFYPaa5Q@SOLTS$i&%)+&026qB3NSx~ z*kGm7m*ZjiioXnOhJPo;oLhTC0zC{D%CSiXR>~(BJ%x-|VK6;o%ICff^qC&NyUHM=rW3&7F|%w2gpI3RVe2c69~^rGSDQv@f>@t zRS1;S`<&JEtwBe6X4@}@H6% z9wKy3x9V>noMK)+3*drTnaP+L=T7Y6c!F>>lH>y@(c6`&HsrWg7YH@PKK^_j>WV-7F6QAO1Q4y;coh4@R&i6|78_wc~db zbj9S_15$w86{_a%jXC)g;K2G*u*L-{)ra?|Vuf8Wzn&VIBTW(jYxTV0>n)#IT+I!9 zkV-r(O*I*HpqnWw#qF01(ogp0#Yl3{fiAoR@#Xv=n);GB9ZgAhfC+&yzw!m~r8WEw z;G5*61yRkcOvlb-_2%IhD^u;r!FrH~43|1$;1WieysBx@GA~61phP#%Rz}Y$WF!K)=?dAa*hn(=B?zY znG3kQS;3qeJx`=?ZC&1&;z>70r91>_qPLvk+y$J`W9&n(OOQ+Z>N>8$kPXPxs+X4r z3U9U0{QPY3Yxit#wEXboctWfG9$YvUJ5oQ_th^?-gr=A_+V6Fd^~&uS^r@i#zSqNZ zaJbH+8TqcTutg%h@Tc36vN}?O`@MMUc3IAF+dh>`H%lyVrDfPB0YJ8E_!?LVBXPej zY9WuPOPi}dPcLzHp4>V6DAS77(BN%l%brmmgUJc+3j*nsP|Jc~V%Iv-{?Cl6G(ZQP zt$&;zRfSYr9~o@C3~+tYAp_?$d5q7|p)CQv%T_-KvHgm)ctH!@;A<83?h!ID_Ttv} zrNA)a8bDNEq0LLd{dBi;0cn5>Yt|c|s{z6YE}RTpgal5vM6JDy-bL)mIX*+`u{SHsr>65~nGV_S0tOQn*$*9Q_PgJU+Z#Z!`AWo-D2v z@s$e0ic38jj)TvI0dIm!+ReuJY){-aqi(ac5H6+9`++9cRi12dvq_^^EQc=?Se8jx z&>Uun~RMfsc+9?ntnuN%Vy=JIp7ZsHPNL|U9NP6+*F!XUq zCt@DjU-^?CF^D~Y9Srd){JBk##GT>5)6YJr<0Bee`UCuYDmrj;Iv$M(l3=7p{c6FEQR_23LIRk```r9-K zOeXT+{)mb$VeLs$9}lrJ(`t!O)y{7cGwmZca|_gpoFV(p^m+^2?nYP)X~vj!%;hB z!wE;tdSe{3A@lA2-5CzV(1*zdqZY>WcXIQZV**1;xZ6yOLawbm7j=FJOg6+@0pxE# zT~(L#V-5{DQEv#hk9&?BO@k@*8HuBf*ggq(T!iv;M^qlDPwLNFx{iDgs^Z`c>c4q$ zM4lhdhPf5@e#Ma1VqJHt(_f;H*;)(0%BlZZByl0Xsb_n44={N$Ee)L!)^OWIIR5=) zaPvrR<4-@|flWR@eN+Lcu?yflTEATzc!*yX$2ln`!f>N&TdPC-)(*NHw12a)kESsmnp$1IH_Gr2tnM-l?buaYqNkQjw3IAATa}iy09+ zwtq}}A(Rcq?>V3b|__zv();<(X=K=jQKk4|QRgN1X6_!c`j`k;eof6NUUjoR|Qf^(PX z@}MUJ+*C46A0YO4ITWmPDp&noe6kOga{*5VToTJRyxGO6Rfn7VfRaZ)-ZJ-hE*d6$ zlQ#)&_io!GeJSHMI6NoL=U@Wn; zCIcpkOT*R872>jYfyp$N0@F`F^69X;1R5(H&kX(eu%mjUjd~3?v%dTYO zq{;~^hOG-P6maWAxS%X%zA2T0i_itt|T`Y(0OoweZzEMf%Ppc$*~BpgXy- ztEl6eDcc-%b0M@wCxxhZ@3$&?s)TF1-xqRfEthM*$!#2e>yOlXlXnsQZf5e!4=X4l zVw?O4GwL|xxCeiPVL#jIi*DB@_$h#@-%gLkfOoz#dg>Fc{)M9SxY@3szb#gif1t2Z z9f@wbz`^f+hL&mGo|>sULY|uJI^^NkJ8V~Fvk!=j((xi9Oer>zSXxB;Ovn zN%f3gT1@~vuO-NV9wAz{gQc2ePO0xi!J|eJX7cg#w|EcymejC+RDlEg@s7gwgFxwT zdvMjxp5MCUFPa|U(N>SKcZsqQ#VxYSfQ{jli@8kW5DEZ=o1bz)JDkMpw9hSmKUM3u zEHPt20jf=loG2+}2q>RAoVvpPj`a~MPrYV7tH&ED&_Tv-aw|a{_^B*B8j?P+S%|NF zng$Qk+A!%X>|XFQ$s+YpjR!}owVW&a zubiwE@v~uO<~~cx+H*H@Mi_8!&|0-LxHnaR%X`X5;-$PQHHE?Qoh9JeGz`aOAg%zY zh5iPPn9K-|Sp^iTR{=GDxcC+srh#AKfQ4G%0Dtg?pIpTls`@Pb5a9j>2&j^@NkN6_ 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 literal 39482 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 diff --git a/doc/akonadi_archivemail_agent/index.docbook b/doc/akonadi_archivemail_agent/index.docbook --- a/doc/akonadi_archivemail_agent/index.docbook +++ b/doc/akonadi_archivemail_agent/index.docbook @@ -30,8 +30,8 @@ &FDLNotice; -2013-08-30 -&kde; 4.11 +2019-09-21 +Applications 19.12 @@ -45,7 +45,7 @@ Using &i18n-archivemailagent; -Use ToolsConfigure Automatic Archiving... +Use SettingsConfigure Automatic Archiving... in &kmail;'s reader window to open a dialog to set up automatic archiving of mail folders. @@ -73,7 +73,7 @@ Select the format you would like to save it in. ⪚ .tar.bz2 in the drop down list. The archive filename will consist of the prefix Archive_, the path of the selected folder in &kmail;'s folder list, the date in format year-month-day -and the selected file extension ⪚ Archive_Local Folder_inbox_2013-09-03.tar.bz2. +and the selected file extension ⪚ Archive_Local Folder_inbox_2019-09-03.tar.bz2. By default Archive all subfolders is enabled. Uncheck this if you only want the parent folder archived. @@ -107,6 +107,10 @@ You can use the checkbox at the left of each entry in the list to enable or disable archiving of this job. +It is possible to access this configurational dialog any time later using Settings +Configure &kmail;... then select the Plugins page in &kmail; main window and pressing +the configuration button against the Archive Mail Agent item. + Using the context menu launched with a &RMB; click on an archive job you can open the folder containing the archives or start the archive job immediately. This will overwrite an existing archive created earlier at the same day without notification. @@ -120,10 +124,10 @@ &i18n-archivemailagent; -Program copyright 2013 Laurent Montel montel@kde.org +Program copyright 2013-2019 Laurent Montel montel@kde.org -Documentation Copyright © 2013 Laurent Montel montel@kde.org +Documentation Copyright © 2013-2019 Laurent Montel montel@kde.org diff --git a/doc/akonadi_followupreminder_agent/add-followup-reminder.png b/doc/akonadi_followupreminder_agent/add-followup-reminder.png new file mode 100644 index 0000000000000000000000000000000000000000..2583a51c1fcd443c60527430743064e6c6d4c70f GIT binary patch literal 14035 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 Wue^=o<^TMQ^2bdhNQ literal 0 Hc$@F$&UDW$t>X(d)by1N@$knRqV?oL16 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 CaYSMO literal 0 Hc$@&Laurent.Montel; -2014-06-10 -&kde; 4.14 +2019-09-21 +Applications 19.12 @@ -37,16 +37,61 @@ &i18n-followupreminderagent; is an akonadi agent which follow up reminder mail + +Using &i18n-followupreminderagent; + +Use OptionsCreate Follow Up Reminder +in &kmail;'s composer window to open a dialog which allows you to create a reminder to follow up your current email +at a specific date. + + +&i18n-followupreminderagent; Dialog + + + + + + &i18n-followupreminderagent; Dialog + + + &i18n-followupreminderagent; Dialog + + + + +Press the arrow-down button against the Date field to select the date from the &kde; calendar widget. It is also possible to choose your calender for the reminder using the Store ToDo in drop-down list. +To remove reminders you have scheduled, use Settings +Configure &kmail;... then select the Plugins page in &kmail; and press +the configuration button against the Followup Reminder Agent item. Then use the context menu launched with a &RMB; click on a reminder item to select the Delete action. + + + +Configure &i18n-followupreminderagent; + + + + + + Configure &i18n-followupreminderagent; + + + Configure &i18n-followupreminderagent; + + + + + + Credits and License &i18n-followupreminderagent; -Program copyright 2014 &Laurent.Montel; &Laurent.Montel.mail; +Program copyright 2014-2019 &Laurent.Montel; &Laurent.Montel.mail; -Documentation Copyright © 2014 &Laurent.Montel; &Laurent.Montel.mail; +Documentation Copyright © 2014-2019 &Laurent.Montel; &Laurent.Montel.mail; diff --git a/doc/akonadi_sendlater_agent/index.docbook b/doc/akonadi_sendlater_agent/index.docbook --- a/doc/akonadi_sendlater_agent/index.docbook +++ b/doc/akonadi_sendlater_agent/index.docbook @@ -32,8 +32,8 @@ &Laurent.Montel; -2013-11-30 -&kde; 4.12 +2019-09-21 +Applications 19.12 @@ -82,7 +82,8 @@ messages overdue since the last logout if necessary. To change the options for emails you have scheduled to send later, use Settings -Configure Send Later Agent... in &kmail;. +Configure &kmail;... then select the Plugins page in &kmail; and press +the configuration button against the Send Later Agent item. @@ -113,10 +114,10 @@ &i18n-sendlateragent; -Program copyright 2013 &Laurent.Montel; &Laurent.Montel.mail; +Program copyright 2013-2019 &Laurent.Montel; &Laurent.Montel.mail; -Documentation Copyright © 2013 &Laurent.Montel; &Laurent.Montel.mail; +Documentation Copyright © 2013-2019 &Laurent.Montel; &Laurent.Montel.mail; diff --git a/doc/akonadi_sendlater_agent/sendlateragent-configure.png b/doc/akonadi_sendlater_agent/sendlateragent-configure.png index cd8499fc680c9131c5061856590e87a5f838ade9..9c11db3b7aae1219e66033f6f6074c5619f7682b GIT binary patch literal 14310 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ыWRB~jI?7>oAt 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

IU@`~ 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 P`w$fcjhB^j79sx&)lvMV literal 21714 zc$`(cbzI!e7w^5e!$NUgq{X$kyA~+!THM`TiaQi2?(R_B-QC^Y-S2*X&vXB{`^sh~ znMwA{BV?^lleOILW1cLHM2bL4 z;XfrLgb9IltP)qMT=Uwi3;YRPkQWe~JCjC5Q(PPxAk9eaBuV-{r_&E5@b=CF~ zBewR^F=%~xxv|dn(EG5R17$+@lQy_aQaehS2GJ0{7s5}FG#FE{ST_hHRw{{HWXD#Z zsL+IOK!eyz9a_SClp9O-U;U6k4=`9EA90&gv4l!ncE>`xAajmA*H{z)3y_LebbYnm z5zKNIJf@u*Y}J2P%xR>p)kS^r%nOCid3>9ioP^COZw1~|2?+zHKix;ay>+&=ilTY9 zP8V6S5Qlh4!wM?)@ym!l@bU8_sg=OTw<)XM?x!kZ1#rSJ2bEAIz3kh_X6LPFE6a9< zD7VL#I!);2c(0X*ni0Q>_HZY)4N$QjVj_N^dt0I( z1@16{o*2?2;Yq1<2%4q>P6S1mpx}N|T){AZ*xA95PB8B#-pcP`))4pdib>w=H(drm zPsOW&9!}xgvq8TR+Z&V-4f!At{2&B6-^v1ZFoFcNgC(|~#ww#!0E6him2mk>tU2q| zcnDoI&QE|=uO_KyFYX5-;g{FK%h7$<-up0>nBtYzHIH!Ikg>_RrW$M@YZixjc z?Peg^WPR`pQZFjMTWspvmM+duCI}Mo7PiWeG{3%f*zjCJmymIrK|AfTY3_8?c#1pC z4ArvWF~mz9OG1}4kpflodd-ktxh8n<>Uj%h^KYS59;iv074!eux9wog2DUHiSs9~f z_QI}s9zR3XvTj+2q3FNHyf35Xf!Yko;rxoffWo0vd&7`l3F+Z2(s-Kj&m5XZXlc^e zEV1#iVGXR`#o?3wjz7D*e^Uz8tbn*EjdWWGG(#*`LD*xC1_=Zn`oc28AGI|!#Hjx4 zn*iW4p`GfkS;N*a&cC2LV=JzkXYAB@$tjyM2#WIs+h{?6Lj4FZPDX~?M_QC$cbsj5 z))>B!7+M$vqEW=gP+y3;U$lT0K(@aHAZPvsSDOYxYnkViNv?ee3a-gw&@stJ1rbps zkE&>@Vq;+~H%Wal31+0Fr>CJoL_tw0o9|H{(ccAkU}O}Z!v=$BJ-vXf;2_{F;AetV zg(?I>1XQz1Rhzj|gfJQ6}BEdpTYw|vEixWu4+N@AjRt4q{q-#ZFWMT;LNSTaEH zjM4Mt4livS5#R^yuS^2~1Tztm0RR-kEtq~n000v{^7%>u%XEK532I2Mw&tJs_*}&@ zA~{MWu|Q$rJJ??)CLW@0L8@i<^NImBB?}FUQxz;dAdRwrq2u_q{A_hsk;uhz?$6n3 zrc6!yhUh12!(-&%ia;Z0;}p)_F|Tu}BoL z{z+q>YsGY1bRJQThyz9ik@zKD$b*#e^$HZiOe|fZ7{PraRGFXWs1geH_J(E9+Wi$* z{@vZ&?b|)iw{Z$_nib+?Rws6x;WE;ijW+bzY~7?D?bm0^V?&{KC>3myiDAw4tXy2F zlN6j3efmr$M)?v!A;i z_jaR#9=g_#*@BW#;beE(p60V%3r>&D<>w>+c!C35O||v5>K*@3Fx!+DfbW5niVqGB zuF#?+hdyH`_@t&u;_fi+X|BT?&--OZn2gl|j1s&eqJr+%rmkW}k9O>{*Etas{jE3H z(dUrFIe~tQ**uPctNp@4w5KlEBsX0qB|Z^4eHd1)L~v-lUZu@oBW>ai&)6y5p8 z!adDnkw-^ne-ZQ$DWtHmvA#9P3BfOwtICbRkmjpeVrYIfG07L>h!}8tiI8&r!A-~z zkk4v60Rs?%*CklNAPr*TwOh~*0!qbyhwB5^ruFutJj^B4mzIv0A$O_Jw2q%Ra6b#A z&FA*0cx2?1mP)rkDawVn{e%Z>j7e|n0tea#Jx8>9Y*YAUfIfmk(NTvl4ze`2QMoFrHESjwiEQK@Pf z1X-`5q5_*2*PCCQ?N{dE0TqFug;!cy3K{9on!usw>pi?9CKnRe;eC&jCGdJT%laj- zTYZ=z%++hSV*1Ai+3b$sN(b6DXJOB^XF~7s&!&fuj(P0W0Rg14^5Xmv{_TYNGYhOw zHmP{la^(5L8HjjL@tL*;NqnJ^+qU1(mE=?rA>p(0`&0?DxAjqkvz>)y7(zp#BB^!&egLy| z8h;b7!mDE{j~{L~ba zYjBMD#@qVi!PkFsgd9Fznk#s&!DwhPOlc8P0eg#z@f71+P^WcXruH*KOl7kl7cB4IW+8XVaIF7_6J{$fpt%_BS_ z4`i&~el`vg1_B4#=f~?LPn}7-fUnTuLMsWnhp*8GN68L0kX{ZY;ha`KdC% z2aqdSTid2RTU*fD)0!?oAedWzq1LY#4^bOTR|*u>DatV?p^RMc6OgLm2Ata-*`1?!XXiI`yj)%PQ}B zFD}7iy-uHtcx4rEqvKB;-n{RRG+i8u~zGra?czAft&5P{T%lPQTswx@^ zgZc4f@agDBV(ZPzwJ+Lg#A>b%9Pbpmm`I?>^R{As#mRPkOc*W{3KxY zEeJ6v3KR|e%#{OI28Q+>;xHY!&j@dA##b8V|KLBC^d8%B5>iNU>oD|L%tMFo)huwi z6ANT|u3xsj}s_H_Y{VvZxOAe#0 zuJ1+iP(ksUU&lOMZC3XvNPodzVRTjMY|?2qU6oZWx}MF2nCFTrnCrRtsZw;~p0KwLO)~gNHTBZTaeG!1VWl`rDi3=rFBK-`=YbE)1Lod;y zS*du;q8^^~XyZ{e-m9*_s`d~3x}Gl-$97Fk_lOW7qhgB0-)txU8aFJPj{jBBQF{M) zd)Cn4y6hCl8tyxGxW4Z{c2XGX-RsKo9m^8%T@J_kLgKq~%VsI?@svRF_%@_3%%#Kd z?=Jw_Z?@l1QB}26VHXMxZDMHXY_=$77}JU!2kB3r4)Koy)v`Gn?S8cKfY>uS%T7-N zcTRQVlg|o+d(6u&qD_ zoG%6)nw>&XyBA9FcFo$TMWfU+u;DR+7(|%V=VW0q(ikLZ{Vva`QDk*AqmAtlJJHa_ zxj)X2aV!_Gv9TH6^o6o?AJ0D?w77fAHEd&WxlWdbm8#laR?b{Ea%>S1nBQ+Nw_%WQ ze4e`D;Ip~vHu1jOtZn}qB;c??UgAb;;tT-_;#6t#xn9o%py5npaa`^sl>z)B)GBq` z9I!xl3k0^2xNJB7+v&qfdE-VtSG}yPtbk{9iMAgO*fXBnTsJdVoGp}|S2X231* z*}b0Pehr485Bv$`uI)Ury%@PHmIZ(2n3@Z5%ss_iMWqE^rb>-xF{wTRl)G6d9Qw z+HAC70rpIG9GU>Yi&PVq;n8uuk7UK?m(C@U8Y4A*n=Xgk)mp|`&XWRR5XkDCLWiZ#9LCOPKm*A=m5ute>NdLV z-@rZ;6GO6ix$Oh!u1ig=YJVBAtm=RSbX9A*I^3lUQiZp?UbIF;L_k0$GwR^8IN=8A zKZV9!w!cqT4LDxv#IV!N9;!NbPW5IB^01az%j?v8k!gC!>s=FE^uiyGLrc zOm;vi44ZG%6PQ>H_`gLM1&NUA{~xu*vCo<|>XHJ~_dT>$ph6qSQZe zbHBGF*)a$j?g<27#gCc*{oL02Mxj00ymO$awT%KBB|Z*^6QxEvuRLIDZ>3-R8$ZG9ik6}6s;i-ep||EjWa3)Y`3bn22Hm*Sz%uBb+BfSmU!SMco*;4U!e7MD{^{*ZU1EX>dMsjT{5J zUuLIM^MuMb2w@7LsYgl*inEpGUW2;xwVL(bX=~D&fI73|`2NeWRL`5c)X5HY*?0;_ z$)edLOq^MF#rOn`7?H>tA7@6nRn&$9*qu<=dYko^QxpOmM$LNbQ&ny*Qqt`-TbC89 zf9I?JzEV)kVTY4J*mXi)B|>By%Op=^zE-vd0kT!Y!nD|JT{sEvW}Ub*n)CbKGySgr z65A>tVP46dc8Tu2lF4OhtV>8Ozg zk&=?8;+d}h7#Wqmb*Q}fFpyUf(=eB+Ns|)yXem*(Y!d4M!6Tp!OOEEJYIoRO+yvKM zKpN?ExRHKuSG}K^6%iH&1^Mk9GY0+mhK?SW)@Z|a#D+6z9Lw-}aL!}+cX005Rx{(n z0Vv4Jnyi)Q{q*iTYNA#_NCCELE$- z;m0x_KfnUv@_73Fb$zp)=hAzx+en_m;H>F75EdDnZedAT-B0Fl^xQfg-`gkB`DF#X zH`*S3S6Ux0Y}Qwb3L&8fq6q}trm`Q-SD3Y=Cn!aQ6QWbHy1qmE?Mu`O6i%(lJ~|T) z_Vfzh`$JI5XPBry9qOfo0j`vv5{e)pp@e&T>F9pgvZm`ZQPZ-Ka9?RD z7(gglA`fU*Y{S9Z5uza>&Er|BOxiR$-c8svTHgQOrIf>u9GIH=*)7EC{8Gl_^WWhh z;WY}?3_di{apul=UUVS(_g5i?zjU4;I*T)h16No?_U+oz?&VMbGAeThFB#|V$$E2O7P{z7aU(edwyWHX3S}6N>n{xpF z>qyqznQ=?r(4P2obGM+KCiAWwBX!&GQ928oyT=PsDd(O~&aS(GT0vC%Z(1GXHv*zhX~ z3h{fHDpV!Vj!H`^XDpn-HNxsjDq$4jD4}s z&WqY$SH{DmW!wY~pf0uMmjDosn%`l?g#fT)EbdYOx-xP(j*gl5v$Pq=I4)NTkZ@>5 zMl|~d#KgrpiR7YGm6X-p*mx*e=MtxAn7Lb0f1kDqk)}hO86&m{Mq=j-;g!>xM zCRJ;7~i6#iM4z5M@41Mn;xidDSl_rsn9-+uMWjMT^6hxWYk#Ah?A{n?X&^ zW+M3Za8zbgv)&B7d+u*~diB(lY6V7KUfMJ%8U?>C73JefKhh!X$cR?oK&=WR4=XEc zj!K!y_}>y0i?HV`hN9b*21^`9-Eu10n5bXJmr3PT3Dgv%IVyD~vd`T(j89~oxj0YG zsi2|So11{Qw%pv@lTsQSp<?ztMaC04oL`Tyubha?A|Zd|KnR+TwGKdD+1emdo*+h z9Z{?m19fhGa>Z@!6;fhx2|Ory)VM+Y+=W1gKSR!z6@ShGrLPa$Fi>%1dz6N$?T?Pz zG&KZ#-04?@`j0b1NwQdg9+g!{Xq7EFh%HX#AsY<W0jL@Wt>CmFhh8?kP;)u@B(gTMZ^`B=n!w6$KG;3qaM9te!Y6nSI%vd^$ z=P6XE3c&~aX#v{Mg&B%Q4QuR_V;-pbzYRJ@(FAETB==i1te!y&6)V$J$XT-D&ar+W z?XlP1cUxlQ&McnMh0a&AyI+{;m8~Q@=K> zh9`>vEeuIuFP|!gLS-JkN{UvsNlun2(L`;NU-XSb)(_Apl!NZS=*@QDdwV^a#aLE;Ak=lQe)S1X{t}K3i4Cgf{{xRZ zH24MdFC8UTAXJ;oZvU1gd1&-2MaAolK;wu$Q*6^f!NScU#|s)WU}jf6IN3x97)Jj# z*#+m1>~(kLq7#c|yN%NqVZfxCx9|O(>aK+Im%l${oF1w? zl_2v?zm@e*5pj%PeaLtfUFVODoHztLRz>CS;6BI+eukt2r*!LXq%94PkGA=|h3+NwMmG0!f zS<3gx#1y^6@Br$SKwCV{xFLkz{E%3jcjE_EQdAnZL45P3ZC&F;`FdHuDN4IoB>}JM z;8+TF1oF5aXmDY<$yR~=o_D?JVx-#_ykdY(AECB@e75bB@UiEaqTY=U=UH`J003!svI zpZ!!C7H#5Z*ogGv3X0kx*H9aTEJ#)lT;*J!{+~4smZ_M!~J7~YZkJ)>bCTj)U{K>=a{-#%s z+qH2mGNrS_KR*i<$?M$_a1p+nG#FAm)IVNE*YS&RM%UB2*Jv7*5z90B*Eo78 zcySS-L{#YbMC5iVWQ4m=BY=w`&hGoi)Q;$>me(;+z?0mU*)RiHas35Ogz~uG1g?Z| zLIx-YG4g+Gm9$APHrZ6<*7|4{o`R@%YPLM^=@dqOnN?z|B8|GDl9>&4 zg@%cKBMX`u9ozJ ztuA7LxH!_^;M8a5q0UGMU1G^w21t(EC(gia8!-K32$&n47H0X0G8~C71407mqF__p zep?O=^m4MuSNQTYJBW;LGW6+-y?GC3Oi^|HhMQ`FI!Y-Vd&mIM)fx^WpN?4GY50!M zRESPSWi-JgOW&8OKF+MiMJoZX`E(XVk>iI5k4r~Zi5`za@&W5*yej694J|2`d~K2> z$t@)4RO+XG@X{;I7YFmiy!Yt=ipcg2s^l1v{GlP-W68txhKrDh4nVK^NX#Cjz%j$s z`ywo~j$@Y*R3qNyiSe62p$}qbT@>=>AU8%Yi56#2>`z%0y-oOSE zj3i1vM8`dKSS9}Um)bc;UIw$N)Nl^g4`B#NkUGj7cD4gRn=TDIR$LGo5(gDsm!kTXBjQ}#o>q_f*Wh71W!4;ahU83#G#ua7W=1G#RD zY4+QrCVhJd8?B50!V|jI9Ml7GbHdQ9f)OqOYV(7~jF7*QcyxIC=6_YKZu-SeLbs`9 z>^c)*`H$3+i4ZdVd@o0E8p!BJZdO*)K_GgQN6D}D{m8L;p%J&*^s-!JCB6s!?B9yQ3DNSwkL21(y7!K~1zC-I#271{M}2l|hZ)qoCL}+xNt69q zqwd?$hPj=MUMnn4%ZT@q)Ha4%D$OaY>rJNn1NZtJ-X)ox($630NuUbQxDPNmW&-~H z&Pn31BKoifLAABcWZ5|-?ex>IksOa5=`I}Fr&WMI;BN{9*#~^sQbl8NI7f=eMo7aj zGV}bbTFckif=XWgR|yKgc|o1fdU2(tCGq@miyEef<((IaCJQU_U2&kQx)g2>Ei|`% zj!souZlqwvVHD~0C?y6IzKL;=l{NMo33Ih@wr$#}3Nt0l^#Q1sc(NZzahDmpc_kI2 zBUDUU^o31wPi)N!*eOQ*cW7t{l;WVHFIL&@kU$!d#-vw<6)*)khaCL#j18~-(NAhh>C-`sdi;EUb2TY z4IPy~^6h)hYA!L7_Z;@hlxm zXeQgWVjVr~TaQ#_s>J~CtG%h^+x%p*yV@$89&k|cBT7=@%+~z8vLUU)$>ne-D7t4?28)GMlc3YVm6gExAf1eEn^{b0wR`-3lG9iCeDE zG`Vf~K8SWphEN0-Hegd#l(7@IA7IoZ+qL>+fbdOMyxBdf6tJvS{bW_K_7^q+x??Ev zk}RAI0#$N&c)_LheLwa4WCmZ6qUAT)3{*fi6^0-L(r!_^Cwu@E1H;E@RbW-e&B)vH z?H3G9k7dMQVM#ihW8Ks7NvbNr?BvhwXWB_SFB<+xdoSM)jL*$wzN)$t}4-*BPKu|l#{1fTT4 zv56GTGM`FpG_*ONcJO+?uu8=fao78PJmc6Arm>pO;OLd3qM|~=1EIN0#!@CbpLi)K zM0@^h=Rg;QVJ>}zmg);!Rxp6rg}E|ibEra8rP%QKim@$9WtHI`u`%Ko2&>~aVwqf9 zK2)`67j>Bsu`iz_cw>|Bt8Qpyi_OT#5hSCdQ2nBeWw1z`twO6t%xMQ=qB7ebk$3jU z@cPZ?`7ky#lpo`I{_-%E`W*>-Os~;~UI?h?+n$;5-2Qlgg3oHVJAiV!ScQg!q}OUw z!3^5!c=b46t_zv4d$}v=>+6f%((gj4zRLT)20+2E3u;d8pNt*CqnrQ%+tDNG0euPV zhL`G$80fL6{!dt*+XD<=M6)A((vHU?3Ex9eZdo z(6OsXaTk08x}{9Yj}FMnGXW~9nl0O>_gKdJHaR|z=dN1+tQ1O=Y589`d3iAv61{v3 z3=FVk&cF2uyx+~v$_vaFE9Ck4`B5ts67ssmeks;$urO|QIR}%?CLcop06@rn=bFXe&ZVG>o(%zMApEROp1munYhus`(Wd-w1Q2HSHB0nd{>hK6Euvsql_Yazy8h>8) zr>d4UeELBoe3N%svJ(7vE*@_rB-FiNz3OuDW-|6GW;zTC_D-+EP|U`LK?ta!p>d1j z)peQ6f_ulE@ee%o&o@{XcMD-*P0|e)qm0Hp62kmp$ySnm^caz6pc-_xp30zVMsjWV zX!*Tywm2u#$}dtpKjRgMk0s->S7|Wbww@){2-K*(E8Qb`#*B0ltEB^x_|P zB+QTF-=r`GtHB0G;qup)*OyDpn%GWy3|f?+x5iC=Zht^AA?FQt(y22Eu(SV}`0jS4 z4`1WD=~-1>U2HyE_~l!qgw>qycJN{6li~gAEl$dhLUeL*LSCoP(mECKNZcBS{gJsj zj&OHvjudep2ROZ;o$PFt8t$zsi1$X*#XtE zB`O|~Ipq94LvjLzl#(RaA7m^`X{CC;7pqlFZ$Xd>VELOw#|x4Nlb*naP8!ynt=yjn zJYPbIy7Q+UjiC9lF^*}m4^-<=m9({OxBrapAm8E}AlDSwKWBoprGm{lg{7~}Bkxe> zxp4_Bd!%9OFljYL!QI?#<;)FWs!a`-ZuPMLB7KB~k8WT$om`ID6`3;@D#u*#kq4h> zqGMG?8Nd`&(rpWFPyO4vk*-MJER8tW)AMpY0LK zlfy6_uRM!zKQCB+px?&q`6wcTP+)f=nbc9n9(ZLGD%Iuk@R86IgUz$?MXnAKD`Q}h z;t@FB-km{-hj<83P&eIm*S00rZoAjJ+)wI0Lh)5~`S|$WHfn}dp8-bERZ!s22}1Ux zqDNjVmXf~1CJf{h#m(KKCpFqc59;JEAnX$oUI>50n~+4rjAaBue2Od<>ndRRjvUWs zW5u;0X0H`LAt~k9`Pqf`C2zvaL_n?i*pU<1LrY8|1fnEXdDXhgC44z)-<}GPY9C%2VecI@Os1lcG-6sMq3s#^0Dd9IJ{5A03*LVvY0 z>*{b-5}?A=o<}2z&wwk|%@=zwKV;jf-rWNvhwM*O;K{Y%Ts1R(L8;#3OO;~Km7c#` zyPbr#RDPoP1x4uT*@w38S2epmle-wq7Cd_iczpeK68qT{Y7~EM#DKN8r(CaGEf{Yw z8E^f;C-Ae$_RpI_Y1I2Ttx&|YP)EM0SoXVu#rcuLlg&?ajT4Ls|MRE?y)g8@M~7Q3 zKF~`Y<1lm9kd+k_?2m80`fcM!VfQk<>iq&O z{l&GVCu`5QB}Cl6gMz4LVqpgN_sxsszc$zqVPfWo-iafsR=(#(R<*iQ@z9ou6ipx? zR3MAzk)d!IHK^MWw#K^uvtDHnm$c2-FF;92bMonm&FSrUby>_H!0Of4w$jelqaVnS z@)r`Sskz3P%n$=NE!QvD3dY;KN7EP?rTs&%_3`vYK9cZ$=+w5&{cfq|6FSnSE~a$$ zG|JyUy$^eO{D_3|y^F**67Sv2aP+A%gS+G9W^{jl|3c>2-28EKHQ^x$r|r|nLfWB~ zotlI$$FOuYS~{9^cI%V&$MxRNaW8ih z?;va-ZZQY07e1+EWd z(^9B?&o&vKoNb7^b@e{YmTQgaHT&qaYWvJsGdu0J({x%}oKEJLqz{y&Y`!y%vW@e@r7kEg4mOp4Wbm#v(n;ljv+*ohti8d%x^SxgCK54a5tMbyopxt(LH!CkD z#_rLy>34Es5deY@m;#F}KmL6HPZ5Jz2g127p@IJYt9E{GY-r0?@cHzn3 zH(I)C7x?5gUb$0<;e8n?t1>>^n>uC)c)Git1h-?l4wKsSdZh_!05^>%6<6ot_@g%S-#O#PiSgc4Wc33fFq024uX@7D+Ki{`^0-;{iOeALyKz-nc>)%7wyKEAZnBFsbaiN9*6+OTmX@xAYqm@zCo-L`;lUr-6u&5Co<7qJo*KPkN7 z?ZNm(mDkPQu>0ls`^#w+x64VB#e9*|OEeMB&FyV6qgIRCbO@z|0M?@h34`|1=eCdK zqF2pJ#AJ`K$fE5M0Py0nCf20__chmiqo>WAv zQnEeVc(X%Kvq9Qwt~hShH}3Xjs*VAU*Y|_)6T4`(*>y5Ar#A$RfZ6aeMu0mb(|U!H zm;ZV;DQhZo<)%R9o9tgY`nNQZ>Rf?HYslxZZ7>{41$doSG!8}*bs7!V*3PhSdv7wn z7RqN}W8vZHBfA;y^mTqdFTRImrStQ#kSP|;qZ08x-6YXEy^z3tq_dbisGFIon=Q=^ zC&1{LF2{ehUag-lW`k`vI7?xsluN%;CXl0VA>aN=&gXq`#&r?p^mzICo|(y~LW2e9 zvS?^}#R&`uq{oh6r9Eh$nImh_a4;;JFY8QU^Nd!{WV2j|BoW9l9)*TC(9l>uTdu3p zX)T<$fJ4F0pFOs)uqc#GQ`OL*o*tX<+Q&*8XLr8IudQVP_$^yyvY5yB+W21kei!0H z#;r1ZcIyv6mghg7J>A@FeO%+JlNmoytaHCeUsf$k@?B&U_*^TLT^)!b;ILWaERap} z?tI(nz$994bH7c=dboIZ-s}J-NUiuZYe3U}><+kk?*j=jSiE2A!N#gT4-b+S#`eo3 zPapSx{W{72`F0hT_d5#r`6++cq;B~=Ohj1t=vS2LsT23{?##?gvADt=_*963k#V@b z*>BuT<+JJO%juPf#N+5_YtshGyLi{#q6Q`VemCL+yeX=rFN)7jYs1ZA*po1RZ^vh1CBGWP;DTM%^JO$m6l)G6#;>Y@TM?hy{ULf?PZ*H%20oup!}`Ox9~B zEJi@H#_Bj89Cf9UKEI)tTYV0Vn(QfdZe?dr$M8Bl&wPDhCFAv)rzE*t>o`v%T6H~N zyB?1|&jg}dwqCEyR##W|^a#H+WoHXkGezJqHg~Eq{yl%G>d2=GmkR+d6zy^BPD%tl zZ@;cj3cQY)>Um99dV6vQgF;2%&^CO1ZC~nD49mV3$1p9SS z&lVOI6@?k6@Oiq3iw|7y4$jWZOk@d=U}Ca@bI8cZ$p0c%sX_1W1~4TQ7sE?W)OZ!^ zbuMnY-OiOHtaH0c^Ee(wSMM-iv{U- zQXV{BcG_QG8*FbkMD2yfMPU1+q@^XKrPY~jhmcF~kzp|!ZPJQ=dTu|<;4or9E5v4X zUIn6Ew!GTZq$?H4tvA_|OU1jiwigzfOr&#(=UtyQ*G&q1YI}IJ$Q7l1ca;N2-(%)i z4A$!~%5Oi?;Q=YE?juX~yQhrY2sMOnr;P9hhYUKL8?lRvzT3^FNQj8waqrlCUmua@ zcmD{+;X-?NS*!$SF5`V&$Iss}xXz$vA@2@$HQs*2M`eH9d-bEoK9(J<_ z<2Z~uGpF~|!^2=J2s8MzeSP7#!3hx?2ZzIa#%=6qF#kD{klAp&#hJ0~i7dM8H!7aj z%NU+drfH^+#d-@P4udA41q%uu%Tt!`XGO)=-jMc(fi&z0sVrP z@}UZRRr~dU$UE`HlHe~;U!S6B+gNOq+Sz^U;}NsdR2O)}CNf&fb?ewGEBo)AG_5!J zJtwrW$D#DaE1YQ%L4WgQ)?!lZuu*^-iy5L6<3HjBB- z&iC&B9!z9hlmUmYMU{Mx@9&KPSb3$TG)X^W)pI^moVay#xKQ zvvO+1Q`|b#)@xR%!*oQ6y=)??27Elf0yl1_OW=E{wdeEV78G@46%ae#9`jX8EG;ao z*vnMQR4nU(!eZYHMHQ4)jQf*ha7LtMpdg`C$i6j`&74xGBS=e|mpw^vl)OWd($Q0w z(9tU8lZL>@&z(A9Y-5S#FG^KoDC=tGf}2pAH{e&O<_&dA2!jQAn|}X$UT5n2?8uEG zB6a@HK!s2LK(1F3>W2tnMCv&vWmU~FjZZOuod4cXG&tJy{b-k398{Jh4YqOiP`{4B zRFup)6=evK{r`(1@OE$H_`fg}j~*z(b0x#c;FHM^Q}Y!|?2&J|p|qfN@ojwBs`M)P zVcMZea%*o!lF9&T>;!im;~+rSu@fjDG$sZKd(*#93`o=Pt;M}wE)N0#fCngkNPob9 z8yx72Iya|VBnhbJ>;R&D4VO1$$Y(pLYGvfrIj6S z*NP6SE+Zy^{2&Lh{^h&bFnTQ*SeTnC3}^@t_99ESMMX)?5|;fig?2%>WvbownMRLT zvDdtIp>GiIW>SC*9#YLxv#7p=jJLn&rxTz>jm`rHH2j@GxQ z_RF#JvpI5QRaIVAFsy^Tj{E?G{l_Ufq)G^L~*ys8Vil?BZrA6V+Xf9oACD^Zq3r?Y-r459H zL3}w%sksx<7Zem0?g_fy#a}!}vVT9CX8zS^v*K3gt&pK=iwtj<_3`xnc-QSG6nJsf z;&VTelzwIf5HvP6UYIYVH`ItA#)E>q<8BwU1Cpk#3n^fVDU9905g$bWYnQFW#QG(o z3D4(Be#O@MmxF%(OdP++2HrSZN4&g9P~@Juz=_34Zj5~uRd8ty6vc#vhHTejw*~-| z7w68_UuQ>DvL-TaC!%84#}|zUs4-AzZ4#S*l~iYMoh|=J7@ljES^OmtV`O4-bpJx- zLLL;vU(6FMj7i{11@M!riZGuhgmBs)Nt$yh0RYP8J)URwZ*CBSVyWj66X)2TN4q;wU0TbuWTWq#PX*52L74N)DKsDRs8QYzQV=RlrYsa6tZlN zqi4fADGmG{fzmXmsJ+R^#FU~a001U43}*B7Q) zfem2tIBQ~#iTc2{2d}$z`zOM`g4+sg%uUaJxRgPIZGbq|3Pr zjwKqfyHq7Pbm;-1Qs-)GaE+!&(@!B~ zvs%-e!9`DR-Tiv$-LwTJyEj|c%fi|I8%CX)w{EzX$~UuTO4>iczyGq^t|J0gYVG*| z`lAE)TI`jF$sv<8h3@s!`a?rw+28X`ji7O(#?vHZFj;QTmfamqZ8xr*A6qY9&L20A z?;^({pPrh`zh_!py%X5};`Y5Lmo7M&X`rvG-W9(N!kn2#CAS!B`h z7X<&(eb2o0;N!k#T+OJ)%*3%>8f)Aye<%d9z{wdF^|vP z(zR0I$OeTZ2VI!8*A72JyK2NuV zxOM10;chqO<>XW?Sv>-`rzONQxV;BXbz=g`J?>jB7dIalO~Agb`?yZ4GZgk^ASC4n zyx#}fK9zLYJTx>kHWro=ri!jEI=)3N70uVLCFSKi zOEtS8Xe4ZDGPYb^-OP5bF`nh@TH*s5A-$=YamUp>Et|7nphC%MKVx(J-^f9$0`YS> z;{*%jLE#ZHs@@+Os;a7@ZcWQpKF>*uYfmtwPMf$`=u#vSV&Z?2l4b`DpR2UnTg-3& zl%H97p#4Pd<%I!KH-XALTUb6E5PgTmiEuU4{4;OiXwPK}=&--1r0x2!OHiJ`RKS(L%#$#aE@)aSJ9` zr<1w;r|UfMP(T2jE>>jA6qf1O_=DK??n!c90LX?C6K|+pg7CSyWSQ<31FLl=jphj$ z#Mlojw2Ts>LAQZl#QMd?|FRdL35&=&wWxn!k@)g@EluI92v{;5Rj97cQJPL21BGkU zu#JqFj(F;AeYYkB&;dj|^&Gf&08p6lj6eR1+m>HQ=ZlAko140@uuPOVJ+%dlTa(kl z-SNrE3Gw6FF1rC(QEi5x!otD1p1UOT`U$0fkca02g;7I#tr*5f8O;*nl`R)zDf+;P z-lWdd*mRZ)0wA7;E*zVbL`1Y6DaYlzZRk{I;?a&u3Juu1>ik+<*h0fgR<3fIk90Wk zPfiZud$6*~pV#7lx$`OKB+m_TB_to{K%;&t5p^?lL&GwWkdNclqQ}FsMeWg1*XGdl z^fho_cP83=dIx4|Z@|+%0sF(zMur^D=w&qzI3bCb(Ni<~)|gbhYWPDyEZ*F}=*dQ^ zRJ~rjdw-I=K7QJ7wm(WA?n$!oGY}76(`z+u&gQ`hZ`Ig;!8h|<;t9aeqEx_i-n%j= znneKEaS}?z5EfFEsu)^UVua2q_T9#yzQ11zd=g8^j273ZE5>V`-g~?#YI|9^xJ-10 z#1w*K4Gb&`UkRAim(L!$x&SY8Mu=RlA8+7Flf%7wD?Ewyzsd?GHh3h9kKG}LT7Ali zNN(;J7PRk{z}J49&!Gs)1F5!7wW^BMf1Mnz>_K*5;QiYFH42}@!>AA5H8U}Bk7L6l zjbga<@`T;!3dH@M14jZJ6Rja{5<-lBsm0jXc8`uL^%>(vn?zIz0V|f)>&qAL*!a)eCpxY&%CUnk4}AeXf0a zT1BLI$f4tY_aP%exAA$of83M_ACHOh5#`oWRegYhf;G3D9fv&?(NL>0F)^8AXR==D z>#Nt-bzVAuefXFn`}SK;hEb>a<*LiSStI%M)+wIiJIiE)oK?Ye@g-FahwZe(B-&FcwY_#hY0-0l(3lz1+v{WZhBpax@tRFzSU`jvSpKXu+Gb7bcYziF3|$omqUsg@ z+C6=JZtoY{k_jO!Wg7w*y)4iPEE_cIYAXi@`t7@50Qw~**x&V-LRAvg%o@1EXlP_5 zVltoseXKEHt$!q^38z=Yk@$DKf&0|eYw?`*+2m87iHehnhvzYb#KrYwhK*O*=~LFx z{P^;o0^3#2Cd~jz{$2E9S1fEh3*OVpLjlNm6sQFI@mKBQu zZlykANPK((0f!Bt;f|a^o+Jw+k4)L@O+ON|8S6<55#P$~hNnXF@-|MN)A8CiYT`dR zTX~sWN3Fw3y~Y6af^@ni=32Q?BDtkz>9)@C*~&dHJf5i=`ZD zi!CZD%5J_US;h9W@fdh=N;1EkC0I6VUayJJi7BkkV=WH^lsM{5!$Cm{J zmqDsIt2zc2aMrYYfoZ#sQRVM3iT-*2gRO0hRUZX_IB77Zg`{7}=NkY_S(2m%ehP2o z;L;K7vxKyl+JCi7e%s|SC9(e@nSTD01bE}AsH>R7YsUX}0|gn`x$C-44nl{F9iWiM z5OkiULl*`>3PJ!ZlPmKaTh^I_IM-s~&eo7#S#EFSdGSsM7|AEXyF%TGgcin~SKSs5 zTt59n$5Y-#CkIY4>CxBZA%LXeCS}N&?auI!0FWp^9{_rU=Y>v2CiqgUdigsC0lJRhL;&c5V>NxT#FSwmzo7&;$Rl)7>r$=UsrM705HxyFY#i3K zn&3J|xwqwC+4bZ{3edu0sj==OT(fPdr`7r2H76EPfUqAZXh=z1yudH>rj<645=~zP z!+4^vVtR^9j`nc*1ah98^Fp@cM3W#0XmlV1>~3Kj;-lBJw&{~DwccMt6B;{cdXQ?E zO~DJc=kThIcC@ZsQ6(l7rA0kOQD+=517|5`FOUxIi!<=Hg%SngrT#(aCjVsd2}fM1 zs?QR9s8GX;o{Fz93ngX$yCEl+zx5wJ|37n}Z21Q{n3{8exsvgA&6o;LRTvg*zjsrN zsx~vIO}XOH`*8{wk5nlGK=mFXw@c~`nkWFlhCtZFPX0F-KojA_S~*?FIL*IBH2Omm zX68HLop2+goe1GZmZn&W$_0vgx!Pqq)iM$E(9NLT(x3$?)7e@0o`N2GDXvATc!jI| z=+#!$;csWy&Tpdo$#4 zfqr&lxHyY<{f9NNTdPtm8`omX?0XAegJRc@0hqxjjh!Aj%~qTKUwU8e;h9csuW0X1 zIj)Mbe40{45zpk{OhH~5>2W`})Xv`bN8ZqSxSg#YrbHkV6o5T{<1ub)ehtE*SU)u~W$=?VR03HNm}Wo=9Rj1tu~IIia+AohCd4r8o(x#`6d50qola(93J%XTW4 z$*ZEIl#sGyu{VUS)9TVJ7ks(tJC(_|Iohn|GePj}a3t$N=kKHL==E*`tjNNpulmi+ zorm?$(Wj}oe=kcZj<%E1qM)WtC=9}AV!nrYHNC^VJ#kUdNaFV+D73rg;j-8O#>Q4s zk!SNx%+%4$j7Hca7NC>2JG}PYAoeUil>d{7KdGX+VawR-P^PLCe&+ z5=yqwsonw!p{iBs>eL!7*G=-zcX+>s--LtZ%Kf?Hr>sJ7Z0A!hr(|Qt`;N}wzxS)d z0lgWI0(MXP5g>O#Q~l2JBfG#-r>$~cb#Bj&AdwtMLDh6J({uM;&6%4B0Q$dytp_tD$4sIwdj}OUnl^4z?0$q zO6SK5(x6K3Z&Y+zUP@+0#?RAxf|;2a$#{!JhWpeaQ)n0%6ntJ}0F(X}5YYA5>MDg} zGO|b6@owX4ZoYhR+0pFd&{6Lc%*+BksA7uxw(@KAn{06y6)mIAmH$6SPmE$(BnSJ3 z1)zCLy_49ehAq6qQmygo5_636=?WGAh=uk1<~TWphLz|Slr9y&2ClR1ylm90h~eiB z$8JdRGEyad&X3$|ABSX4yt7?JgX`eY=5%@z(U?CeuF(~){~>7S~XtB@n1>6*rr{5_0|VN;>DTm+v#lCsor`}H}!K? zO|L>Cbme_r4$yUR>2mR5Q?%HVUtmh7*|gPa>ne#fqSZDUkxt8~rx+Z3kjYQXalqU_ zy`-Y5$$1N=1`3sib#sQHCEx6;Hw`+9{F|Gv%&0gFx+iPRPy#wXAu${_YHrgaBO}4~ ze(c;Pnba+pd9`)?4PbPweW`?x6fJ*01t6?^yUM&^@TyN|%OgYTv0Is%&!Ol-$@dOjN*)+dRfp>~1YS5JKi zAs-*fa&UkjS^R9gyxMsRXn4F=H~X|sFCPM^KT_X!LptTUPJ@ zOIhiU&)J?1<2dxbF-)_DipH`b;mGJH6cp6+F$M-O@z%EUo!|K+e`rWDu$$>PEKGM_ zNq#u=RU+Kgsf>V;CH?T>8a+fl|7#xy2Q>6IiUOnbH*)r`3z#!Q`($yW|2`W9HoaZk zPL~QXyaECti{#UIy;t@|Mn-I1&UM?2mOULeApn@kiM+3C5l*|&zyM%NY7jKc^dNr2 z%CXbTU_pVgLLB;?eO@tD>UFYAa+O!R&+dGgnxzHZf0qZ=@KU(GB7VWf*Zh=>QbUCX za8b&`LPS#0a!h8J7E^!wq;WZ(5-|QFSJjTcRuSJAZ+SqjV+;Aui_A5P2`9e5%kP8XB7KYsDfNIr&rYHdDTQZ;vn%BGO+r zOIW}VBNY(r+xFM-#(Cl>zUBwFuz}qc4RT&yG#L=WLu1qmDJ>1#l~w5t%*;%bUjp5R zX{!wWV6-ozLaKz63WacNvfg`UI}LJp5aKDvS`m{Elp1@z)$CF}d5arj023U+z^Uuw zb9*p7CUYb32g6rk2(C3Fx0oXnf0>N#YA2W+vu7SZVL{&^{?FL=5K}&`7VFakUE8e3 zkC5YIJk*f9+FFOfXq{{O8mAW#v5Y* zUSPTC^L19Bc9n=bL#{#<2Meo8^FEkIL|+Lo|QEr4IM7# zPdDZ*7qBofRn^q0bRJdS_jjv&^QS5Q; z5Jkt4|9*L?Igz@G$_SCt-c>v;Yy?S%BT~mJ-`)Ko4**pf8Q+tzK50&1E%V79-J>nc z7Yho>J;=yMHn)o8l8Jv48?1k`e{8g;*JL_GoOK{(ap`PhCFtm!zCu^W=onRBq1uag8`0oq})>>vjL3R^N+RZ`0R($F-9tR zwlN<>t65K0yBvt7m5q}3`^Ayi(oos@#&t;=7)$wEchh~l?_7uP0OrJRH-wvJPBE!yn4YDtTa z3EXUr*5f8?bSG>5DaW>4XwXJhD*(e5KEAY?Y5v>&H6tLqe$4A;Pb&0hgvm5)o={xf zk726o(K;5`HuVJ@{PAVsvK|K&M zGUA-Y+;$F_kaW;PKP4+>VQ^9KGvw?@PkA&ZX8x0*4fVXu^6RQa6-0Pzc*_f zes|awPON2#rjpu)s6qx~a_ON7k3B<#<|cAQ|9^;sTy`mo9{L{u`2q6&r>LFUL;V>k zO5FZOL-*Y{qSQ*z|J{Rvy^VIe*7=X5a(+YNioXR@V0kG>k_K1C_~tKxf$8qkV{taK^cK*(XmA?e8`Ncpo-BvZYH%T(y{)#doAv z9Y8NE@*^YQV=Cq^dmn`Uo) Edit Menu -If the menu item you are looking for is missing, please see Edit Menu of the &kde; Fundamentals. +If the menu item you are looking for is missing, please see Edit Menu of the &kde; Fundamentals. The items listed here are &kmail; specific. @@ -1175,7 +1175,7 @@ Settings Menu -If the menu item you are looking for is missing, please see Settings Menu of the &kde; Fundamentals. +If the menu item you are looking for is missing, please see Settings Menu of the &kde; Fundamentals. The items listed here are &kmail; specific. @@ -1237,7 +1237,7 @@ Help Menu - + Help Menu of the &kde; Fundamentals. @@ -1372,7 +1372,7 @@ Edit Menu -If the menu item you are looking for is missing, please see Edit Menu of the &kde; Fundamentals. +If the menu item you are looking for is missing, please see Edit Menu of the &kde; Fundamentals. The items listed here are &kmail; specific. @@ -1708,7 +1708,7 @@ Tools Menu -If the menu item you are looking for is missing, please see Tools Menu of the &kde; Fundamentals. +If the menu item you are looking for is missing, please see Tools Menu of the &kde; Fundamentals. The items listed here are &kmail; specific. @@ -1738,7 +1738,7 @@ Settings Menu -If the menu item you are looking for is missing, please see Settings Menu of the &kde; Fundamentals. +If the menu item you are looking for is missing, please see Settings Menu of the &kde; Fundamentals. The items listed here are &kmail; specific. @@ -1756,7 +1756,7 @@ Help Menu -Help Menu of the &kde; Fundamentals. +Help Menu of the &kde; Fundamentals. diff --git a/kmail-refresh-settings/CMakeLists.txt b/kmail-refresh-settings/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/kmail-refresh-settings/CMakeLists.txt @@ -0,0 +1,21 @@ +set(kmail-refresh-settings_SRCS + main.cpp + refreshsettingsassistant.cpp + refreshsettringsfinishpage.cpp + refreshsettingscleanuppage.cpp + refreshsettingsfirstpage.cpp + ) + +ecm_qt_declare_logging_category(kmail-refresh-settings_SRCS HEADER kmail-refresh-settings_debug.h IDENTIFIER KMAIL_REFRESH_SETTINGS_LOG CATEGORY_NAME org.kde.pim.kmail_refresh_settings + DESCRIPTION "kmail-refresh-settings" + EXPORT KMAIL + ) + + +add_executable(kmail-refresh-settings ${kmail-refresh-settings_SRCS}) +target_link_libraries(kmail-refresh-settings KF5::I18n KF5::AkonadiWidgets KF5::DBusAddons KF5::Crash KF5::XmlGui) + + +install(TARGETS kmail-refresh-settings ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) +install(PROGRAMS org.kde.kmail-refresh-settings.desktop DESTINATION ${KDE_INSTALL_APPDIR}) + diff --git a/kmail-refresh-settings/Messages.sh b/kmail-refresh-settings/Messages.sh new file mode 100644 --- /dev/null +++ b/kmail-refresh-settings/Messages.sh @@ -0,0 +1,2 @@ +#! /bin/sh +$XGETTEXT `find . -name "*.cpp" -o -name "*.h"` -o $podir/kmail-refresh-settings.pot diff --git a/kmail-refresh-settings/main.cpp b/kmail-refresh-settings/main.cpp new file mode 100644 --- /dev/null +++ b/kmail-refresh-settings/main.cpp @@ -0,0 +1,67 @@ +/* + Copyright (C) 2019-2020 Laurent Montel + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "refreshsettingsassistant.h" + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); + QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true); + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); + QApplication app(argc, argv); + KLocalizedString::setApplicationDomain("kmail-refresh-settings"); + KCrash::initialize(); + KAboutData aboutData(QStringLiteral("kmail-refresh-settings"), + i18n("KMail Assistant for refreshing settings"), + QStringLiteral("0.1"), + i18n("KMail Assistant for refreshing settings"), + KAboutLicense::LGPL, + i18n("(c) 2019-2020 Laurent Montel ")); + aboutData.addAuthor(i18n("Laurent Montel"), i18n("Author"), QStringLiteral("montel@kde.org")); + + app.setOrganizationDomain(QStringLiteral("kde.org")); + app.setWindowIcon(QIcon::fromTheme(QStringLiteral("kontact"))); + QCommandLineParser parser; + KAboutData::setApplicationData(aboutData); + + aboutData.setupCommandLine(&parser); + parser.process(app); + aboutData.processCommandLine(&parser); + + KDBusService service(KDBusService::Unique); + + Akonadi::ControlGui::start(nullptr); + + RefreshSettingsAssistant dlg(nullptr); + dlg.show(); + return app.exec(); +} diff --git a/kmail-refresh-settings/org.kde.kmail-refresh-settings.desktop b/kmail-refresh-settings/org.kde.kmail-refresh-settings.desktop new file mode 100755 --- /dev/null +++ b/kmail-refresh-settings/org.kde.kmail-refresh-settings.desktop @@ -0,0 +1,90 @@ +[Desktop Entry] +Name=KMail Refresh Settings +Name[ca]=Actualització dels ajustaments del KMail +Name[ca@valencia]=Actualització dels ajustaments del KMail +Name[cs]=Obnovení nastavení KMailu +Name[de]=Erneuerung der Einstellungen für KMail +Name[en_GB]=KMail Refresh Settings +Name[es]=Preferencias de refresco de KMail +Name[et]=KMaili värskendamise seadistused +Name[eu]=KMail freskatu ezarpenak +Name[fi]=KMailin asetusten virkistys +Name[fr]=Rafraîchissement des paramètres de KMail +Name[gl]=Configuración de actualización de KMail +Name[ia]=KMail Refresh Settings (Refresca preferentias de KMail) +Name[it]=Rinnovo delle impostazioni di KMail +Name[ko]=KMail 설정 초기화 +Name[nl]=Vernieuwen van instellingen van KMail +Name[pl]=Odświeżanie ustawień KMaila +Name[pt]=Actualização da Configuração do KMail +Name[pt_BR]=Atualizar configurações do KMail +Name[ru]=Удаление неиспользуемых параметров KMail +Name[sk]=KMail Obnoviť Nastavenia +Name[sl]=Osvežite nastavitve KMail +Name[sv]=Kmail uppdatera inställningar +Name[uk]=Оновлення параметрів KMail +Name[x-test]=xxKMail Refresh Settingsxx +Name[zh_CN]=KMail 刷新设置 +Type=Application +Exec=kmail-refresh-settings -qwindowtitle %c %u +Icon=kmail +X-DocPath=kmail2/index.html +GenericName=KMail refresh settings +GenericName[ca]=Actualització dels ajustaments del KMail +GenericName[ca@valencia]=Actualització dels ajustaments del KMail +GenericName[cs]=Obnovení nastavení KMailu +GenericName[de]=Erneuerung der Einstellungen für KMail +GenericName[en_GB]=KMail refresh settings +GenericName[es]=Preferencias de refresco de KMail +GenericName[et]=KMaili värskendamise seadistused +GenericName[eu]=KMail freskatu ezarpenak +GenericName[fi]=KMailin asetusten virkistys +GenericName[fr]=Rafraîchissement des paramètres de KMail +GenericName[gl]=Configuración de actualización de KMail +GenericName[ia]=KMail Refresh Settings (Refresca preferentias de KMail) +GenericName[it]=Rinnovo delle impostazioni di KMail +GenericName[ko]=KMail 설정 초기화 +GenericName[nl]=Instellingen van vernieuwen KMail +GenericName[pl]=Odświeżanie ustawień KMaila +GenericName[pt]=Actualização da Configuração do KMail +GenericName[pt_BR]=Atualizar configurações do KMail +GenericName[ru]=Удаление неиспользуемых параметров KMail +GenericName[sk]=KMail obnoviť nastavenia +GenericName[sl]=Osvežite nastavitve KMail +GenericName[sv]=Kmail uppdatera inställningar +GenericName[uk]=Оновити параметри KMail +GenericName[x-test]=xxKMail refresh settingsxx +GenericName[zh_CN]=KMail 刷新设置 +Comment=Refresh KMail settings +Comment[ca]=Actualitza els ajustaments del KMail +Comment[ca@valencia]=Actualitza els ajustaments del KMail +Comment[cs]=Obnovit nastavení KMailu +Comment[de]=Erneuerung der Einstellungen für KMail +Comment[en_GB]=Refresh KMail settings +Comment[es]=Refrescar preferencias de KMail +Comment[et]=KMaili seadistuste värskendamine +Comment[eu]=Freskatu KMail ezarpenak +Comment[fi]=Virkistä KMail-asetukset +Comment[fr]=Rafraîchir les paramètres de KMail +Comment[gl]=Configuración de actualización de KMail +Comment[ia]=Refresca Preferentias del KMail +Comment[it]=Rinnova le impostazioni di KMail +Comment[ko]=KMail 설정 초기화 +Comment[nl]=KMail-instellingen vernieuwen +Comment[pl]=Ustawienia odświeżania KMaila +Comment[pt]=Actualizar a configuração do KMail +Comment[pt_BR]=Atualizar configurações do KMail +Comment[ru]=Удаление неиспользуемых параметров KMail +Comment[sk]=Obnoviť KMail nastavenia +Comment[sl]=Osvežite nastavitve KMail +Comment[sv]=Uppdatera Kmail-inställningar +Comment[uk]=Оновлення параметрів KMail +Comment[x-test]=xxRefresh KMail settingsxx +Comment[zh_CN]=刷新 KMail 设置 +Terminal=false +StartupNotify=true +X-DBUS-StartupType=Unique +X-DBUS-ServiceName=org.kde.kmail-refresh-settings +Categories=Qt;KDE;Office;Network;Email; +InitialPreference=10 +Hidden=true diff --git a/kmail-refresh-settings/refreshsettingsassistant.h b/kmail-refresh-settings/refreshsettingsassistant.h new file mode 100644 --- /dev/null +++ b/kmail-refresh-settings/refreshsettingsassistant.h @@ -0,0 +1,47 @@ +/* + Copyright (C) 2019-2020 Laurent Montel + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef REFRESHSETTINGSASSISTANT_H +#define REFRESHSETTINGSASSISTANT_H + +#include +class RefreshSettingsCleanupPage; +class RefreshSettingsFirstPage; +class RefreshSettringsFinishPage; +class RefreshSettingsAssistant : public KAssistantDialog +{ + Q_OBJECT +public: + explicit RefreshSettingsAssistant(QWidget *parent = nullptr); + ~RefreshSettingsAssistant(); + +private: + void initializePages(); + void cleanUpDone(); + KPageWidgetItem *mCleanUpPageItem = nullptr; + RefreshSettingsCleanupPage *mCleanUpPage = nullptr; + + KPageWidgetItem *mFirstPageItem = nullptr; + RefreshSettingsFirstPage *mFirstPage = nullptr; + + KPageWidgetItem *mFinishPageItem = nullptr; + RefreshSettringsFinishPage *mFinishPage = nullptr; +}; + +#endif // REFRESHSETTINGSASSISTANT_H diff --git a/kmail-refresh-settings/refreshsettingsassistant.cpp b/kmail-refresh-settings/refreshsettingsassistant.cpp new file mode 100644 --- /dev/null +++ b/kmail-refresh-settings/refreshsettingsassistant.cpp @@ -0,0 +1,72 @@ +/* + Copyright (C) 2019-2020 Laurent Montel + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "refreshsettingsassistant.h" +#include "refreshsettingscleanuppage.h" +#include "refreshsettingsfirstpage.h" +#include "refreshsettringsfinishpage.h" +#include +#include +#include +#include +#include +#include + +RefreshSettingsAssistant::RefreshSettingsAssistant(QWidget *parent) + : KAssistantDialog(parent) +{ + setModal(true); + setWindowTitle(i18nc("@title:window", "KMail Refresh Settings")); + setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Help); + resize(640, 480); + Akonadi::ControlGui::widgetNeedsAkonadi(this); + initializePages(); + KHelpMenu *helpMenu = new KHelpMenu(this, KAboutData::applicationData(), true); + //Initialize menu + QMenu *menu = helpMenu->menu(); + helpMenu->action(KHelpMenu::menuAboutApp)->setIcon(QIcon::fromTheme(QStringLiteral("kmail"))); + button(QDialogButtonBox::Help)->setMenu(menu); +} + +RefreshSettingsAssistant::~RefreshSettingsAssistant() +{ +} + +void RefreshSettingsAssistant::initializePages() +{ + mFirstPage = new RefreshSettingsFirstPage(this); + mFirstPageItem = new KPageWidgetItem(mFirstPage, i18n("Warning")); + addPage(mFirstPageItem); + + mCleanUpPage = new RefreshSettingsCleanupPage(this); + mCleanUpPageItem = new KPageWidgetItem(mCleanUpPage, i18n("Clean up Settings")); + addPage(mCleanUpPageItem); + + mFinishPage = new RefreshSettringsFinishPage(this); + mFinishPageItem = new KPageWidgetItem(mFinishPage, i18n("Finish")); + addPage(mFinishPageItem); + + connect(mCleanUpPage, &RefreshSettingsCleanupPage::cleanDoneInfo, mFinishPage, &RefreshSettringsFinishPage::cleanDoneInfo); + connect(mCleanUpPage, &RefreshSettingsCleanupPage::cleanUpDone, this, &RefreshSettingsAssistant::cleanUpDone); +} + +void RefreshSettingsAssistant::cleanUpDone() +{ + next(); +} diff --git a/src/editor/widgets/cryptostateindicatorwidget.h b/kmail-refresh-settings/refreshsettingscleanuppage.h copy from src/editor/widgets/cryptostateindicatorwidget.h copy to kmail-refresh-settings/refreshsettingscleanuppage.h --- a/src/editor/widgets/cryptostateindicatorwidget.h +++ b/kmail-refresh-settings/refreshsettingscleanuppage.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,30 +17,31 @@ Boston, MA 02110-1301, USA. */ -#ifndef CRYPTOSTATEINDICATORWIDGET_H -#define CRYPTOSTATEINDICATORWIDGET_H +#ifndef REFRESHSETTINGSCLEANUPPAGE_H +#define REFRESHSETTINGSCLEANUPPAGE_H #include -class QLabel; +#include -class CryptoStateIndicatorWidget : public QWidget +class RefreshSettingsCleanupPage : public QWidget { Q_OBJECT public: - explicit CryptoStateIndicatorWidget(QWidget *parent = nullptr); - ~CryptoStateIndicatorWidget(); + explicit RefreshSettingsCleanupPage(QWidget *parent = nullptr); + ~RefreshSettingsCleanupPage(); - void updateSignatureAndEncrypionStateIndicators(bool isSign, bool isEncrypted); - - void setShowAlwaysIndicator(bool status); +Q_SIGNALS: + void cleanDoneInfo(const QString &msg); + void cleanUpDone(); private: - void updateShowAlwaysIndicator(); - QLabel *mSignatureStateIndicator = nullptr; - QLabel *mEncryptionStateIndicator = nullptr; - bool mShowAlwaysIndicator = true; - bool mIsSign = false; - bool mIsEncrypted = false; + void cleanSettings(); + void cleanupFolderSettings(KConfigGroup &oldGroup); + void initCleanupFolderSettings(const QString &configName); + void initCleanupFiltersSettings(const QString &configName); + void initCleanDialogSettings(const QString &configName); + void removeTipOfDay(const QString &configName); + void initCleanupDialogSettings(const QString &configName); }; -#endif // CRYPTOSTATEINDICATORWIDGET_H +#endif // REFRESHSETTINGSCLEANUPPAGE_H diff --git a/kmail-refresh-settings/refreshsettingscleanuppage.cpp b/kmail-refresh-settings/refreshsettingscleanuppage.cpp new file mode 100644 --- /dev/null +++ b/kmail-refresh-settings/refreshsettingscleanuppage.cpp @@ -0,0 +1,156 @@ +/* + Copyright (C) 2019-2020 Laurent Montel + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "refreshsettingscleanuppage.h" +#include +#include +#include +#include +#include +#include + +RefreshSettingsCleanupPage::RefreshSettingsCleanupPage(QWidget *parent) + : QWidget(parent) +{ + QHBoxLayout *mainLayout = new QHBoxLayout(this); + mainLayout->setObjectName(QStringLiteral("mainLayout")); + mainLayout->setContentsMargins(0, 0, 0, 0); + QPushButton *button = new QPushButton(i18n("Clean"), this); + button->setObjectName(QStringLiteral("button")); + mainLayout->addWidget(button); + connect(button, &QPushButton::clicked, this, &RefreshSettingsCleanupPage::cleanSettings); +} + +RefreshSettingsCleanupPage::~RefreshSettingsCleanupPage() +{ +} + +void RefreshSettingsCleanupPage::cleanSettings() +{ + const QStringList configNameFiles {QStringLiteral("kmail2rc"), QStringLiteral("kontactrc")}; + for (const QString &configName: configNameFiles) { + initCleanupFolderSettings(configName); + initCleanupFiltersSettings(configName); + initCleanDialogSettings(configName); + initCleanupDialogSettings(configName); + removeTipOfDay(configName); + } + Q_EMIT cleanUpDone(); +} + +void RefreshSettingsCleanupPage::removeTipOfDay(const QString &configName) +{ + KSharedConfigPtr settingsrc = KSharedConfig::openConfig(configName); + + const QString tipOfDayStr = QStringLiteral("TipOfDay"); + if (settingsrc->hasGroup(tipOfDayStr)) { + settingsrc->deleteGroup(tipOfDayStr); + } + settingsrc->sync(); + Q_EMIT cleanDoneInfo(i18n("Remove obsolete \"TipOfDay\" settings: Done")); +} + +void RefreshSettingsCleanupPage::initCleanDialogSettings(const QString &configName) +{ + KSharedConfigPtr settingsrc = KSharedConfig::openConfig(configName); + + const QStringList dialogList = settingsrc->groupList().filter(QRegularExpression(QStringLiteral(".*Dialog$"))); + for (const QString &str : dialogList) { + settingsrc->deleteGroup(str); + } + settingsrc->sync(); + Q_EMIT cleanDoneInfo(i18n("Delete Dialog settings in file `%1`: Done", configName)); +} + +void RefreshSettingsCleanupPage::initCleanupFiltersSettings(const QString &configName) +{ + KSharedConfigPtr settingsrc = KSharedConfig::openConfig(configName); + + const QStringList filterList = settingsrc->groupList().filter(QRegularExpression(QStringLiteral("Filter #\\d+"))); + for (const QString &str : filterList) { + settingsrc->deleteGroup(str); + } + settingsrc->sync(); + Q_EMIT cleanDoneInfo(i18n("Delete Filters settings in file `%1`: Done", configName)); +} + +void RefreshSettingsCleanupPage::initCleanupFolderSettings(const QString &configName) +{ + KSharedConfigPtr settingsrc = KSharedConfig::openConfig(configName); + + const QStringList folderList = settingsrc->groupList().filter(QRegularExpression(QStringLiteral("Folder-\\d+"))); + for (const QString &str : folderList) { + KConfigGroup oldGroup = settingsrc->group(str); + cleanupFolderSettings(oldGroup); + } + settingsrc->sync(); + Q_EMIT cleanDoneInfo(i18n("Clean Folder Settings in setting file `%1`: Done", configName)); +} + +void RefreshSettingsCleanupPage::cleanupFolderSettings(KConfigGroup &oldGroup) +{ + const bool mailingListEnabled = oldGroup.readEntry("MailingListEnabled", false); + if (!mailingListEnabled) { + oldGroup.deleteEntry("MailingListEnabled"); + } + const int mailingListFeatures = oldGroup.readEntry("MailingListFeatures", 0); + if (mailingListFeatures == 0) { + oldGroup.deleteEntry("MailingListFeatures"); + } + const int mailingListHandler = oldGroup.readEntry("MailingListHandler", 0); + if (mailingListHandler == 0) { + oldGroup.deleteEntry("MailingListHandler"); + } + const QString mailingListId = oldGroup.readEntry("MailingListId"); + if (mailingListId.isEmpty()) { + oldGroup.deleteEntry("MailingListId"); + } + + const bool putRepliesInSameFolder = oldGroup.readEntry("PutRepliesInSameFolder", false); + if (!putRepliesInSameFolder) { + oldGroup.deleteEntry("PutRepliesInSameFolder"); + } + + const bool folderHtmlLoadExtPreference = oldGroup.readEntry("htmlLoadExternalOverride", false); + if (!folderHtmlLoadExtPreference) { + oldGroup.deleteEntry("htmlLoadExternalOverride"); + } + const bool useDefaultIdentity = oldGroup.readEntry("UseDefaultIdentity", false); + if (useDefaultIdentity) { + oldGroup.deleteEntry("UseDefaultIdentity"); + } +} + +void RefreshSettingsCleanupPage::initCleanupDialogSettings(const QString &configName) +{ + KSharedConfigPtr settingsrc = KSharedConfig::openConfig(configName); + + const QStringList dialogListName{QStringLiteral("AddHostDialog"), + QStringLiteral("AuditLogViewer"), + QStringLiteral("CollectionPropertiesDialog"), + QStringLiteral("MailSourceWebEngineViewer"), + QStringLiteral("SelectAddressBookDialog"), + QStringLiteral("VCardViewer")}; + for (const QString &str : dialogListName) { + KConfigGroup oldGroup = settingsrc->group(str); + cleanupFolderSettings(oldGroup); + } + settingsrc->sync(); + Q_EMIT cleanDoneInfo(i18n("Clean Dialog Size in setting file `%1`: Done", configName)); +} diff --git a/agents/mailfilteragent/config/configurewidget.h b/kmail-refresh-settings/refreshsettingsfirstpage.h rename from agents/mailfilteragent/config/configurewidget.h rename to kmail-refresh-settings/refreshsettingsfirstpage.h --- a/agents/mailfilteragent/config/configurewidget.h +++ b/kmail-refresh-settings/refreshsettingsfirstpage.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -16,17 +16,18 @@ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef CONFIGUREWIDGET_H -#define CONFIGUREWIDGET_H + +#ifndef REFRESHSETTINGSFIRSTPAGE_H +#define REFRESHSETTINGSFIRSTPAGE_H #include -class ConfigureWidget : public QWidget +class RefreshSettingsFirstPage : public QWidget { Q_OBJECT public: - explicit ConfigureWidget(QWidget *parent = nullptr); - ~ConfigureWidget(); + explicit RefreshSettingsFirstPage(QWidget *parent = nullptr); + ~RefreshSettingsFirstPage(); }; -#endif // CONFIGUREWIDGET_H +#endif // REFRESHSETTINGSFIRSTPAGE_H diff --git a/src/widgets/statusbarlabeltoggledstate.h b/kmail-refresh-settings/refreshsettingsfirstpage.cpp rename from src/widgets/statusbarlabeltoggledstate.h rename to kmail-refresh-settings/refreshsettingsfirstpage.cpp --- a/src/widgets/statusbarlabeltoggledstate.h +++ b/kmail-refresh-settings/refreshsettingsfirstpage.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,34 +17,26 @@ Boston, MA 02110-1301, USA. */ -#ifndef STATUSBARLABELTOGGLEDSTATE_H -#define STATUSBARLABELTOGGLEDSTATE_H - +#include "refreshsettingsfirstpage.h" #include +#include +#include -class StatusBarLabelToggledState : public QLabel +RefreshSettingsFirstPage::RefreshSettingsFirstPage(QWidget *parent) + : QWidget(parent) { - Q_OBJECT -public: - explicit StatusBarLabelToggledState(QWidget *parent = nullptr); - ~StatusBarLabelToggledState() override; - - void setToggleMode(bool state); - - bool toggleMode() const; - - void setStateString(const QString &toggled, const QString &untoggled); -Q_SIGNALS: - void toggleModeChanged(bool state); - -protected: - void mousePressEvent(QMouseEvent *ev) override; - -private: - void updateLabel(); - QString mToggled; - QString mUnToggled; - bool mToggleMode = false; -}; - -#endif // STATUSBARLABELTOGGLEDSTATE_H + QHBoxLayout *mainLayout = new QHBoxLayout(this); + mainLayout->setObjectName(QStringLiteral("mainLayout")); + mainLayout->setContentsMargins(0, 0, 0, 0); + QLabel *label = new QLabel(i18n("Please close KMail/Kontact before using it.")); + QFont f = label->font(); + f.setBold(true); + f.setPointSize(22); + label->setFont(f); + label->setObjectName(QStringLiteral("label")); + mainLayout->addWidget(label, 0, Qt::AlignHCenter); +} + +RefreshSettingsFirstPage::~RefreshSettingsFirstPage() +{ +} diff --git a/src/tests/searchdbustest.h b/kmail-refresh-settings/refreshsettringsfinishpage.h copy from src/tests/searchdbustest.h copy to kmail-refresh-settings/refreshsettringsfinishpage.h --- a/src/tests/searchdbustest.h +++ b/kmail-refresh-settings/refreshsettringsfinishpage.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2016-2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,19 +17,24 @@ Boston, MA 02110-1301, USA. */ -#ifndef SEARCHDBUSTEST_H -#define SEARCHDBUSTEST_H +#ifndef REFRESHSETTRINGSFINISHPAGE_H +#define REFRESHSETTRINGSFINISHPAGE_H #include - -class searchdbustest : public QWidget +class QPlainTextEdit; +class RefreshSettringsFinishPage : public QWidget { Q_OBJECT public: - explicit searchdbustest(QWidget *parent = nullptr); - ~searchdbustest() = default; -private Q_SLOTS: - void slotReindexCollections(); + explicit RefreshSettringsFinishPage(QWidget *parent = nullptr); + ~RefreshSettringsFinishPage(); + +Q_SIGNALS: + void cleanDoneInfo(const QString &info); + +private: + void slotCleanDoneInfo(const QString &info); + QPlainTextEdit *mTextEdit = nullptr; }; -#endif // SEARCHDBUSTEST_H +#endif // REFRESHSETTRINGSFINISHPAGE_H diff --git a/kmail-refresh-settings/refreshsettringsfinishpage.cpp b/kmail-refresh-settings/refreshsettringsfinishpage.cpp new file mode 100644 --- /dev/null +++ b/kmail-refresh-settings/refreshsettringsfinishpage.cpp @@ -0,0 +1,46 @@ +/* + Copyright (C) 2019-2020 Laurent Montel + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "refreshsettringsfinishpage.h" +#include +#include +#include + +RefreshSettringsFinishPage::RefreshSettringsFinishPage(QWidget *parent) + : QWidget(parent) +{ + QHBoxLayout *mainLayout = new QHBoxLayout(this); + mainLayout->setObjectName(QStringLiteral("mainLayout")); + mainLayout->setContentsMargins(0, 0, 0, 0); + + mTextEdit = new QPlainTextEdit(this); + mTextEdit->setObjectName(QStringLiteral("textedit")); + mTextEdit->setReadOnly(true); + mainLayout->addWidget(mTextEdit); + connect(this, &RefreshSettringsFinishPage::cleanDoneInfo, this, &RefreshSettringsFinishPage::slotCleanDoneInfo); +} + +RefreshSettringsFinishPage::~RefreshSettringsFinishPage() +{ +} + +void RefreshSettringsFinishPage::slotCleanDoneInfo(const QString &str) +{ + mTextEdit->insertPlainText(str + QLatin1Char('\n')); +} diff --git a/kmail.categories b/kmail.categories deleted file mode 100644 --- a/kmail.categories +++ /dev/null @@ -1,7 +0,0 @@ -org.kde.pim.kmail kmail (kmail) IDENTIFIER [KMAIL_LOG] -org.kde.pim.sendlateragent kmail (sendlateragent) IDENTIFIER [SENDLATERAGENT_LOG] -org.kde.pim.archivemailagent kmail (archivemailagent) IDENTIFIER [ARCHIVEMAILAGENT_LOG] -org.kde.pim.followupreminderagent kmail (followupreminderagent) IDENTIFIER [FOLLOWUPREMINDERAGENT_LOG] -org.kde.pim.kmail_plugin kmail (kmail kontact plugins) IDENTIFIER [KMAILPLUGIN_LOG] -org.kde.pim.mailfilteragent kmail (mailfilter agent) IDENTIFIER [MAILFILTERAGENT_LOG] -org.kde.pim.unifiedmailboxagent kmail (unifiedmailboxagent) IDENTIFIER [UNIFIEDMAILBOXAGENT_LOG] diff --git a/kmail.renamecategories b/kmail.renamecategories deleted file mode 100644 --- a/kmail.renamecategories +++ /dev/null @@ -1,7 +0,0 @@ -log_kmail org.kde.pim.kmail -log_sendlateragent org.kde.pim.sendlateragent -log_archivemailagent org.kde.pim.archivemailagent -log_followupreminderagent org.kde.pim.followupreminderagent -log_kmail_plugin org.kde.pim.kmail_plugin -log_mailfilteragent org.kde.pim.mailfilteragent - diff --git a/ktnef/CMakeLists.txt b/ktnef/CMakeLists.txt --- a/ktnef/CMakeLists.txt +++ b/ktnef/CMakeLists.txt @@ -5,6 +5,4 @@ add_subdirectory(src) -install( FILES ktnefapps.categories ktnefapps.renamecategories DESTINATION ${KDE_INSTALL_CONFDIR} ) - add_subdirectory(doc) diff --git a/ktnef/ktnefapps.categories b/ktnef/ktnefapps.categories deleted file mode 100644 --- a/ktnef/ktnefapps.categories +++ /dev/null @@ -1 +0,0 @@ -org.kde.pim.ktnefapps ktnef (ktnef apps) IDENTIFIER [KTNEFAPPS_LOG] diff --git a/ktnef/ktnefapps.renamecategories b/ktnef/ktnefapps.renamecategories deleted file mode 100644 --- a/ktnef/ktnefapps.renamecategories +++ /dev/null @@ -1 +0,0 @@ -log_ktnefapps org.kde.pim.ktnefapps diff --git a/ktnef/src/CMakeLists.txt b/ktnef/src/CMakeLists.txt --- a/ktnef/src/CMakeLists.txt +++ b/ktnef/src/CMakeLists.txt @@ -11,7 +11,12 @@ qwmf.cpp ) qt5_add_resources(ktnef_SRCS ktnef.qrc) -ecm_qt_declare_logging_category(ktnef_SRCS HEADER ktnef_debug.h IDENTIFIER KTNEFAPPS_LOG CATEGORY_NAME org.kde.pim.ktnefapps) + +ecm_qt_declare_logging_category(ktnef_SRCS HEADER ktnef_debug.h IDENTIFIER KTNEFAPPS_LOG CATEGORY_NAME org.kde.pim.ktnefapps + DESCRIPTION "kmail-refresh-settings" + EXPORT KMAIL + ) + file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/pics/hicolor/*-apps-ktnef.png") ecm_add_app_icon(ktnef_SRCS ICONS ${ICONS_SRCS}) diff --git a/ktnef/src/ktnefmain.cpp b/ktnef/src/ktnefmain.cpp --- a/ktnef/src/ktnefmain.cpp +++ b/ktnef/src/ktnefmain.cpp @@ -25,15 +25,17 @@ #include #include -#include +#include #include #include #include "ktnef_debug.h" #include #include #include #include #include +#include +#include #include #include #include @@ -245,7 +247,7 @@ if (mimename.isEmpty() || mimename == QLatin1String("application/octet-stream")) { qCDebug(KTNEFAPPS_LOG) << "No mime type found in attachment object, trying to guess..."; QMimeDatabase db; - db.mimeTypeForFile(url.path(), QMimeDatabase::MatchExtension).name(); + mimename = db.mimeTypeForFile(url.path(), QMimeDatabase::MatchExtension).name(); qCDebug(KTNEFAPPS_LOG) << "Detected mime type: " << mimename; } else { qCDebug(KTNEFAPPS_LOG) << "Mime type from attachment object: " << mimename; @@ -312,7 +314,7 @@ QString dir = QFileDialog::getExistingDirectory(this, QString(), mLastDir); if (!dir.isEmpty()) { mLastDir = dir; - dir.append(QLatin1String("/")); + dir.append(QLatin1Char('/')); QList list = mParser->message()->attachmentList(); QList::ConstIterator it; QList::ConstIterator end(list.constEnd()); @@ -390,8 +392,8 @@ void KTNEFMain::extractTo(const QString &dirname) { QString dir = dirname; - if (dir.right(1) != QLatin1String("/")) { - dir.append(QLatin1String("/")); + if (dir.right(1) != QLatin1Char('/')) { + dir.append(QLatin1Char('/')); } QList list = mView->getSelection(); QList::ConstIterator it; @@ -410,7 +412,7 @@ void KTNEFMain::contextMenuEvent(QContextMenuEvent *event) { QList list = mView->getSelection(); - if (!list.count()) { + if (list.isEmpty()) { return; } @@ -543,11 +545,13 @@ { if (!mView->getSelection().isEmpty()) { KTNEFAttach *attach = mView->getSelection().at(0); - QUrl url = QUrl::fromLocalFile(QLatin1String("file:") + extractTemp(attach)); - QList lst; - lst.append(url); + const QUrl url = QUrl::fromLocalFile(extractTemp(attach)); + QList lst{url}; if (offer) { - KRun::runService(*offer, lst, this, false); + KIO::ApplicationLauncherJob *job = new KIO::ApplicationLauncherJob(offer); + job->setUrls(lst); + job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); + job->start(); } else { KRun::displayOpenWithDialog(lst, this, false); } diff --git a/ktnef/src/main.cpp b/ktnef/src/main.cpp --- a/ktnef/src/main.cpp +++ b/ktnef/src/main.cpp @@ -18,19 +18,19 @@ #include "ktnef-version.h" #include -#include +#include #include #include #include #include #include int main(int argc, char *argv[]) { + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); QApplication app(argc, argv); KLocalizedString::setApplicationDomain("ktnef"); - app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); - app.setAttribute(Qt::AA_EnableHighDpiScaling); KCrash::initialize(); Kdelibs4ConfigMigrator migrate(QStringLiteral("ktnef")); migrate.setConfigFiles(QStringList() << QStringLiteral("ktnefrc")); diff --git a/ktnef/src/messagepropertydialog.cpp b/ktnef/src/messagepropertydialog.cpp --- a/ktnef/src/messagepropertydialog.cpp +++ b/ktnef/src/messagepropertydialog.cpp @@ -36,7 +36,7 @@ mMessage = msg; QVBoxLayout *mainLayout = new QVBoxLayout(this); - setWindowTitle(i18n("Message Properties")); + setWindowTitle(i18nc("@title:window", "Message Properties")); mListView = new QTreeWidget(this); mainLayout->addWidget(mListView); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); diff --git a/ktnef/src/org.kde.ktnef.desktop b/ktnef/src/org.kde.ktnef.desktop --- a/ktnef/src/org.kde.ktnef.desktop +++ b/ktnef/src/org.kde.ktnef.desktop @@ -15,6 +15,7 @@ Name[en_GB]=KTnef Name[es]=KTnef Name[et]=KTnef +Name[eu]=KTnef Name[fi]=KTnef Name[fr]=KTnef Name[fy]=KTnef @@ -67,6 +68,7 @@ GenericName[en_GB]=TNEF File Viewer (proprietary format used by outlook) GenericName[es]=Visor de archivos TNEF (formato propietario usado por outlook) GenericName[et]=TNEF-failide (Outlookis kasutatav omanduslik vorming) näitaja +GenericName[eu]=TNEF fitxategi erakuslea (outlook-ek erabiltzen duen formatu jabeduna) GenericName[fi]=TNEF-tiedostokatselin (Outlookin käyttämä suljettu tiedostomuoto) GenericName[fr]=Afficheur de fichier TNEF (format propriétaire utilisé par Outlook) GenericName[gl]=Visor de ficheiros de TNEF (formato privativo empregado por outlook) @@ -104,15 +106,16 @@ Comment[ar]=عارض/مستخرج لملفّات TNEF Comment[bg]=Програма за преглед и извличане на файлове TNEF Comment[bs]=Pregledač/izdvajač iz TNEF datoteka -Comment[ca]=Un visor/extractor pels fitxers TNEF -Comment[ca@valencia]=Un visor/extractor pels fitxers TNEF +Comment[ca]=Un visor/extractor per als fitxers TNEF +Comment[ca@valencia]=Un visor/extractor per als fitxers TNEF Comment[cy]=Gwelydd/echdynnydd i ffeiliau TNEF Comment[da]=En fremviser/udpakker til TNEF-filer Comment[de]=Betrachten und Extrahieren von TNEF-Dateien Comment[el]=Ένας προβολέας/εξαγωγέας για αρχεία TNEF Comment[en_GB]=A viewer/extractor for TNEF files Comment[es]=Un visor/extractor para archivos TNEF Comment[et]=TNEF-failide näitaja/ekstraktija +Comment[eu]=TNEF fitxategien erakusle/erauzle bat Comment[fa]=یک مشاهده‌گر/استخراج‌گر برای پرونده‌های TNEF Comment[fi]=Näytin/purkaja TNEF-tiedostoille Comment[fr]=Un afficheur / extracteur de fichier TNEF diff --git a/ktnef/src/qwmf.h b/ktnef/src/qwmf.h --- a/ktnef/src/qwmf.h +++ b/ktnef/src/qwmf.h @@ -68,23 +68,23 @@ /** * @return true if the metafile is placeable. */ - bool isPlaceable() const + Q_REQUIRED_RESULT bool isPlaceable() const { return mIsPlaceable; } /** * @return true if the metafile is enhanced. */ - bool isEnhanced() const + Q_REQUIRED_RESULT bool isEnhanced() const { return mIsEnhanced; } /** * @return bounding rectangle */ - QRect bbox() const + Q_REQUIRED_RESULT QRect bbox() const { return mBBox; } diff --git a/ktnef/src/qwmf.cpp b/ktnef/src/qwmf.cpp --- a/ktnef/src/qwmf.cpp +++ b/ktnef/src/qwmf.cpp @@ -217,7 +217,7 @@ mBBox.setBottom(pheader.bbox.bottom); mHeaderBoundingBox = mBBox; if (QWMF_DEBUG) { - qCDebug(KTNEFAPPS_LOG) << endl << "-------------------------------------------------"; + qCDebug(KTNEFAPPS_LOG) << "\n-------------------------------------------------"; qCDebug(KTNEFAPPS_LOG) << "WMF Placeable Header (" << static_cast(sizeof(pheader)) << "):"; qCDebug(KTNEFAPPS_LOG) << " bbox=(" << mBBox.left() << ";" << mBBox.top() << ";" << mBBox.width() << "; " << mBBox.height() << ")"; @@ -258,7 +258,7 @@ st >> eheader.szlMillimeters.height; if (QWMF_DEBUG) { - qCDebug(KTNEFAPPS_LOG) << endl << "-------------------------------------------------"; + qCDebug(KTNEFAPPS_LOG) << "\n-------------------------------------------------"; qCDebug(KTNEFAPPS_LOG) << "WMF Extended Header:"; qCDebug(KTNEFAPPS_LOG) << " iType=" << eheader.iType; qCDebug(KTNEFAPPS_LOG) << " nSize=" << eheader.nSize; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,6 +17,9 @@ +if (TARGET KUserFeedbackWidgets) + add_definitions(-DWITH_KUSERFEEDBACK) +endif() add_subdirectory(pics) add_subdirectory(icons) @@ -84,7 +87,6 @@ identity/identityfolderrequester.cpp ) set(kmailprivate_editor_LIB_SRCS - editor/widgets/snippetwidget.cpp editor/kmcomposereditorng.cpp editor/composer.cpp editor/codec/codecaction.cpp @@ -103,6 +105,7 @@ editor/warningwidgets/externaleditorwarning.cpp editor/warningwidgets/attachmentmissingwarning.cpp editor/warningwidgets/incorrectidentityfolderwarning.cpp + editor/warningwidgets/attachmentaddedfromexternalwarning.cpp ) set(kmailprivate_editor_potentialphishingemail_SRCS @@ -115,6 +118,7 @@ dialog/archivefolderdialog.cpp dialog/addemailtoexistingcontactdialog.cpp dialog/kmknotify.cpp + dialog/spellcheckerconfigdialog.cpp ) set(kmailprivate_job_LIB_SRCS job/addressvalidationjob.cpp @@ -143,7 +147,6 @@ widgets/collectionpane.cpp widgets/vacationscriptindicatorwidget.cpp widgets/displaymessageformatactionmenu.cpp - widgets/statusbarlabeltoggledstate.cpp widgets/kactionmenutransport.cpp widgets/kactionmenuaccount.cpp widgets/zoomlabelwidget.cpp @@ -176,8 +179,28 @@ sieveimapinterface/kmsieveimappasswordprovider.cpp ) +set(kmailprivate_undosend_LIB_SRCS + undosend/undosendcombobox.cpp + undosend/undosendmanager.cpp + undosend/undosendcreatejob.cpp + ) + +set(kmailprivate_userfeedback_LIB_SRCS) +if (TARGET KUserFeedbackWidgets) + set(kmailprivate_userfeedback_LIB_SRCS ${kmailprivate_userfeedback_LIB_SRCS} + userfeedback/accountinfosource.cpp + userfeedback/plugininfosource.cpp + userfeedback/kmailuserfeedbackprovider.cpp + ) +endif() + set(kmail_common_SRCS) -ecm_qt_declare_logging_category(kmail_common_SRCS HEADER kmail_debug.h IDENTIFIER KMAIL_LOG CATEGORY_NAME org.kde.pim.kmail) +ecm_qt_declare_logging_category(kmail_common_SRCS HEADER kmail_debug.h IDENTIFIER KMAIL_LOG CATEGORY_NAME org.kde.pim.kmail + DESCRIPTION "kmail (kmail)" + OLD_CATEGORY_NAMES log_kmail + EXPORT KMAIL + ) + set(kmailprivate_LIB_SRCS ${kmail_common_SRCS} kmmainwin.cpp @@ -189,7 +212,6 @@ kmkernel.cpp kmcommands.cpp kmreadermainwin.cpp - kmstartup.cpp kmmainwidget.cpp aboutdata.cpp mailserviceimpl.cpp @@ -218,6 +240,8 @@ ${kmailprivate_editor_plugininterface_LIB_SRCS} ${kmailprivate_checkindexing_LIB_SRCS} ${kmailprivate_sieveimapinstanceinterface_LIB_SRCS} + ${kmailprivate_undosend_LIB_SRCS} + ${kmailprivate_userfeedback_LIB_SRCS} ) qt5_add_dbus_adaptor(kmailprivate_LIB_SRCS @@ -285,6 +309,11 @@ editor/custommimeheader/custommimeheader.kcfgc ) +set(kmail_userfeedback_LIB) +if (TARGET KUserFeedbackWidgets) + set(kmail_userfeedback_LIB KUserFeedbackWidgets) +endif() + add_library(kmailprivate ${kmailprivate_LIB_SRCS}) generate_export_header(kmailprivate BASE_NAME kmail) @@ -318,7 +347,6 @@ KF5::Contacts KF5::PimTextEdit KF5::MessageViewer - KF5::SendLater KF5::FollowupReminder KF5::IconThemes KF5::XmlGui @@ -328,6 +356,7 @@ KF5::AkonadiSearchPIM KF5::WebEngineViewer KF5::SyntaxHighlighting + ${kmail_userfeedback_LIB} ) target_include_directories(kmailprivate PUBLIC $) target_include_directories(kmailprivate PUBLIC $) @@ -376,6 +405,7 @@ KF5::TemplateParser KF5::Libkdepim KF5::Crash + ${kmail_userfeedback_LIB} ) if(BUILD_TESTING) @@ -385,6 +415,7 @@ add_subdirectory(editor/potentialphishingemail/autotests) add_subdirectory(editor/warningwidgets/autotests) add_subdirectory(sieveimapinterface/tests/) + add_subdirectory(undosend/autotests/) endif() ########### install files ############### @@ -409,7 +440,6 @@ ) install( FILES data/kmail2.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFY5RCDIR} ) -install(FILES data/dbusmail.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR}) install(TARGETS kmailpart kcm_kmail @@ -420,3 +450,7 @@ ${kmail_BINARY_DIR}/src/org.kde.kmail.kmail.xml DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR} ) + +configure_file(data/org.kde.kmail.service.in org.kde.kmail.service) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.kmail.service DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR}) + diff --git a/src/Messages.sh b/src/Messages.sh --- a/src/Messages.sh +++ b/src/Messages.sh @@ -1,5 +1,5 @@ #! /bin/sh -$EXTRACT_GRANTLEE_TEMPLATE_STRINGS `find -name \*.html` >> html.cpp +$EXTRACT_GRANTLEE_TEMPLATE_STRINGS `find -name \*.html` >> rc.cpp $EXTRACTRC `find . -name '*.ui' -or -name '*.rc' -or -name '*.kcfg' -or -name '*.kcfg.cmake'` >> rc.cpp || exit 11 $XGETTEXT `find -name '*.cpp' -o -name '*.h' | grep -v '/tests/' | grep -v '/autotests/'` -o $podir/kmail.pot -rm -f rc.cpp html.cpp ./grantlee-extractor-pot-scripts/grantlee_strings_extractor.pyc +rm -f rc.cpp ./grantlee-extractor-pot-scripts/grantlee_strings_extractor.pyc diff --git a/src/aboutdata.cpp b/src/aboutdata.cpp --- a/src/aboutdata.cpp +++ b/src/aboutdata.cpp @@ -362,7 +362,7 @@ QStringLiteral(KDEPIM_VERSION), i18n("KDE Email Client"), KAboutLicense::GPL, - i18n("Copyright © 1997–2019, KMail authors"), + i18n("Copyright © 1997–2020, KMail authors"), QString(), QStringLiteral("https://userbase.kde.org/KMail")) { diff --git a/src/attributes/taskattribute.h b/src/attributes/taskattribute.h --- a/src/attributes/taskattribute.h +++ b/src/attributes/taskattribute.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014-2019 Montel Laurent + Copyright (c) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -28,7 +28,7 @@ TaskAttribute(Akonadi::Item::Id id); ~TaskAttribute() override; - QByteArray type() const override; + Q_REQUIRED_RESULT QByteArray type() const override; TaskAttribute *clone() const override; diff --git a/src/attributes/taskattribute.cpp b/src/attributes/taskattribute.cpp --- a/src/attributes/taskattribute.cpp +++ b/src/attributes/taskattribute.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2014-2019 Montel Laurent + Copyright (c) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/autotests/CMakeLists.txt b/src/autotests/CMakeLists.txt --- a/src/autotests/CMakeLists.txt +++ b/src/autotests/CMakeLists.txt @@ -17,12 +17,6 @@ ecm_mark_as_test(kmail-identityaddvcarddialogtest) target_link_libraries( identityaddvcarddialogtest Qt5::Test Qt5::Widgets KF5::Completion KF5::KIOWidgets KF5::I18n) -set( kmail_statusbarlabeltoggledstate_source statusbarlabeltoggledstatetest.cpp ../widgets/statusbarlabeltoggledstate.cpp ../kmail_debug.cpp) -add_executable(statusbarlabeltoggledstatetest ${kmail_statusbarlabeltoggledstate_source}) -ecm_mark_as_test(kmail-statusbarlabeltoggledstatetest) -target_link_libraries( statusbarlabeltoggledstatetest Qt5::Test KF5::KIOWidgets KF5::I18n) - - set( kmail_createfollowupreminderonexistingmessagejobtest_source createfollowupreminderonexistingmessagejobtest.cpp ../job/createfollowupreminderonexistingmessagejob.cpp ../kmail_debug.cpp) add_executable( createfollowupreminderonexistingmessagejobtest ${kmail_createfollowupreminderonexistingmessagejobtest_source}) ecm_mark_as_test(kmail_createfollowupreminderonexistingmessagejobtest) @@ -41,10 +35,12 @@ ecm_mark_as_test(kactionmenutransporttest) target_link_libraries( kactionmenutransporttest Qt5::Test KF5::MailTransportAkonadi KF5::WidgetsAddons KF5::I18n KF5::ConfigGui) -set(KDEPIMLIBS_RUN_ISOLATED_TESTS TRUE) -set(KDEPIMLIBS_RUN_SQLITE_ISOLATED_TESTS TRUE) +if (KDEPIM_RUN_AKONADI_TEST) + set(KDEPIMLIBS_RUN_ISOLATED_TESTS TRUE) + set(KDEPIMLIBS_RUN_SQLITE_ISOLATED_TESTS TRUE) -add_akonadi_isolated_test_advanced( tagselectdialogtest.cpp "../tag/tagselectdialog.cpp;../kmail_debug.cpp" "${KDEPIMLIBS_AKONADI_LIBS};kmailprivate;KF5::MailCommon;KF5::Libkdepim;KF5::ItemViews;KF5::TemplateParser;KF5::XmlGui;KF5::Completion;KF5::I18n") + add_akonadi_isolated_test_advanced( tagselectdialogtest.cpp "../tag/tagselectdialog.cpp;../kmail_debug.cpp" "kmailprivate;KF5::MailCommon;KF5::Libkdepim;KF5::ItemViews;KF5::TemplateParser;KF5::XmlGui;KF5::Completion;KF5::I18n") -add_akonadi_isolated_test_advanced(kmcommandstest.cpp "../kmcommands.cpp;../util.cpp;../secondarywindow.cpp;../undostack.cpp;../kmail_debug.cpp;../job/handleclickedurljob.cpp;../job/createreplymessagejob.cpp;../job/createforwardmessagejob.cpp" - "Qt5::Test;Qt5::Widgets;KF5::AkonadiCore;KF5::Bookmarks;KF5::ConfigWidgets;KF5::Contacts;KF5::I18n;KF5::IconThemes;KF5::IdentityManagement;KF5::KIOCore;KF5::KIOFileWidgets;KF5::MessageCore;KF5::MessageComposer;KF5::MessageList;KF5::MessageViewer;KF5::MailCommon;KF5::MailTransportAkonadi;KF5::Libkdepim;KF5::TemplateParser;kmailprivate") + add_akonadi_isolated_test_advanced(kmcommandstest.cpp "../kmcommands.cpp;../util.cpp;../secondarywindow.cpp;../undostack.cpp;../kmail_debug.cpp;../job/handleclickedurljob.cpp;../job/createreplymessagejob.cpp;../job/createforwardmessagejob.cpp" + "Qt5::Test;Qt5::Widgets;KF5::AkonadiCore;KF5::Bookmarks;KF5::ConfigWidgets;KF5::Contacts;KF5::I18n;KF5::IdentityManagement;KF5::KIOCore;KF5::KIOFileWidgets;KF5::MessageCore;KF5::MessageComposer;KF5::MessageList;KF5::MessageViewer;KF5::MailCommon;KF5::MailTransportAkonadi;KF5::Libkdepim;KF5::TemplateParser;kmailprivate") +endif() diff --git a/src/autotests/createfollowupreminderonexistingmessagejobtest.h b/src/autotests/createfollowupreminderonexistingmessagejobtest.h --- a/src/autotests/createfollowupreminderonexistingmessagejobtest.h +++ b/src/autotests/createfollowupreminderonexistingmessagejobtest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/autotests/createfollowupreminderonexistingmessagejobtest.cpp b/src/autotests/createfollowupreminderonexistingmessagejobtest.cpp --- a/src/autotests/createfollowupreminderonexistingmessagejobtest.cpp +++ b/src/autotests/createfollowupreminderonexistingmessagejobtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/autotests/cryptostateindicatorwidgettest.h b/src/autotests/cryptostateindicatorwidgettest.h --- a/src/autotests/cryptostateindicatorwidgettest.h +++ b/src/autotests/cryptostateindicatorwidgettest.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014-2019 Montel Laurent + Copyright (c) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/autotests/cryptostateindicatorwidgettest.cpp b/src/autotests/cryptostateindicatorwidgettest.cpp --- a/src/autotests/cryptostateindicatorwidgettest.cpp +++ b/src/autotests/cryptostateindicatorwidgettest.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2014-2019 Montel Laurent + Copyright (c) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/autotests/displaymessageformatactionmenutest.h b/src/autotests/displaymessageformatactionmenutest.h --- a/src/autotests/displaymessageformatactionmenutest.h +++ b/src/autotests/displaymessageformatactionmenutest.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014-2019 Montel Laurent + Copyright (c) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/autotests/displaymessageformatactionmenutest.cpp b/src/autotests/displaymessageformatactionmenutest.cpp --- a/src/autotests/displaymessageformatactionmenutest.cpp +++ b/src/autotests/displaymessageformatactionmenutest.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2014-2019 Montel Laurent + Copyright (c) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -47,7 +47,7 @@ { DisplayMessageFormatActionMenu menu; KToggleAction *prefereHtml = menu.findChild(QStringLiteral("prefer-html-action")); - QSignalSpy spy(&menu, SIGNAL(changeDisplayMessageFormat(MessageViewer::Viewer::DisplayFormatMessage))); + QSignalSpy spy(&menu, &DisplayMessageFormatActionMenu::changeDisplayMessageFormat); prefereHtml->trigger(); QCOMPARE(spy.count(), 1); QCOMPARE(spy.at(0).at(0).value(), MessageViewer::Viewer::Html); @@ -69,7 +69,7 @@ void DisplayMessageFormatActionMenuTest::shouldDontEmitSignalWhenChangeFormat() { DisplayMessageFormatActionMenu menu; - QSignalSpy spy(&menu, SIGNAL(changeDisplayMessageFormat(MessageViewer::Viewer::DisplayFormatMessage))); + QSignalSpy spy(&menu, &DisplayMessageFormatActionMenu::changeDisplayMessageFormat); menu.setDisplayMessageFormat(MessageViewer::Viewer::Text); QCOMPARE(spy.count(), 0); } diff --git a/src/autotests/identityaddvcarddialogtest.h b/src/autotests/identityaddvcarddialogtest.h --- a/src/autotests/identityaddvcarddialogtest.h +++ b/src/autotests/identityaddvcarddialogtest.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014-2019 Montel Laurent + Copyright (c) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/autotests/identityaddvcarddialogtest.cpp b/src/autotests/identityaddvcarddialogtest.cpp --- a/src/autotests/identityaddvcarddialogtest.cpp +++ b/src/autotests/identityaddvcarddialogtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2014-2019 Montel Laurent + Copyright (c) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/autotests/kactionmenutransporttest.h b/src/autotests/kactionmenutransporttest.h --- a/src/autotests/kactionmenutransporttest.h +++ b/src/autotests/kactionmenutransporttest.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/autotests/kactionmenutransporttest.cpp b/src/autotests/kactionmenutransporttest.cpp --- a/src/autotests/kactionmenutransporttest.cpp +++ b/src/autotests/kactionmenutransporttest.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/autotests/statusbarlabeltoggledstatetest.h b/src/autotests/statusbarlabeltoggledstatetest.h deleted file mode 100644 --- a/src/autotests/statusbarlabeltoggledstatetest.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - Copyright (c) 2014-2019 Montel Laurent - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef StatusBarLabelToggledStateTEST_H -#define StatusBarLabelToggledStateTEST_H - -#include - -class StatusBarLabelToggledStateTest : public QObject -{ - Q_OBJECT -public: - explicit StatusBarLabelToggledStateTest(QObject *parent = nullptr); - ~StatusBarLabelToggledStateTest(); - -private Q_SLOTS: - void shouldHasDefaultValue(); - void shouldChangeState(); - void shouldEmitSignalWhenChangeState(); - void shouldNotEmitSignalWhenWeDontChangeState(); - void shouldEmitSignalWhenClickOnLabel(); - void shouldChangeTestWhenStateChanged(); -}; - -#endif // StatusBarLabelToggledStateTEST_H diff --git a/src/autotests/statusbarlabeltoggledstatetest.cpp b/src/autotests/statusbarlabeltoggledstatetest.cpp deleted file mode 100644 --- a/src/autotests/statusbarlabeltoggledstatetest.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - Copyright (c) 2014-2019 Montel Laurent - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "statusbarlabeltoggledstatetest.h" -#include "../widgets/statusbarlabeltoggledstate.h" -#include -#include -#include - -StatusBarLabelToggledStateTest::StatusBarLabelToggledStateTest(QObject *parent) - : QObject(parent) -{ -} - -StatusBarLabelToggledStateTest::~StatusBarLabelToggledStateTest() -{ -} - -void StatusBarLabelToggledStateTest::shouldHasDefaultValue() -{ - StatusBarLabelToggledState widget; - widget.setStateString(QStringLiteral("toggle"), QStringLiteral("untoggle")); - QVERIFY(!widget.toggleMode()); -} - -void StatusBarLabelToggledStateTest::shouldChangeState() -{ - StatusBarLabelToggledState widget; - widget.setStateString(QStringLiteral("toggle"), QStringLiteral("untoggle")); - widget.setToggleMode(true); - QVERIFY(widget.toggleMode()); - QVERIFY(!widget.text().isEmpty()); - - widget.setToggleMode(true); - QVERIFY(widget.toggleMode()); - - widget.setToggleMode(false); - QVERIFY(!widget.toggleMode()); -} - -void StatusBarLabelToggledStateTest::shouldEmitSignalWhenChangeState() -{ - StatusBarLabelToggledState widget; - widget.setStateString(QStringLiteral("toggle"), QStringLiteral("untoggle")); - QSignalSpy spy(&widget, SIGNAL(toggleModeChanged(bool))); - widget.setToggleMode(true); - QCOMPARE(spy.count(), 1); - - widget.setToggleMode(false); - QCOMPARE(spy.count(), 2); -} - -void StatusBarLabelToggledStateTest::shouldNotEmitSignalWhenWeDontChangeState() -{ - StatusBarLabelToggledState widget; - widget.setStateString(QStringLiteral("toggle"), QStringLiteral("untoggle")); - QSignalSpy spy(&widget, SIGNAL(toggleModeChanged(bool))); - widget.setToggleMode(false); - QCOMPARE(spy.count(), 0); - - widget.setToggleMode(true); - QCOMPARE(spy.count(), 1); - - widget.setToggleMode(true); - QCOMPARE(spy.count(), 1); -} - -void StatusBarLabelToggledStateTest::shouldEmitSignalWhenClickOnLabel() -{ - StatusBarLabelToggledState widget; - widget.setStateString(QStringLiteral("toggle"), QStringLiteral("untoggle")); - QSignalSpy spy(&widget, SIGNAL(toggleModeChanged(bool))); - widget.show(); - QVERIFY(QTest::qWaitForWindowExposed(&widget)); - QTest::mouseClick(&widget, Qt::LeftButton); - QCOMPARE(spy.count(), 1); - - QTest::mouseClick(&widget, Qt::LeftButton); - QCOMPARE(spy.count(), 2); -} - -void StatusBarLabelToggledStateTest::shouldChangeTestWhenStateChanged() -{ - StatusBarLabelToggledState widget; - widget.setStateString(QStringLiteral("toggle"), QStringLiteral("untoggle")); - const QString initialText = widget.text(); - widget.setToggleMode(true); - const QString newText = widget.text(); - QVERIFY(initialText != newText); - - widget.setToggleMode(false); - QCOMPARE(widget.text(), initialText); - - widget.setToggleMode(true); - QCOMPARE(widget.text(), newText); -} - -QTEST_MAIN(StatusBarLabelToggledStateTest) diff --git a/src/autotests/tagselectdialogtest.h b/src/autotests/tagselectdialogtest.h --- a/src/autotests/tagselectdialogtest.h +++ b/src/autotests/tagselectdialogtest.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/autotests/tagselectdialogtest.cpp b/src/autotests/tagselectdialogtest.cpp --- a/src/autotests/tagselectdialogtest.cpp +++ b/src/autotests/tagselectdialogtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/collectionpage/collectionmailinglistpage.h b/src/collectionpage/collectionmailinglistpage.h --- a/src/collectionpage/collectionmailinglistpage.h +++ b/src/collectionpage/collectionmailinglistpage.h @@ -1,7 +1,7 @@ /* This file is part of KMail, the KDE mail client. Copyright (c) 2005 Till Adam - Copyright (c) 2011-2019 Montel Laurent + Copyright (c) 2011-2020 Laurent Montel Copyright (c) 2012 Jonathan Marten KMail is free software; you can redistribute it and/or modify it @@ -21,7 +21,7 @@ #ifndef COLLECTIONMAILINGLISTPAGE_H #define COLLECTIONMAILINGLISTPAGE_H -#include "MessageCore/MailingList" +#include #include #include @@ -47,7 +47,7 @@ void load(const Akonadi::Collection &col) override; void save(Akonadi::Collection &col) override; - bool canHandle(const Akonadi::Collection &col) const override; + Q_REQUIRED_RESULT bool canHandle(const Akonadi::Collection &col) const override; private: void slotFetchDone(KJob *job); diff --git a/src/collectionpage/collectionmailinglistpage.cpp b/src/collectionpage/collectionmailinglistpage.cpp --- a/src/collectionpage/collectionmailinglistpage.cpp +++ b/src/collectionpage/collectionmailinglistpage.cpp @@ -1,7 +1,7 @@ /* This file is part of KMail, the KDE mail client. Copyright (c) 2005 Till Adam - Copyright (c) 2011-2019 Montel Laurent + Copyright (c) 2011-2020 Laurent Montel Copyright (c) 2012 Jonathan Marten KMail is free software; you can redistribute it and/or modify it @@ -19,8 +19,8 @@ */ #include "collectionmailinglistpage.h" -#include "mailcommon/mailkernel.h" -#include "mailcommon/mailutil.h" +#include +#include #include "util.h" #include @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include #include @@ -102,7 +102,7 @@ mMLHandlerCombo->addItem(i18n("KMail"), MailingList::KMail); mMLHandlerCombo->addItem(i18n("Browser"), MailingList::Browser); groupLayout->addWidget(mMLHandlerCombo, 5, 1, 1, 2); - connect(mMLHandlerCombo, QOverload::of(&QComboBox::activated), this, &CollectionMailingListPage::slotMLHandling); + connect(mMLHandlerCombo, qOverload(&QComboBox::activated), this, &CollectionMailingListPage::slotMLHandling); label->setBuddy(mMLHandlerCombo); label = new QLabel(i18n("Address type:"), mGroupWidget); @@ -134,7 +134,7 @@ i18n("Post to List"), i18n("Subscribe to List"), i18n("Unsubscribe From List"), i18n("List Archives"), i18n("List Help") }; mAddressCombo->addItems(el); - connect(mAddressCombo, QOverload::of(&QComboBox::activated), this, &CollectionMailingListPage::slotAddressChanged); + connect(mAddressCombo, qOverload(&QComboBox::activated), this, &CollectionMailingListPage::slotAddressChanged); topLayout->addWidget(mGroupWidget); mGroupWidget->setEnabled(false); @@ -330,19 +330,29 @@ save(mCurrentCollection); switch (mAddressCombo->currentIndex()) { case 0: - KMail::Util::mailingListPost(mFolder, mCurrentCollection); + if (!KMail::Util::mailingListPost(mFolder, mCurrentCollection)) { + qCWarning(KMAIL_LOG) << "invalid folder"; + } break; case 1: - KMail::Util::mailingListSubscribe(mFolder, mCurrentCollection); + if (!KMail::Util::mailingListSubscribe(mFolder, mCurrentCollection)) { + qCWarning(KMAIL_LOG) << "invalid folder"; + } break; case 2: - KMail::Util::mailingListUnsubscribe(mFolder, mCurrentCollection); + if (!KMail::Util::mailingListUnsubscribe(mFolder, mCurrentCollection)) { + qCWarning(KMAIL_LOG) << "invalid folder"; + } break; case 3: - KMail::Util::mailingListArchives(mFolder, mCurrentCollection); + if (!KMail::Util::mailingListArchives(mFolder, mCurrentCollection)) { + qCWarning(KMAIL_LOG) << "invalid folder"; + } break; case 4: - KMail::Util::mailingListHelp(mFolder, mCurrentCollection); + if (!KMail::Util::mailingListHelp(mFolder, mCurrentCollection)) { + qCWarning(KMAIL_LOG) << "invalid folder"; + } break; default: qCWarning(KMAIL_LOG) << "Wrong entry in the mailing list entry combo!"; diff --git a/src/collectionpage/collectionquotapage.h b/src/collectionpage/collectionquotapage.h --- a/src/collectionpage/collectionquotapage.h +++ b/src/collectionpage/collectionquotapage.h @@ -2,7 +2,7 @@ /** * * Copyright (c) 2006 Till Adam - * Copyright (c) 2009-2019 Laurent Montel + * Copyright (c) 2009-2020 Laurent Montel * * * This program is free software; you can redistribute it and/or modify @@ -45,7 +45,7 @@ explicit CollectionQuotaPage(QWidget *parent = nullptr); void load(const Akonadi::Collection &col) override; void save(Akonadi::Collection &col) override; - bool canHandle(const Akonadi::Collection &collection) const override; + Q_REQUIRED_RESULT bool canHandle(const Akonadi::Collection &collection) const override; private: void init(); diff --git a/src/collectionpage/collectionquotapage.cpp b/src/collectionpage/collectionquotapage.cpp --- a/src/collectionpage/collectionquotapage.cpp +++ b/src/collectionpage/collectionquotapage.cpp @@ -2,7 +2,7 @@ /** * * Copyright (c) 2006 Till Adam - * Copyright (c) 2009-2019 Laurent Montel + * Copyright (c) 2009-2020 Laurent Montel * * * This program is free software; you can redistribute it and/or modify @@ -35,9 +35,8 @@ #include #include -#include #include - +#include CollectionQuotaPage::CollectionQuotaPage(QWidget *parent) : CollectionPropertiesPage(parent) { diff --git a/src/collectionpage/collectionquotawidget.cpp b/src/collectionpage/collectionquotawidget.cpp --- a/src/collectionpage/collectionquotawidget.cpp +++ b/src/collectionpage/collectionquotawidget.cpp @@ -2,7 +2,7 @@ * * Copyright (c) 2006 Till Adam * - * Copyright (C) 2012-2019 Laurent Montel + * Copyright (C) 2012-2020 Laurent Montel * * * This program is free software; you can redistribute it and/or modify @@ -33,9 +33,8 @@ #include "collectionquotawidget.h" #include - +#include #include -#include #include #include diff --git a/src/collectionpage/collectiontemplatespage.h b/src/collectionpage/collectiontemplatespage.h --- a/src/collectionpage/collectiontemplatespage.h +++ b/src/collectionpage/collectiontemplatespage.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2009-2019 Montel Laurent + Copyright (C) 2009-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -37,7 +37,7 @@ void load(const Akonadi::Collection &col) override; void save(Akonadi::Collection &col) override; - bool canHandle(const Akonadi::Collection &collection) const override; + Q_REQUIRED_RESULT bool canHandle(const Akonadi::Collection &collection) const override; private: void slotCopyGlobal(); diff --git a/src/collectionpage/collectiontemplatespage.cpp b/src/collectionpage/collectiontemplatespage.cpp --- a/src/collectionpage/collectiontemplatespage.cpp +++ b/src/collectionpage/collectiontemplatespage.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2009-2019 Montel Laurent + Copyright (C) 2009-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -19,9 +19,9 @@ #include "collectiontemplatespage.h" -#include "mailcommon/mailkernel.h" +#include #include -#include "TemplateParser/TemplatesConfiguration" +#include #include "templatesconfiguration_kfg.h" #include diff --git a/src/collectionpage/collectionviewpage.h b/src/collectionpage/collectionviewpage.h --- a/src/collectionpage/collectionviewpage.h +++ b/src/collectionpage/collectionviewpage.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2009-2019 Montel Laurent + Copyright (C) 2009-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/collectionpage/collectionviewpage.cpp b/src/collectionpage/collectionviewpage.cpp --- a/src/collectionpage/collectionviewpage.cpp +++ b/src/collectionpage/collectionviewpage.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2009-2019 Montel Laurent + Copyright (C) 2009-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -18,35 +18,33 @@ */ #include "collectionviewpage.h" -#include "mailcommon/mailkernel.h" +#include #include #include #include #include #include -#include #include #include #include #include #include #include #include "kmail_debug.h" -#include "messagelist/aggregationcombobox.h" -#include "messagelist/aggregationconfigbutton.h" -#include "messagelist/themecombobox.h" -#include "messagelist/themeconfigbutton.h" +#include +#include +#include +#include #include using namespace MailCommon; CollectionViewPage::CollectionViewPage(QWidget *parent) : CollectionPropertiesPage(parent) - , mIsLocalSystemFolder(false) { setObjectName(QStringLiteral("KMail::CollectionViewPage")); setPageTitle(i18nc("@title:tab View settings for a folder.", "View")); @@ -324,4 +322,5 @@ qCDebug(KMAIL_LOG) << "No settings defined"; } mFolderCollection->setFormatMessage(formatMessage); + mFolderCollection->writeConfig(); } diff --git a/src/configuredialog/colorlistbox.h b/src/configuredialog/colorlistbox.h --- a/src/configuredialog/colorlistbox.h +++ b/src/configuredialog/colorlistbox.h @@ -40,7 +40,7 @@ void setColor(int index, const QColor &color); // like setColor, but does not Q_EMIT changed() void setColorSilently(int index, const QColor &color); - QColor color(int index) const; + Q_REQUIRED_RESULT QColor color(int index) const; Q_SIGNALS: void changed(); diff --git a/src/configuredialog/configmodule.h b/src/configuredialog/configmodule.h --- a/src/configuredialog/configmodule.h +++ b/src/configuredialog/configmodule.h @@ -26,7 +26,7 @@ #include "kmail_export.h" -#include +#include class ConfigModule : public KCModule { public: diff --git a/src/configuredialog/configureaccountpage.h b/src/configuredialog/configureaccountpage.h --- a/src/configuredialog/configureaccountpage.h +++ b/src/configuredialog/configureaccountpage.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2013-2019 Montel Laurent + Copyright (c) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -24,6 +24,7 @@ class QCheckBox; class QComboBox; +class UndoSendCombobox; class OrgFreedesktopAkonadiNewMailNotifierInterface; namespace KLDAP { class LdapConfigureWidget; @@ -35,7 +36,7 @@ public: explicit AccountsPageSendingTab(QWidget *parent = nullptr); ~AccountsPageSendingTab() override; - QString helpAnchor() const; + Q_REQUIRED_RESULT QString helpAnchor() const; void save() override; private: @@ -47,6 +48,8 @@ QCheckBox *mCheckSpellingBeforeSending = nullptr; QComboBox *mSendOnCheckCombo = nullptr; QComboBox *mSendMethodCombo = nullptr; + UndoSendCombobox *mUndoSendComboBox = nullptr; + QCheckBox *mUndoSend = nullptr; }; // subclasses: one class per tab: diff --git a/src/configuredialog/configureaccountpage.cpp b/src/configuredialog/configureaccountpage.cpp --- a/src/configuredialog/configureaccountpage.cpp +++ b/src/configuredialog/configureaccountpage.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2013-2019 Montel Laurent + Copyright (c) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -21,14 +21,15 @@ #include "kmkernel.h" #include "settings/kmailsettings.h" #include "configagentdelegate.h" -#include "MessageComposer/MessageComposerSettings" -#include "MailCommon/AccountConfigOrderDialog" -#include "PimCommon/ConfigureImmutableWidgetUtils" +#include "undosend/undosendcombobox.h" +#include +#include +#include using namespace PimCommon::ConfigureImmutableWidgetUtils; -#include +#include using MailTransport::TransportManagementWidget; #include "ui_accountspagereceivingtab.h" -#include "MailCommon/MailUtil" +#include #include #include @@ -133,16 +134,16 @@ << i18n("On Manual Mail Checks") << i18n("On All Mail Checks")); glay->addWidget(mSendOnCheckCombo, 2, 1); - connect(mSendOnCheckCombo, QOverload::of(&QComboBox::activated), this, &AccountsPageSendingTab::slotEmitChanged); + connect(mSendOnCheckCombo, qOverload(&QComboBox::activated), this, &AccountsPageSendingTab::slotEmitChanged); // "default send method" combo: mSendMethodCombo = new QComboBox(group); mSendMethodCombo->setEditable(false); mSendMethodCombo->addItems(QStringList() << i18n("Send Now") << i18n("Send Later")); glay->addWidget(mSendMethodCombo, 3, 1); - connect(mSendMethodCombo, QOverload::of(&QComboBox::activated), this, &AccountsPageSendingTab::slotEmitChanged); + connect(mSendMethodCombo, qOverload(&QComboBox::activated), this, &AccountsPageSendingTab::slotEmitChanged); // labels: QLabel *l = new QLabel(i18n("Send &messages in outbox folder:"), group); @@ -156,26 +157,46 @@ l = new QLabel(i18n("Defa&ult send method:"), group); l->setBuddy(mSendMethodCombo); glay->addWidget(l, 3, 0); + + mUndoSend = new QCheckBox(i18n("Enable Undo Send"), this); + glay->addWidget(mUndoSend, 4, 0); + connect(mUndoSend, &QCheckBox::toggled, this, [this](bool state) { + mUndoSendComboBox->setEnabled(state); + Q_EMIT slotEmitChanged(); + }); + + mUndoSendComboBox = new UndoSendCombobox(this); + mUndoSendComboBox->setEnabled(false); + glay->addWidget(mUndoSendComboBox, 4, 1); + connect(mUndoSendComboBox, qOverload(&QComboBox::activated), this, &AccountsPageSendingTab::slotEmitChanged); } void AccountsPage::SendingTab::doLoadFromGlobalSettings() { mSendOnCheckCombo->setCurrentIndex(KMailSettings::self()->sendOnCheck()); + loadWidget(mConfirmSendCheck, KMailSettings::self()->confirmBeforeSendItem()); + loadWidget(mCheckSpellingBeforeSending, KMailSettings::self()->checkSpellingBeforeSendItem()); + loadWidget(mUndoSend, KMailSettings::self()->enabledUndoSendItem()); + mUndoSendComboBox->setDelay(KMailSettings::self()->undoSendDelay()); } void AccountsPage::SendingTab::doLoadOther() { mSendMethodCombo->setCurrentIndex(MessageComposer::MessageComposerSettings::self()->sendImmediate() ? 0 : 1); loadWidget(mConfirmSendCheck, KMailSettings::self()->confirmBeforeSendItem()); loadWidget(mCheckSpellingBeforeSending, KMailSettings::self()->checkSpellingBeforeSendItem()); + loadWidget(mUndoSend, KMailSettings::self()->enabledUndoSendItem()); + mUndoSendComboBox->setDelay(KMailSettings::self()->undoSendDelay()); } void AccountsPage::SendingTab::save() { KMailSettings::self()->setSendOnCheck(mSendOnCheckCombo->currentIndex()); saveCheckBox(mConfirmSendCheck, KMailSettings::self()->confirmBeforeSendItem()); saveCheckBox(mCheckSpellingBeforeSending, KMailSettings::self()->checkSpellingBeforeSendItem()); + saveCheckBox(mUndoSend, KMailSettings::self()->enabledUndoSendItem()); MessageComposer::MessageComposerSettings::self()->setSendImmediate(mSendMethodCombo->currentIndex() == 0); + KMailSettings::self()->setUndoSendDelay(mUndoSendComboBox->delay()); } QString AccountsPage::ReceivingTab::helpAnchor() const @@ -399,7 +420,7 @@ mLdapConfigureWidget = new KLDAP::LdapConfigureWidget(this); layout->addWidget(mLdapConfigureWidget); - connect(mLdapConfigureWidget, &KLDAP::LdapConfigureWidget::changed, this, QOverload::of(&LdapCompetionTab::changed)); + connect(mLdapConfigureWidget, &KLDAP::LdapConfigureWidget::changed, this, qOverload(&LdapCompetionTab::changed)); } LdapCompetionTab::~LdapCompetionTab() diff --git a/src/configuredialog/configureappearancepage.h b/src/configuredialog/configureappearancepage.h --- a/src/configuredialog/configureappearancepage.h +++ b/src/configuredialog/configureappearancepage.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2013-2019 Montel Laurent + Copyright (c) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -30,7 +30,7 @@ class QButtonGroup; class QGroupBox; class QSpinBox; -class KLineEdit; +class QLineEdit; class QModelIndex; class KJob; namespace MessageViewer { @@ -58,7 +58,7 @@ Q_OBJECT public: explicit AppearancePageFontsTab(QWidget *parent = nullptr); - QString helpAnchor() const; + Q_REQUIRED_RESULT QString helpAnchor() const; void save() override; private: @@ -81,7 +81,7 @@ Q_OBJECT public: explicit AppearancePageColorsTab(QWidget *parent = nullptr); - QString helpAnchor() const; + Q_REQUIRED_RESULT QString helpAnchor() const; void save() override; private: @@ -102,7 +102,7 @@ Q_OBJECT public: explicit AppearancePageLayoutTab(QWidget *parent = nullptr); - QString helpAnchor() const; + Q_REQUIRED_RESULT QString helpAnchor() const; void save() override; @@ -127,7 +127,7 @@ public: explicit AppearancePageHeadersTab(QWidget *parent = nullptr); - QString helpAnchor() const; + Q_REQUIRED_RESULT QString helpAnchor() const; void save() override; @@ -146,7 +146,7 @@ MessageList::Utils::ThemeComboBox *mThemeComboBox = nullptr; QButtonGroup *mDateDisplay = nullptr; QGroupBox *mDateDisplayBox = nullptr; - KLineEdit *mCustomDateFormatEdit = nullptr; + QLineEdit *mCustomDateFormatEdit = nullptr; QString mCustomDateWhatsThis; }; @@ -246,7 +246,7 @@ void updateButtons(); private: // data - KLineEdit *mTagAddLineEdit = nullptr; + QLineEdit *mTagAddLineEdit = nullptr; QPushButton *mTagAddButton = nullptr; QPushButton *mTagRemoveButton = nullptr; QPushButton *mTagUpButton = nullptr; diff --git a/src/configuredialog/configureappearancepage.cpp b/src/configuredialog/configureappearancepage.cpp --- a/src/configuredialog/configureappearancepage.cpp +++ b/src/configuredialog/configureappearancepage.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2013-2019 Montel Laurent + Copyright (c) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -16,34 +16,35 @@ */ #include "configureappearancepage.h" -#include "PimCommon/ConfigureImmutableWidgetUtils" +#include using namespace PimCommon::ConfigureImmutableWidgetUtils; #include "configuredialog/colorlistbox.h" -#include "messagelist/aggregationcombobox.h" -#include "messagelist/aggregationconfigbutton.h" -#include "messagelist/themecombobox.h" -#include "messagelist/themeconfigbutton.h" +#include +#include +#include +#include +#include #include "messagelistsettings.h" -#include "MailCommon/TagWidget" +#include #include "MailCommon/Tag" #include "kmkernel.h" #include "util.h" -#include "MailCommon/FolderTreeWidget" +#include #include "kmmainwidget.h" #include "mailcommonsettings_base.h" -#include "MessageViewer/ConfigureWidget" -#include "messageviewer/messageviewersettings.h" +#include +#include -#include "messagelist/messagelistutil.h" +#include #include -#include "MessageCore/MessageCoreUtil" +#include #include "settings/kmailsettings.h" -#include "MailCommon/MailUtil" +#include #include #include @@ -61,7 +62,7 @@ #include #include #include -#include +#include #include #include "kmail_debug.h" @@ -196,7 +197,7 @@ connect(mCustomFontCheck, &QAbstractButton::toggled, mFontChooser, &QWidget::setEnabled); // load the right font settings into mFontChooser: - connect(mFontLocationCombo, QOverload::of(&QComboBox::activated), + connect(mFontLocationCombo, qOverload(&QComboBox::activated), this, &AppearancePage::FontsTab::slotFontSelectorChanged); } @@ -210,7 +211,7 @@ // Save current fontselector setting before we install the new: if (mActiveFontIndex == 0) { mFont[0] = mFontChooser->font(); - // hardcode the family and size of "message body" dependant fonts: + // hardcode the family and size of "message body" dependent fonts: for (int i = 0; i < numFontNames; ++i) { if (!fontNames[i].enableFamilyAndSize) { // ### shall we copy the font and set the save and re-set @@ -372,7 +373,7 @@ mCloseToQuotaThreshold = new QSpinBox(this); mCloseToQuotaThreshold->setRange(0, 100); mCloseToQuotaThreshold->setSingleStep(1); - connect(mCloseToQuotaThreshold, QOverload::of(&QSpinBox::valueChanged), + connect(mCloseToQuotaThreshold, qOverload(&QSpinBox::valueChanged), this, &ConfigModuleTab::slotEmitChanged); mCloseToQuotaThreshold->setSuffix(i18n("%")); @@ -491,7 +492,7 @@ mFolderListGroup = new QButtonGroup(this), Qt::Vertical, KMailSettings::self()->folderListItem()); vlay->addWidget(mFolderListGroupBox); - connect(mFolderListGroup, QOverload::of(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); + connect(mFolderListGroup, qOverload(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); QHBoxLayout *folderCBHLayout = new QHBoxLayout; mFolderQuickSearchCB = new QCheckBox(i18n("Show folder quick search field"), this); @@ -504,7 +505,7 @@ mFavoriteFoldersViewGroupBox->setTitle(i18n("Show Favorite Folders View")); mFavoriteFoldersViewGroupBox->setLayout(new QVBoxLayout()); mFavoriteFoldersViewGroup = new QButtonGroup(this); - connect(mFavoriteFoldersViewGroup, QOverload::of(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); + connect(mFavoriteFoldersViewGroup, qOverload(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); QRadioButton *favoriteFoldersViewHiddenRadio = new QRadioButton(i18n("Never"), mFavoriteFoldersViewGroupBox); mFavoriteFoldersViewGroup->addButton(favoriteFoldersViewHiddenRadio, static_cast(MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::HiddenMode)); @@ -525,7 +526,7 @@ mFolderToolTipsGroupBox->setTitle(i18n("Folder Tooltips")); mFolderToolTipsGroupBox->setLayout(new QVBoxLayout()); mFolderToolTipsGroup = new QButtonGroup(this); - connect(mFolderToolTipsGroup, QOverload::of(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); + connect(mFolderToolTipsGroup, qOverload(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); QRadioButton *folderToolTipsAlwaysRadio = new QRadioButton(i18n("Always"), mFolderToolTipsGroupBox); mFolderToolTipsGroup->addButton(folderToolTipsAlwaysRadio, static_cast< int >(FolderTreeWidget::DisplayAlways)); @@ -543,7 +544,7 @@ Qt::Vertical, KMailSettings::self()->readerWindowModeItem()); vlay->addWidget(mReaderWindowModeGroupBox); - connect(mReaderWindowModeGroup, QOverload::of(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); + connect(mReaderWindowModeGroup, qOverload(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); vlay->addStretch(10); // spacer } @@ -629,7 +630,7 @@ connect(aggregationConfigButton, &MessageList::Utils::AggregationConfigButton::configureDialogCompleted, this, &AppearancePageHeadersTab::slotSelectDefaultAggregation); - connect(mAggregationComboBox, QOverload::of(&MessageList::Utils::AggregationComboBox::activated), + connect(mAggregationComboBox, qOverload(&MessageList::Utils::AggregationComboBox::activated), this, &ConfigModuleTab::slotEmitChanged); // "Theme" @@ -650,7 +651,7 @@ connect(themeConfigButton, &MessageList::Utils::ThemeConfigButton::configureDialogCompleted, this, &AppearancePageHeadersTab::slotSelectDefaultTheme); - connect(mThemeComboBox, QOverload::of(&MessageList::Utils::ThemeComboBox::activated), + connect(mThemeComboBox, qOverload(&MessageList::Utils::ThemeComboBox::activated), this, &ConfigModuleTab::slotEmitChanged); vlay->addWidget(group); @@ -678,7 +679,8 @@ hboxHBoxLayout->addWidget(radio); mDateDisplay->addButton(radio, dateDisplayConfig[i].dateDisplay); - mCustomDateFormatEdit = new KLineEdit(hbox); + mCustomDateFormatEdit = new QLineEdit(hbox); + new KPIM::LineEditCatchReturnKey(mCustomDateFormatEdit, this); hboxHBoxLayout->addWidget(mCustomDateFormatEdit); mCustomDateFormatEdit->setEnabled(false); hboxHBoxLayout->setStretchFactor(mCustomDateFormatEdit, 1); @@ -738,7 +740,7 @@ } // end for loop populating mDateDisplay vlay->addWidget(mDateDisplayBox); - connect(mDateDisplay, QOverload::of(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); + connect(mDateDisplay, qOverload(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); vlay->addStretch(10); // spacer } @@ -969,8 +971,8 @@ QHBoxLayout *addremovegrid = new QHBoxLayout(); tageditgrid->addLayout(addremovegrid); - mTagAddLineEdit = new KLineEdit(mTagsGroupBox); - mTagAddLineEdit->setTrapReturnKey(true); + mTagAddLineEdit = new QLineEdit(mTagsGroupBox); + new KPIM::LineEditCatchReturnKey(mTagAddLineEdit, this); addremovegrid->addWidget(mTagAddLineEdit); mTagAddButton = new QPushButton(mTagsGroupBox); @@ -1031,16 +1033,16 @@ connect(mTagWidget, &TagWidget::changed, this, &AppearancePageMessageTagTab::slotEmitChangeCheck); //For enabling the add button in case box is non-empty - connect(mTagAddLineEdit, &KLineEdit::textChanged, + connect(mTagAddLineEdit, &QLineEdit::textChanged, this, &AppearancePage::MessageTagTab::slotAddLineTextChanged); //For on-the-fly updating of tag name in editbox connect(mTagWidget->tagNameLineEdit(), &QLineEdit::textChanged, this, &AppearancePageMessageTagTab::slotNameLineTextChanged); connect(mTagWidget, &TagWidget::iconNameChanged, this, &AppearancePageMessageTagTab::slotIconNameChanged); - connect(mTagAddLineEdit, &KLineEdit::returnPressed, + connect(mTagAddLineEdit, &QLineEdit::returnPressed, this, &AppearancePageMessageTagTab::slotAddNewTag); connect(mTagAddButton, &QAbstractButton::clicked, @@ -1163,12 +1165,12 @@ TagListWidgetItem *tagItem = static_cast(item); MailCommon::Tag::Ptr tmp_desc = tagItem->kmailTag(); - disconnect(mTagWidget->tagNameLineEdit(), &KLineEdit::textChanged, + disconnect(mTagWidget->tagNameLineEdit(), &QLineEdit::textChanged, this, &AppearancePage::MessageTagTab::slotNameLineTextChanged); mTagWidget->tagNameLineEdit()->setEnabled(!tmp_desc->isImmutable); mTagWidget->tagNameLineEdit()->setText(tmp_desc->tagName); - connect(mTagWidget->tagNameLineEdit(), &KLineEdit::textChanged, + connect(mTagWidget->tagNameLineEdit(), &QLineEdit::textChanged, this, &AppearancePage::MessageTagTab::slotNameLineTextChanged); mTagWidget->setTagTextColor(tmp_desc->textColor); diff --git a/src/configuredialog/configurecomposerpage.h b/src/configuredialog/configurecomposerpage.h --- a/src/configuredialog/configurecomposerpage.h +++ b/src/configuredialog/configurecomposerpage.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2013-2019 Montel Laurent + Copyright (c) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -84,7 +84,7 @@ Q_OBJECT public: explicit ComposerPageTemplatesTab(QWidget *parent = nullptr); - QString helpAnchor() const; + Q_REQUIRED_RESULT QString helpAnchor() const; void save() override; @@ -100,7 +100,7 @@ Q_OBJECT public: explicit ComposerPageCustomTemplatesTab(QWidget *parent = nullptr); - QString helpAnchor() const; + Q_REQUIRED_RESULT QString helpAnchor() const; void save() override; @@ -116,7 +116,7 @@ Q_OBJECT public: explicit ComposerPageSubjectTab(QWidget *parent = nullptr); - QString helpAnchor() const; + Q_REQUIRED_RESULT QString helpAnchor() const; void save() override; @@ -136,7 +136,7 @@ Q_OBJECT public: explicit ComposerPageCharsetTab(QWidget *parent = nullptr); - QString helpAnchor() const; + Q_REQUIRED_RESULT QString helpAnchor() const; void save() override; @@ -155,7 +155,7 @@ Q_OBJECT public: explicit ComposerPageHeadersTab(QWidget *parent = nullptr); - QString helpAnchor() const; + Q_REQUIRED_RESULT QString helpAnchor() const; void save() override; diff --git a/src/configuredialog/configurecomposerpage.cpp b/src/configuredialog/configurecomposerpage.cpp --- a/src/configuredialog/configurecomposerpage.cpp +++ b/src/configuredialog/configurecomposerpage.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2013-2019 Montel Laurent + Copyright (c) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -16,26 +16,26 @@ */ #include "configurecomposerpage.h" -#include "PimCommon/ConfigureImmutableWidgetUtils" +#include using namespace PimCommon::ConfigureImmutableWidgetUtils; #include "kmkernel.h" #include "kmmainwidget.h" -#include "PimCommon/AutoCorrectionWidget" -#include "MessageComposer/ImageScalingWidget" -#include "MessageComposer/MessageComposerSettings" +#include +#include +#include #include #include "settings/kmailsettings.h" #include "configuredialog/configuredialoglistview.h" -#include "PimCommon/SimpleStringListEditor" +#include #include "templatesconfiguration_kfg.h" -#include "TemplateParser/TemplatesConfiguration" -#include "templateparser/customtemplates.h" +#include +#include #include "globalsettings_templateparser.h" -#include "libkdepim/recentaddresses.h" +#include #include -#include "libkdepimakonadi/completionordereditor.h" +#include using KPIM::RecentAddresses; #include @@ -57,8 +57,10 @@ #include #include -#include - +#include +#ifdef KDEPIM_ENTERPRISE_BUILD +#include +#endif QString ComposerPage::helpAnchor() const { return QStringLiteral("configure-composer"); @@ -245,7 +247,7 @@ mWrapColumnSpin->setWhatsThis(helpText); connect(mWordWrapCheck, &QCheckBox::stateChanged, this, &ConfigModuleTab::slotEmitChanged); - connect(mWrapColumnSpin, QOverload::of(&QSpinBox::valueChanged), this, &ComposerPageGeneralTab::slotEmitChanged); + connect(mWrapColumnSpin, qOverload(&QSpinBox::valueChanged), this, &ComposerPageGeneralTab::slotEmitChanged); // only enable the spinbox if the checkbox is checked connect(mWordWrapCheck, &QAbstractButton::toggled, mWrapColumnSpin, &QWidget::setEnabled); @@ -281,7 +283,7 @@ connect(mImprovePlainTextOfHtmlMessage, &QCheckBox::stateChanged, this, &ConfigModuleTab::slotEmitChanged); groupGridLayout->addWidget(mImprovePlainTextOfHtmlMessage, row, 0, 1, -1); ++row; - + QLabel *label = nullptr; #ifdef KDEPIM_ENTERPRISE_BUILD ++row; // "Default forwarding type" combobox @@ -297,7 +299,7 @@ label = new QLabel(i18n("Default forwarding type:"), this); label->setBuddy(mForwardTypeCombo); - connect(mForwardTypeCombo, QOverload::of(&QComboBox::activated), this, &ComposerPageGeneralTab::slotEmitChanged); + connect(mForwardTypeCombo, qOverload(&QComboBox::activated), this, &ComposerPageGeneralTab::slotEmitChanged); groupGridLayout->addWidget(label, row, 0); groupGridLayout->addWidget(mForwardTypeCombo, row, 1); @@ -340,7 +342,7 @@ #ifdef KDEPIM_ENTERPRISE_BUILD // "Warn if too many recipients" checkbox/spinbox mRecipientCheck = new QCheckBox( - GlobalSettings::self()->tooManyRecipientsItem()->label(), this); + KMailSettings::self()->tooManyRecipientsItem()->label(), this); mRecipientCheck->setObjectName(QStringLiteral("kcfg_TooManyRecipients")); helpText = i18n(KMailSettings::self()->tooManyRecipientsItem()->whatsThis().toUtf8().constData()); mRecipientCheck->setWhatsThis(helpText); @@ -358,7 +360,7 @@ mRecipientSpin->setToolTip(i18n("Set the maximum number of recipients for the warning")); connect(mRecipientCheck, &QCheckBox::stateChanged, this, &ComposerPageGeneralTab::slotEmitChanged); - connect(mRecipientSpin, QOverload::of(&QSpinBox::valueChanged), this, &ComposerPageGeneralTab::slotEmitChanged); + connect(mRecipientSpin, qOverload(&QSpinBox::valueChanged), this, &ComposerPageGeneralTab::slotEmitChanged); // only enable the spinbox if the checkbox is checked connect(mRecipientCheck, &QCheckBox::toggled, mRecipientSpin, &QSpinBox::setEnabled); @@ -383,10 +385,10 @@ mMaximumRecipients->setToolTip(helpText); mMaximumRecipients->setWhatsThis(helpText); - QLabel *label = new QLabel(MessageComposer::MessageComposerSettings::self()->maximumRecipientsItem()->label(), this); + label = new QLabel(MessageComposer::MessageComposerSettings::self()->maximumRecipientsItem()->label(), this); label->setBuddy(mMaximumRecipients); - connect(mMaximumRecipients, QOverload::of(&QSpinBox::valueChanged), this, &ConfigModuleTab::slotEmitChanged); + connect(mMaximumRecipients, qOverload(&QSpinBox::valueChanged), this, &ConfigModuleTab::slotEmitChanged); groupGridLayout->addWidget(label, row, 0, 1, 2); groupGridLayout->addWidget(mMaximumRecipients, row, 2); @@ -425,7 +427,7 @@ mMaximumRecentAddress->setToolTip(helpText); mMaximumRecentAddress->setWhatsThis(helpText); - connect(mMaximumRecentAddress, QOverload::of(&QSpinBox::valueChanged), this, &ConfigModuleTab::slotEmitChanged); + connect(mMaximumRecentAddress, qOverload(&QSpinBox::valueChanged), this, &ConfigModuleTab::slotEmitChanged); connect(mShowRecentAddressesInComposer, &QAbstractButton::toggled, mMaximumRecentAddress, &QWidget::setEnabled); connect(mShowRecentAddressesInComposer, &QAbstractButton::toggled, label, &QWidget::setEnabled); @@ -463,7 +465,7 @@ label = new QLabel(KMailSettings::self()->autosaveIntervalItem()->label(), this); label->setBuddy(mAutoSave); - connect(mAutoSave, QOverload::of(&QSpinBox::valueChanged), this, &ConfigModuleTab::slotEmitChanged); + connect(mAutoSave, qOverload(&QSpinBox::valueChanged), this, &ConfigModuleTab::slotEmitChanged); groupGridLayout->addWidget(label, row, 0); groupGridLayout->addWidget(mAutoSave, row, 1); @@ -1170,7 +1172,7 @@ mMaximumAttachmentSize->setRange(-1, 99999); mMaximumAttachmentSize->setSingleStep(100); mMaximumAttachmentSize->setSuffix(i18nc("spinbox suffix: unit for kilobyte", " kB")); - connect(mMaximumAttachmentSize, QOverload::of(&QSpinBox::valueChanged), this, &ConfigModuleTab::slotEmitChanged); + connect(mMaximumAttachmentSize, qOverload(&QSpinBox::valueChanged), this, &ConfigModuleTab::slotEmitChanged); mMaximumAttachmentSize->setSpecialValueText(i18n("No limit")); layAttachment->addWidget(mMaximumAttachmentSize); vlay->addLayout(layAttachment); diff --git a/src/configuredialog/configuredialog.h b/src/configuredialog/configuredialog.h --- a/src/configuredialog/configuredialog.h +++ b/src/configuredialog/configuredialog.h @@ -22,7 +22,7 @@ #ifndef CONFIGURE_DIALOG_H #define CONFIGURE_DIALOG_H -#include +#include #include diff --git a/src/configuredialog/configuredialog.cpp b/src/configuredialog/configuredialog.cpp --- a/src/configuredialog/configuredialog.cpp +++ b/src/configuredialog/configuredialog.cpp @@ -27,8 +27,6 @@ #include "settings/kmailsettings.h" #include "kmkernel.h" -#include -#include #include ConfigureDialog::ConfigureDialog(QWidget *parent, bool modal) @@ -39,8 +37,6 @@ |QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Cancel |QDialogButtonBox::Apply | QDialogButtonBox::Reset); setModal(modal); - KWindowSystem::setIcons(winId(), qApp->windowIcon().pixmap(IconSize(KIconLoader::Desktop), IconSize(KIconLoader::Desktop)), - qApp->windowIcon().pixmap(IconSize(KIconLoader::Small), IconSize(KIconLoader::Small))); addModule(QStringLiteral("kmail_config_accounts")); addModule(QStringLiteral("kmail_config_appearance")); addModule(QStringLiteral("kmail_config_composer")); diff --git a/src/configuredialog/configuredialog_p.h b/src/configuredialog/configuredialog_p.h --- a/src/configuredialog/configuredialog_p.h +++ b/src/configuredialog/configuredialog_p.h @@ -8,7 +8,7 @@ #include "kmail_export.h" #include "configmodule.h" -#include +#include class QTabWidget; class ConfigureDialog; diff --git a/src/configuredialog/configuremiscpage.h b/src/configuredialog/configuremiscpage.h --- a/src/configuredialog/configuremiscpage.h +++ b/src/configuredialog/configuremiscpage.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2013-2019 Montel Laurent + Copyright (c) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -37,7 +37,7 @@ explicit MiscPageFolderTab(QWidget *parent = nullptr); void save() override; - QString helpAnchor() const; + Q_REQUIRED_RESULT QString helpAnchor() const; private: void doLoadFromGlobalSettings() override; @@ -89,4 +89,22 @@ MessageViewer::PrintingSettings *mPrintingUi = nullptr; }; +#ifdef WITH_KUSERFEEDBACK +namespace KUserFeedback { +class FeedbackConfigWidget; +} +class KuserFeedBackPageTab : public ConfigModuleTab +{ + Q_OBJECT +public: + explicit KuserFeedBackPageTab(QWidget *parent = nullptr); + void save() override; + void doResetToDefaultsOther() override; + +private: + void doLoadFromGlobalSettings() override; + KUserFeedback::FeedbackConfigWidget *mUserFeedbackWidget = nullptr; +}; +#endif + #endif // CONFIGUREMISCPAGE_H diff --git a/src/configuredialog/configuremiscpage.cpp b/src/configuredialog/configuremiscpage.cpp --- a/src/configuredialog/configuremiscpage.cpp +++ b/src/configuredialog/configuremiscpage.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2013-2019 Montel Laurent + Copyright (c) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -16,22 +16,26 @@ */ #include "configuremiscpage.h" -#include "PimCommon/ConfigureImmutableWidgetUtils" +#include using namespace PimCommon::ConfigureImmutableWidgetUtils; #include "settings/kmailsettings.h" - +#include "kmkernel.h" #include -#include "MessageViewer/InvitationSettings" -#include "MessageViewer/PrintingSettings" -#include "messageviewer/messageviewersettings.h" +#include +#include +#include #include #include #include #include #include +#ifdef WITH_KUSERFEEDBACK +#include +#endif + using namespace MailCommon; QString MiscPage::helpAnchor() const { @@ -49,6 +53,10 @@ MiscPagePrintingTab *printingTab = new MiscPagePrintingTab(); addTab(printingTab, i18n("Printing")); +#ifdef WITH_KUSERFEEDBACK + KuserFeedBackPageTab *userFeedBackTab = new KuserFeedBackPageTab(); + addTab(userFeedBackTab, i18n("User Feedback")); +#endif } QString MiscPageFolderTab::helpAnchor() const @@ -71,9 +79,9 @@ i18n(KMailSettings::self()->excludeImportantMailFromExpiryItem()->whatsThis().toUtf8().constData())); connect(mMMTab.mExcludeImportantFromExpiry, &QCheckBox::stateChanged, this, &MiscPageFolderTab::slotEmitChanged); - connect(mMMTab.mLoopOnGotoUnread, QOverload::of(&KComboBox::activated), this, &MiscPageFolderTab::slotEmitChanged); - connect(mMMTab.mActionEnterFolder, QOverload::of(&KComboBox::activated), this, &MiscPageFolderTab::slotEmitChanged); - connect(mMMTab.mDelayedMarkTime, QOverload::of(&QSpinBox::valueChanged), this, &MiscPageFolderTab::slotEmitChanged); + connect(mMMTab.mLoopOnGotoUnread, qOverload(&QComboBox::activated), this, &MiscPageFolderTab::slotEmitChanged); + connect(mMMTab.mActionEnterFolder, qOverload(&QComboBox::activated), this, &MiscPageFolderTab::slotEmitChanged); + connect(mMMTab.mDelayedMarkTime, qOverload(&QSpinBox::valueChanged), this, &MiscPageFolderTab::slotEmitChanged); connect(mMMTab.mDelayedMarkAsRead, &QAbstractButton::toggled, mMMTab.mDelayedMarkTime, &QWidget::setEnabled); connect(mMMTab.mDelayedMarkAsRead, &QAbstractButton::toggled, this, &ConfigModuleTab::slotEmitChanged); connect(mMMTab.mShowPopupAfterDnD, &QCheckBox::stateChanged, this, &MiscPageFolderTab::slotEmitChanged); @@ -172,3 +180,43 @@ { mPrintingUi->save(); } + +#ifdef WITH_KUSERFEEDBACK +KuserFeedBackPageTab::KuserFeedBackPageTab(QWidget *parent) + : ConfigModuleTab(parent) +{ + mUserFeedbackWidget = new KUserFeedback::FeedbackConfigWidget(this); + QHBoxLayout *l = new QHBoxLayout(this); + l->setContentsMargins(0, 0, 0, 0); + l->addWidget(mUserFeedbackWidget); + connect(mUserFeedbackWidget, &KUserFeedback::FeedbackConfigWidget::configurationChanged, this, &KuserFeedBackPageTab::slotEmitChanged); + + if (KMKernel::self()) { + mUserFeedbackWidget->setFeedbackProvider(KMKernel::self()->userFeedbackProvider()); + } +} + +void KuserFeedBackPageTab::save() +{ + if (KMKernel::self()) { + // set current active mode + write back the config for future starts + KMKernel::self()->userFeedbackProvider()->setTelemetryMode(mUserFeedbackWidget->telemetryMode()); + KMKernel::self()->userFeedbackProvider()->setSurveyInterval(mUserFeedbackWidget->surveyInterval()); + } +} + +void KuserFeedBackPageTab::doResetToDefaultsOther() +{ + if (KMKernel::self()) { + mUserFeedbackWidget->setFeedbackProvider(KMKernel::self()->userFeedbackProvider()); + } +} + +void KuserFeedBackPageTab::doLoadFromGlobalSettings() +{ + if (KMKernel::self()) { + mUserFeedbackWidget->setFeedbackProvider(KMKernel::self()->userFeedbackProvider()); + } +} + +#endif diff --git a/src/configuredialog/configurepluginpage.h b/src/configuredialog/configurepluginpage.h --- a/src/configuredialog/configurepluginpage.h +++ b/src/configuredialog/configurepluginpage.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2016-2019 Montel Laurent + Copyright (c) 2016-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -31,7 +31,7 @@ explicit ConfigurePluginPage(QWidget *parent); ~ConfigurePluginPage() override; - QString helpAnchor() const override; + Q_REQUIRED_RESULT QString helpAnchor() const override; void load() override; void save() override; void defaults() override; diff --git a/src/configuredialog/configurepluginpage.cpp b/src/configuredialog/configurepluginpage.cpp --- a/src/configuredialog/configurepluginpage.cpp +++ b/src/configuredialog/configurepluginpage.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2016-2019 Montel Laurent + Copyright (C) 2016-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/configuredialog/configureplugins/configurepluginslistwidget.h b/src/configuredialog/configureplugins/configurepluginslistwidget.h --- a/src/configuredialog/configureplugins/configurepluginslistwidget.h +++ b/src/configuredialog/configureplugins/configurepluginslistwidget.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2016-2019 Montel Laurent + Copyright (c) 2016-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -18,7 +18,7 @@ #ifndef KMAILCONFIGUREPLUGINSLISTWIDGET_H #define KMAILCONFIGUREPLUGINSLISTWIDGET_H -#include +#include #include #include class ConfigurePluginsListWidget : public PimCommon::ConfigurePluginsListWidget @@ -38,20 +38,20 @@ void slotConfigureClicked(const QString &configureGroupName, const QString &identifier); void initializeAgentPlugins(); PimCommon::PluginUtilData createAgentPluginData(const QString &agentIdentifier, const QString &path); - bool agentActivateState(const QString &agentIdentifier, const QString &pathName); + Q_REQUIRED_RESULT bool agentActivateState(const QString &agentIdentifier, const QString &pathName); void changeAgentActiveState(const QString &agentIdentifier, const QString &path, bool enable); void saveAkonadiAgent(); - QList mPluginEditorItems; - QList mPluginMessageViewerItems; - QList mPluginCheckBeforeSendItems; - QList mPluginEditorInitItems; - QList mPluginEditorGrammarItems; - QList mPluginGenericItems; - QList mPluginWebEngineItems; - QList mPluginHeaderStyleItems; - QList mAgentPluginsItems; - QList mPluginConvertTextItems; - QList mPluginConfigureItems; + QVector mPluginEditorItems; + QVector mPluginMessageViewerItems; + QVector mPluginCheckBeforeSendItems; + QVector mPluginEditorInitItems; + QVector mPluginEditorGrammarItems; + QVector mPluginGenericItems; + QVector mPluginWebEngineItems; + QVector mPluginHeaderStyleItems; + QVector mAgentPluginsItems; + QVector mPluginConvertTextItems; + QVector mPluginConfigureItems; QVector mPluginUtilDataList; }; diff --git a/src/configuredialog/configureplugins/configurepluginslistwidget.cpp b/src/configuredialog/configureplugins/configurepluginslistwidget.cpp --- a/src/configuredialog/configureplugins/configurepluginslistwidget.cpp +++ b/src/configuredialog/configureplugins/configurepluginslistwidget.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2016-2019 Montel Laurent + Copyright (C) 2016-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -164,6 +164,7 @@ void ConfigurePluginsListWidget::doLoadFromGlobalSettings() { initialize(); + initializeDone(); } void ConfigurePluginsListWidget::doResetToDefaultsOther() @@ -206,7 +207,7 @@ pluginEditorGrammarGroupName()); //Load generic plugins - //Necessary to initialize pluging when we load it outside kmail + //Necessary to initialize plugin when we load it outside kmail KMailPluginInterface::self()->initializePlugins(); PimCommon::ConfigurePluginsListWidget::fillTopItems(KMailPluginInterface::self()->pluginsDataList(), i18n("Tools Plugins"), @@ -247,7 +248,7 @@ headerStyleGroupName()); //Load Converter plugin PimCommon::ConfigurePluginsListWidget::fillTopItems(MessageComposer::PluginEditorConvertTextManager::self()->pluginsDataList(), - i18n("Convertor Text Plugins"), + i18n("Text Conversion Plugins"), MessageComposer::PluginEditorConvertTextManager::self()->configGroupName(), MessageComposer::PluginEditorConvertTextManager::self()->configPrefixSettingKey(), mPluginConvertTextItems, diff --git a/src/configuredialog/configuresecuritypage.h b/src/configuredialog/configuresecuritypage.h --- a/src/configuredialog/configuresecuritypage.h +++ b/src/configuredialog/configuresecuritypage.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2013-2019 Montel Laurent + Copyright (c) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -37,7 +37,7 @@ Q_OBJECT public: explicit SecurityPageGeneralTab(QWidget *parent = nullptr); - QString helpAnchor() const; + Q_REQUIRED_RESULT QString helpAnchor() const; void save() override; diff --git a/src/configuredialog/configuresecuritypage.cpp b/src/configuredialog/configuresecuritypage.cpp --- a/src/configuredialog/configuresecuritypage.cpp +++ b/src/configuredialog/configuresecuritypage.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2013-2019 Montel Laurent + Copyright (c) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -16,10 +16,10 @@ */ #include "configuresecuritypage.h" -#include "PimCommon/ConfigureImmutableWidgetUtils" +#include using namespace PimCommon::ConfigureImmutableWidgetUtils; -#include "messageviewer/messageviewersettings.h" -#include "MessageComposer/MessageComposerSettings" +#include +#include #include #include #include "settings/kmailsettings.h" @@ -166,15 +166,15 @@ // "ignore", "ask", "deny", "always send" radiobuttons mMDNGroup = new QButtonGroup(this); - connect(mMDNGroup, QOverload::of(&QButtonGroup::buttonClicked), this, &SecurityPageMDNTab::slotEmitChanged); + connect(mMDNGroup, qOverload(&QButtonGroup::buttonClicked), this, &SecurityPageMDNTab::slotEmitChanged); mMDNGroup->addButton(mUi.radioIgnore, 0); mMDNGroup->addButton(mUi.radioAsk, 1); mMDNGroup->addButton(mUi.radioDeny, 2); mMDNGroup->addButton(mUi.radioAlways, 3); // "Original Message quote" radiobuttons mOrigQuoteGroup = new QButtonGroup(this); - connect(mOrigQuoteGroup, QOverload::of(&QButtonGroup::buttonClicked), this, &SecurityPageMDNTab::slotEmitChanged); + connect(mOrigQuoteGroup, qOverload(&QButtonGroup::buttonClicked), this, &SecurityPageMDNTab::slotEmitChanged); mOrigQuoteGroup->addButton(mUi.radioNothing, 0); mOrigQuoteGroup->addButton(mUi.radioFull, 1); mOrigQuoteGroup->addButton(mUi.radioHeaders, 2); @@ -281,12 +281,12 @@ connect(mWidget->warnGroupBox, &QGroupBox::toggled, this, &SecurityPageWarningTab::slotEmitChanged); connect(mWidget->mWarnUnsigned, &QCheckBox::toggled, this, &SecurityPageWarningTab::slotEmitChanged); connect(mWidget->warnUnencryptedCB, &QCheckBox::toggled, this, &SecurityPageWarningTab::slotEmitChanged); - connect(mWidget->mWarnSignKeyExpiresSB, QOverload::of(&KPluralHandlingSpinBox::valueChanged), this, &SecurityPageWarningTab::slotEmitChanged); - connect(mWidget->mWarnEncrKeyExpiresSB, QOverload::of(&KPluralHandlingSpinBox::valueChanged), this, &SecurityPageWarningTab::slotEmitChanged); - connect(mWidget->mWarnEncrChainCertExpiresSB, QOverload::of(&KPluralHandlingSpinBox::valueChanged), this, &SecurityPageWarningTab::slotEmitChanged); - connect(mWidget->mWarnSignChainCertExpiresSB, QOverload::of(&KPluralHandlingSpinBox::valueChanged), this, &SecurityPageWarningTab::slotEmitChanged); - connect(mWidget->mWarnSignRootCertExpiresSB, QOverload::of(&KPluralHandlingSpinBox::valueChanged), this, &SecurityPageWarningTab::slotEmitChanged); - connect(mWidget->mWarnEncrRootCertExpiresSB, QOverload::of(&KPluralHandlingSpinBox::valueChanged), this, &SecurityPageWarningTab::slotEmitChanged); + connect(mWidget->mWarnSignKeyExpiresSB, qOverload(&KPluralHandlingSpinBox::valueChanged), this, &SecurityPageWarningTab::slotEmitChanged); + connect(mWidget->mWarnEncrKeyExpiresSB, qOverload(&KPluralHandlingSpinBox::valueChanged), this, &SecurityPageWarningTab::slotEmitChanged); + connect(mWidget->mWarnEncrChainCertExpiresSB, qOverload(&KPluralHandlingSpinBox::valueChanged), this, &SecurityPageWarningTab::slotEmitChanged); + connect(mWidget->mWarnSignChainCertExpiresSB, qOverload(&KPluralHandlingSpinBox::valueChanged), this, &SecurityPageWarningTab::slotEmitChanged); + connect(mWidget->mWarnSignRootCertExpiresSB, qOverload(&KPluralHandlingSpinBox::valueChanged), this, &SecurityPageWarningTab::slotEmitChanged); + connect(mWidget->mWarnEncrRootCertExpiresSB, qOverload(&KPluralHandlingSpinBox::valueChanged), this, &SecurityPageWarningTab::slotEmitChanged); connect(mWidget->gnupgButton, &QPushButton::clicked, this, &SecurityPageWarningTab::slotConfigureGnupg); connect(mWidget->enableAllWarningsPB, &QPushButton::clicked, this, &SecurityPageWarningTab::slotReenableAllWarningsClicked); diff --git a/src/data/dbusmail.desktop b/src/data/dbusmail.desktop deleted file mode 100644 --- a/src/data/dbusmail.desktop +++ /dev/null @@ -1,52 +0,0 @@ -[Desktop Entry] -Type=ServiceType -X-KDE-ServiceType=DBUS/Mailer -Comment=Mail program with a D-Bus interface -Comment[ar]=برنامج بريد بواجهة D-Bus -Comment[bs]=Mail program sa D-Bus sučeljem -Comment[ca]=Un programa de correu amb una interfície de D-Bus -Comment[ca@valencia]=Un programa de correu amb una interfície de D-Bus -Comment[cs]=Poštovní program s DBUS rozhraním -Comment[da]=E-mail-program med en D-BUS-grænseflade -Comment[de]=E-Mail-Programm mit D-Bus-Schnittstelle -Comment[el]=Πρόγραμμα αλληλογραφίας με διασύνδεση D-Bus -Comment[en_GB]=Mail program with a D-Bus interface -Comment[es]=Programa de correo con una interfaz D-Bus -Comment[et]=E-posti rakendus D-Busi liidesega -Comment[fi]=D-Bus-rajapintainen sähköpostiohjelma -Comment[fr]=Programme de messagerie avec une interface D-Bus -Comment[ga]=Clár ríomhphoist a bhfuil comhéadan D-Bus aige -Comment[gl]=Programa de correo electrónico cunha interface D-BUS -Comment[hu]=Levelezőprogram D-Bus-os felülettel -Comment[ia]=Programma de e-posta con interfacie D-Bus -Comment[it]=Programma di posta con un'interfaccia D-Bus -Comment[ja]=D-Bus インターフェースを持つメールクライアント -Comment[kk]=DBUS интерфейсті пошта бағдарламасы -Comment[km]=កម្មវិធី​សំបុត្រ​ដែល​មាន​ចំណុច​ប្រទាក់ D-BUS -Comment[ko]=D-Bus 인터페이스를 사용하는 이메일 프로그램 -Comment[lt]=Pašto programa su D-Bus sąsaja -Comment[lv]=Pasta programma ar D-BUS saskarni -Comment[mr]=DBus संवादासहीतचा मेल कार्यक्रम -Comment[nb]=E-postprogram med D-Bus-grensesnitt -Comment[nds]=Nettpostprogramm mit en D-Bus-Koppelsteed -Comment[nl]=E-mailprogramma met een D-Bus-interface -Comment[nn]=E-postprogram med eit D-Bus-grensesnitt -Comment[pa]=ਇੱਕ ਡੀਬੱਸ ਇੰਟਰਫੇਸ ਨਾਲ ਮੇਲ ਪਰੋਗਰਾਮ -Comment[pl]=Program pocztowy z interfejsem D-Bus -Comment[pt]=Um programa de correio electrónico com uma interface D-Bus -Comment[pt_BR]=Programa de e-mail com interface D-Bus -Comment[ro]=Program de poștă cu interfață D-Bus -Comment[ru]=Почтовый клиент с интерфейсом D-Bus -Comment[sk]=Poštový program s D-Bus rozhraním -Comment[sl]=Poštni program z vmesnikom D-Bus -Comment[sr]=Поштански програм са д‑бус сучељем -Comment[sr@ijekavian]=Поштански програм са д‑бус сучељем -Comment[sr@ijekavianlatin]=Poštanski program sa D‑Bus sučeljem -Comment[sr@latin]=Poštanski program sa D‑Bus sučeljem -Comment[sv]=E-postprogram med D-Bus gränssnitt -Comment[tr]=D-Bus arayüzü olan e-posta uygulaması -Comment[uk]=Програма ел. пошти з інтерфейсом D-Bus -Comment[wa]=Programe d' emilaedje avou ene eterface D-Bus -Comment[x-test]=xxMail program with a D-Bus interfacexx -Comment[zh_CN]=具有 D-BUS 接口的邮件程序 -Comment[zh_TW]=有 D-Bus 介面的郵件程式 diff --git a/src/data/kmail2.notifyrc b/src/data/kmail2.notifyrc --- a/src/data/kmail2.notifyrc +++ b/src/data/kmail2.notifyrc @@ -1,5 +1,6 @@ [Global] IconName=kmail +DesktopEntry=org.kde.kmail Comment=KMail Comment[af]=KMail Comment[ar]=بريدك @@ -83,6 +84,7 @@ Name[en_GB]=Akonadi server sent a warning Name[es]=El servidor Akonadi envió un aviso Name[et]=Akonadi server saatis hoiatuse +Name[eu]=Akonadi zerbitzariak abisu bat bidali du Name[fi]=Akonadi-palvelin lähetti varoituksen Name[fr]=Avertissement du serveur Akonadi Name[gl]=O servidor de Akonadi enviou unha advertencia @@ -127,6 +129,7 @@ Comment[en_GB]=Akonadi server sent a warning Comment[es]=El servidor Akonadi envió un aviso Comment[et]=Akonadi server saatis hoiatuse +Comment[eu]=Akonadi zerbitzariak abisu bat bidali du Comment[fi]=Akonadi-palvelin lähetti varoituksen Comment[fr]=Avertissement du serveur Akonadi Comment[gl]=O servidor de Akonadi enviou unha advertencia @@ -174,6 +177,7 @@ Name[en_GB]=Akonadi server sent an error Name[es]=El servidor Akonadi envión un error Name[et]=Akonadi server saatis vea +Name[eu]=Akonadi zerbitzariak errore bat bidali du Name[fi]=Akonadi-palvelin lähetti virheen Name[fr]=Erreur du serveur Akonadi Name[gl]=O servidor de Akonadi enviou un erro @@ -218,6 +222,7 @@ Comment[en_GB]=Akonadi server sent an error Comment[es]=El servidor Akonadi envió un error Comment[et]=Akonadi server saatis vea +Comment[eu]=Akonadi zerbitzariak errore bat bidali du Comment[fi]=Akonadi-palvelin lähetti virheen Comment[fr]=Erreur du serveur Akonadi Comment[gl]=O servidor de Akonadi enviou un erro @@ -265,6 +270,7 @@ Name[en_GB]=A resource is broken Name[es]=Un recurso está dañado Name[et]=Ressurss on katki +Name[eu]=Baliabide bat hondatuta dago Name[fi]=Resurssi on rikki Name[fr]=Une ressource est endommagée Name[gl]=Un recurso está estragado @@ -308,6 +314,7 @@ Comment[en_GB]=A resource change its state to broken Comment[es]=Un recurso cambia su estado a dañado Comment[et]=Ressurssi olekuks on nüüd katki. +Comment[eu]=Baliabide batek bere egoera hondatura aldatu du Comment[fi]=Resurssi vaihtoi tilakseen ”rikki” Comment[fr]=Une ressource a changé son état à « endommagé » Comment[gl]=Un recurso cambiou de estado a «estragado». @@ -346,33 +353,55 @@ Name=Impossible to send email Name[ca]=És impossible enviar el correu Name[ca@valencia]=És impossible enviar el correu +Name[cs]=E-mail nelze odeslat +Name[de]=Nachrichten kann nicht versendet werden Name[en_GB]=Impossible to send email Name[es]=No es posible enviar correo +Name[et]=Kirja ei ole võimalik saata +Name[eu]=Ezin da e-posta bidali +Name[fi]=Sähköpostin lähettäminen on mahdotonta Name[fr]=Impossible d'envoyer le courrier électronique Name[gl]=Non se pode enviar a mensaxe +Name[ia]=Impossibile inviar e-posta Name[it]=Impossibile inviare il messaggio di posta Name[ko]=이메일을 보낼 수 없음 Name[nl]=Verzenden van een e-mail is onmogelijk -Name[pt]=Não é possível enviar o e-mail +Name[pl]=Nie można wysłać wiadomości +Name[pt]=Não foi possível enviar o e-mail Name[pt_BR]=Não foi possível enviar o e-mail +Name[ru]=Невозможно отправить письмо +Name[sk]=Nemožné poslať email +Name[sl]=Ni bilo mogoče poslati e-pošte Name[sv]=Omöjligt att skicka e-post Name[uk]=Не вдалося надіслати повідомлення Name[x-test]=xxImpossible to send emailxx +Name[zh_CN]=无法发送电子邮件 Comment=Problem during send mail Comment[ca]=Problema durant l'enviament del correu Comment[ca@valencia]=Problema durant l'enviament del correu +Comment[cs]=Během odesílání e-mailu nastaly problémy +Comment[de]=Probleme beim Versenden der E-Mail Comment[en_GB]=Problem during send mail Comment[es]=Problema al enviar correo +Comment[et]=Probleem kirja saatmisel +Comment[eu]=Arazoa posta bidali bitartean +Comment[fi]=Ongelma lähetettäessä sähköpostia Comment[fr]=Problème lors de l'envoi du courrier électronique Comment[gl]=Problema ao enviar o correo +Comment[ia]=Problema durante expedition de e-posta Comment[it]=Problema durante l'invio della posta Comment[ko]=이메일 전송 중 문제 발생 -Comment[nl]=Probleem bij verzenden van e-mail -Comment[pt]=Problemas durante o envio do e-mail +Comment[nl]=probleem bij verzenden van e-mail +Comment[pl]=Błąd podczas wysyłania poczty +Comment[pt]=Ocorreu um problema no envio do e-mail Comment[pt_BR]=Problema ao enviar o e-mail +Comment[ru]=Ошибка отправки электронной почты +Comment[sk]=Chyba pri odosielaní mailu +Comment[sl]=Problem med pošiljanjem e-pošte Comment[sv]=Problem när e-post skulle skickas Comment[uk]=Проблема під час надсилання пошти Comment[x-test]=xxProblem during send mailxx +Comment[zh_CN]=发送邮件时出现问题 Action=Popup [Event/folderarchivedone] @@ -388,6 +417,7 @@ Name[en_GB]=Archive Mails in Folder done Name[es]=Archivado de correos en carpeta terminado Name[et]=Kirjad on kausta arhiveeritud +Name[eu]=Postak karpetan artxibatzea osatu da Name[fi]=Viestien arkistointi kansioihin valmis Name[fr]=Archivage des dossiers terminé Name[gl]=Rematou «Arquivar o correo do cartafol» @@ -414,7 +444,7 @@ Name[uk]=Архівування пошти до теки завершено Name[x-test]=xxArchive Mails in Folder donexx Name[zh_CN]=文件夹中的邮件归档完成 -Name[zh_TW]=資料夾中的郵件已歸檔完成 +Name[zh_TW]=資料夾中的郵件已封存完成 Action=None [Event/folderarchiveerror] @@ -429,6 +459,7 @@ Name[en_GB]=Folder Archive Error Name[es]=Error de archivado de carpeta Name[et]=Kirjade arhiveerimise tõrge +Name[eu]=Karpeta artxibatzeko errorea Name[fi]=Kansion arkistointivirhe Name[fr]=Erreur d'archivage des dossiers Name[gl]=Erro do arquivo de cartafoles @@ -440,7 +471,7 @@ Name[nb]=Feil i postarkiv Name[nds]=Orner-Archiveerfehler Name[nl]=fout in archiveren van map -Name[pl]=Usługa archiwizacji poczty +Name[pl]=Usługa archiwizowania poczty Name[pt]=Erro no Arquivo de Pastas Name[pt_BR]=Erro no arquivamento de pastas Name[ru]=Ошибка архивирования папки @@ -455,5 +486,41 @@ Name[uk]=Помилка архівування до теки Name[x-test]=xxFolder Archive Errorxx Name[zh_CN]=文件夹归档错误 -Name[zh_TW]=資料夾歸檔錯誤 +Name[zh_TW]=資料夾封存錯誤 Action=Popup + +[Event/undosend] +Name=Email added to the send later queue +Name[ca]=Correu afegit a la cua d'enviar més tard +Name[ca@valencia]=Correu afegit a la cua d'enviar més tard +Name[en_GB]=Email added to the send later queue +Name[es]=Mensaje añadido a la cola para enviar más tarde +Name[et]=Kiri lisati hiljem saatmise järjekorda +Name[fr]=Courriel ajouté à la liste des courriels à envoyer plus tard +Name[it]=Messaggio di posta aggiunto alla coda di invio posticipato +Name[ko]=이메일이 나중에 보내기 대기열에 추가됨 +Name[nl]=E-mail toegevoegd aan de rij Later verzenden +Name[pt]=E-mail adicionado à fila de espera para envio posterior +Name[pt_BR]=E-mail adicionado à fila de enviar mais tarde +Name[ru]=Письмо добавлено в очередь отложенной доставки +Name[sv]=E-post tillagd i kö för att skicka senare +Name[uk]=Повідомлення додано до черги відкладеного надсилання +Name[x-test]=xxEmail added to the send later queuexx +Comment=A delayed email delivery is configured and can be canceled +Comment[ca]=S'ha configurat un lliurament de correu retardat i es pot cancel·lar +Comment[ca@valencia]=S'ha configurat un lliurament de correu retardat i es pot cancel·lar +Comment[en_GB]=A delayed email delivery is configured and can be cancelled +Comment[es]=Se ha configurado un envío de correo aplazado, que se puede cancelar +Comment[et]=Seadistatud on viivitusega kirja saatmine, nii et sellest võib ka loobuda +Comment[fr]=Un envoi de courriel différé est configuré et peut être annulé +Comment[it]=Una consegna posticipata di un messaggio è ora configurata e può essere annullata +Comment[ko]=지연된 이메일 전송이 설정되었고 취소할 수 있음 +Comment[nl]=Er is een vertraagde e-mail aflevering geconfigureerd en deze kan geannuleerd worden +Comment[pt]=Está configurada uma entrega de e-mail posterior e pode ser cancelada +Comment[pt_BR]=Uma entrega de e-mails atrasada está configurada e pode ser cancelada. +Comment[ru]=Отложенная отправка письма уже запланирована и не может быть отменена +Comment[sv]=En fördröjd e-postleverans är inställd och kan avbrytas +Comment[uk]=Налаштовано відкладене надсилання пошти, його можна скасувати +Comment[x-test]=xxA delayed email delivery is configured and can be canceledxx +Action=Popup +Urgency=Normal diff --git a/src/data/kmail_config_accounts.desktop b/src/data/kmail_config_accounts.desktop --- a/src/data/kmail_config_accounts.desktop +++ b/src/data/kmail_config_accounts.desktop @@ -100,7 +100,7 @@ Comment[eo]=Agordo por sendi kaj ricevi mesaĝojn Comment[es]=Configuración para enviar y recibir mensajes Comment[et]=Kirjade saatmise ja saamise seadistused -Comment[eu]=Mezuak bidali eta jasotzeko konfigurazioa +Comment[eu]=Mezuak bidali eta jasotzeko ezarpena Comment[fa]=برپایی برای ارسال و دریافت پیامها Comment[fi]=Viestien lähetys- ja vastaanottoasetukset Comment[fr]=Configuration de l'envoi et de la réception de messages @@ -161,6 +161,7 @@ X-KDE-Keywords[en_GB]=kmail,accounts X-KDE-Keywords[es]=kmail,cuentas X-KDE-Keywords[et]=kmail,kontod +X-KDE-Keywords[eu]=kmail,kontuak X-KDE-Keywords[fi]=kmail,accounts,tilit X-KDE-Keywords[fr]=kmail,comptes X-KDE-Keywords[ga]=kmail,cuntais diff --git a/src/data/kmail_config_appearance.desktop b/src/data/kmail_config_appearance.desktop --- a/src/data/kmail_config_appearance.desktop +++ b/src/data/kmail_config_appearance.desktop @@ -102,7 +102,7 @@ Comment[en_GB]=Customise Visual Appearance Comment[es]=Personalizar la apariencia visual Comment[et]=Välimuse seadistused -Comment[eu]=Pertsonalizatu itxura +Comment[eu]=Egokitu itxura norbere erara Comment[fa]=سفارشی کردن ظاهر تصویری Comment[fi]=Mukauta ulkoasua Comment[fr]=Personnalisation de l'apparence @@ -164,6 +164,7 @@ X-KDE-Keywords[en_GB]=kmail,appearance X-KDE-Keywords[es]=kmail,apariencia X-KDE-Keywords[et]=kmail,välimus +X-KDE-Keywords[eu]=kmail,itxura X-KDE-Keywords[fi]=kmail,appearance,ulkoasu X-KDE-Keywords[fr]=kmail,apparence X-KDE-Keywords[ga]=kmail,cuma diff --git a/src/data/kmail_config_composer.desktop b/src/data/kmail_config_composer.desktop --- a/src/data/kmail_config_composer.desktop +++ b/src/data/kmail_config_composer.desktop @@ -92,6 +92,7 @@ Comment[en_GB]=Message Composer Settings Comment[es]=Preferencias del editor de mensajes Comment[et]=Kirjakoostaja seadistused +Comment[eu]=Mezu editoreko ezarpenak Comment[fi]=Viestimuokkaimen asetukset Comment[fr]=Configuration de l'éditeur de messages Comment[gl]=Configuracións do compositor de mensaxes @@ -102,7 +103,7 @@ Comment[kk]=Хат құрастарғышын баптау Comment[km]=ការ​កំណត់​កម្មវិធី​តែង​សារ Comment[ko]=메시지 작성기 설정 -Comment[lt]=Laiškų rengyklės nustatymai +Comment[lt]=Laiškų rengyklės nuostatos Comment[lv]=Vēstuļu rastītāja iestatījumi Comment[mr]=संदेश संपादक संयोजना Comment[nb]=Innstillinger for meldingskomposer @@ -139,6 +140,7 @@ X-KDE-Keywords[en_GB]=kmail,composer X-KDE-Keywords[es]=kmail,editor X-KDE-Keywords[et]=kmail,koostaja +X-KDE-Keywords[eu]=kmail,editorea X-KDE-Keywords[fi]=kmail,composer, kirjoittaminen X-KDE-Keywords[fr]=kmail,éditeur X-KDE-Keywords[ga]=kmail,cumadóir diff --git a/src/data/kmail_config_misc.desktop b/src/data/kmail_config_misc.desktop --- a/src/data/kmail_config_misc.desktop +++ b/src/data/kmail_config_misc.desktop @@ -30,7 +30,7 @@ Name[en_GB]=Misc Name[es]=Varios Name[et]=Muud -Name[eu]=Miszelanea +Name[eu]=Hainbat Name[fi]=Muut Name[fr]=Divers Name[fy]=Ferskate @@ -115,7 +115,7 @@ Comment[kk]=Басқа параметрлері Comment[km]=ការ​កំណត់​ដែល​មិន​ត្រូវ​នឹង​កន្លែង​ផ្សេង Comment[ko]=어떤 곳에도 어울리지 않는 설정 -Comment[lt]=Kiti nustatymai +Comment[lt]=Kitos nuostatos Comment[lv]=Iestatījumi, kas citur neiederas Comment[mk]=Поставувања што не се вклопуваат на друго место Comment[mr]=कोठेही न बसणाऱ्या संयोजना @@ -140,7 +140,7 @@ Comment[sr@latin]=Postavke koje ne pripadaju drugde Comment[sv]=Inställningar som inte passar någon annanstans Comment[ta]=அமைப்புகள் எந்த இடத்திலும் பொருந்தவில்லை -Comment[tg]=Дигар танзимотҳо +Comment[tg]=Дигар танзимот Comment[tr]=Diğer bölümlere uymayan yapılandırma seçenekleri Comment[uk]=Інші параметри Comment[wa]=Apontiaedjes k' on n' sait wice mete d' ôte @@ -159,6 +159,7 @@ X-KDE-Keywords[en_GB]=kmail,misc X-KDE-Keywords[es]=kmail,miscelánea X-KDE-Keywords[et]=kmail,muud +X-KDE-Keywords[eu]=kmail,hainbat X-KDE-Keywords[fi]=kmail,misc,muut X-KDE-Keywords[fr]=kmail,divers X-KDE-Keywords[ga]=kmail,éagsúil diff --git a/src/data/kmail_config_plugins.desktop b/src/data/kmail_config_plugins.desktop --- a/src/data/kmail_config_plugins.desktop +++ b/src/data/kmail_config_plugins.desktop @@ -30,7 +30,7 @@ Name[eo]=Kromaĵoj Name[es]=Complementos Name[et]=Pluginad -Name[eu]=Plugin-ak +Name[eu]=Pluginak Name[fa]=وصله‌ها Name[fi]=Liitännäiset Name[fr]=Modules externes @@ -93,9 +93,11 @@ Comment[en_GB]=Settings Plugins Comment[es]=Preferencias de complementos Comment[et]=Seadistusplugin +Comment[eu]=Ezarpen pluginak Comment[fi]=Asetusliitännäiset Comment[fr]=Modules de paramètres Comment[gl]=Complementos de configuración +Comment[ia]=Plugins de preferentias Comment[it]=Estensioni per le impostazioni Comment[ko]=설정 플러그인 Comment[nl]=Plug-ins voor instellingen @@ -125,9 +127,11 @@ X-KDE-Keywords[en_GB]=kmail,plugins X-KDE-Keywords[es]=kmail,complementos X-KDE-Keywords[et]=kmail,pluginad +X-KDE-Keywords[eu]=kmail,pluginak X-KDE-Keywords[fi]=kmail,liitännäiset X-KDE-Keywords[fr]=kmail,modules X-KDE-Keywords[gl]=kmail,complementos +X-KDE-Keywords[ia]=kmail,plugins X-KDE-Keywords[it]=kmail,estensioni X-KDE-Keywords[ko]=kmail,plugins,플러그인 X-KDE-Keywords[nl]=kmail,plug-ins diff --git a/src/data/kmail_config_security.desktop b/src/data/kmail_config_security.desktop --- a/src/data/kmail_config_security.desktop +++ b/src/data/kmail_config_security.desktop @@ -31,7 +31,7 @@ Name[eo]=Sekureco Name[es]=Seguridad Name[et]=Turvalisus -Name[eu]=Sekuritatea +Name[eu]=Segurtasuna Name[fa]=امنیت Name[fi]=Turvallisuus Name[fr]=Sécurité @@ -92,17 +92,17 @@ Comment[bg]=Настройки на сигурността Comment[br]=Kefluniadur surentez ar buhez prevez Comment[bs]=Postavke sigurnosti i privatnosti -Comment[ca]=Arranjament de seguretat i privadesa -Comment[ca@valencia]=Arranjament de seguretat i privadesa +Comment[ca]=Arranjament de la seguretat i privadesa +Comment[ca@valencia]=Arranjament de la seguretat i privadesa Comment[cs]=Nastavení soukromí a zabezpečení Comment[da]=Sikkerheds- & Privathedsindstillinger Comment[de]=Sicherheit und Privatsphäre Comment[el]=Ρυθμίσεις Ασφάλειας & Προσωπικού απόρρητου Comment[en_GB]=Security & Privacy Settings Comment[eo]=Agordoj pri Sekureco kaj Privateco Comment[es]=Preferencias de seguridad y privacidad Comment[et]=Turva- ja privaatsusseadistused -Comment[eu]=Sekuritate & pribakortasun ezarpenak +Comment[eu]=Segurtasun eta pribatutasun ezarpenak Comment[fa]=امنیت و تنظیمات محرمانگی Comment[fi]=Turvallisuus- ja yksityisyysasetukset Comment[fr]=Paramètres de sécurité et de confidentialité @@ -119,7 +119,7 @@ Comment[kk]=Қауіпсіздігі пен Дербестік параметрлері Comment[km]=ការ​កំណត់​សុវត្ថិភាព & ភាព​ឯកជន Comment[ko]=보안과 개인 정보 설정 -Comment[lt]=Saugumo ir privatumo nustatymai +Comment[lt]=Saugumo ir privatumo nuostatos Comment[lv]=Drošības un privātuma iestatījumi Comment[mk]=Поставувања за безбедност и приватност Comment[mr]=सुरक्षा व गुप्तता संयोजना @@ -164,6 +164,7 @@ X-KDE-Keywords[en_GB]=kmail,security X-KDE-Keywords[es]=kmail,seguridad X-KDE-Keywords[et]=kmail,turvalisus +X-KDE-Keywords[eu]=kmail,segurtasuna X-KDE-Keywords[fi]=kmail,security,turvallisuus X-KDE-Keywords[fr]=kmail,sécurité X-KDE-Keywords[ga]=kmail,slándáil diff --git a/src/data/kmail_view.desktop b/src/data/kmail_view.desktop --- a/src/data/kmail_view.desktop +++ b/src/data/kmail_view.desktop @@ -11,6 +11,7 @@ Name[en_GB]=KMail view Name[es]=Vista KMail Name[et]=KMaili vaade +Name[eu]=KMail ikuspegia Name[fi]=KMail-näkymä Name[fr]=KMail view Name[ga]=Amharc KMail @@ -54,6 +55,7 @@ NoDisplay=true MimeType=message/rfc822;application/mbox;application/x-mimearchive; +X-KDE-Protocols=akonadi X-KDE-StartupNotify=true X-DBUS-StartupType=Unique X-DBUS-ServiceName=org.kde.kmail diff --git a/src/data/org.kde.kmail.service.in b/src/data/org.kde.kmail.service.in new file mode 100644 --- /dev/null +++ b/src/data/org.kde.kmail.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.kde.kmail +Exec=${CMAKE_INSTALL_FULL_BINDIR}/kmail diff --git a/src/data/org.kde.kmail2.appdata.xml b/src/data/org.kde.kmail2.appdata.xml --- a/src/data/org.kde.kmail2.appdata.xml +++ b/src/data/org.kde.kmail2.appdata.xml @@ -10,15 +10,19 @@ Die KDE-Gemeinschaft The KDE Community La comunidad de KDE + KDE kogukond KDE-yhteisö La communauté KDE A comunidade de KDE Komunitas KDE La comunità KDE + KDE 커뮤니티 De KDE gemeenschap Społeczność KDE A Comunidade do KDE A comunidade KDE + KDE Komunita + Skupnost KDE KDE-gemenskapen Спільнота KDE xxThe KDE Communityxx @@ -67,18 +71,23 @@

A feature-rich email application Una aplicació de correu electrònic rica en característiques Una aplicació de correu electrònic rica en característiques + Dobře vybavená aplikace na e-maily Ein E-Mail-Programm mit vielen Funktionen A feature-rich email application Una aplicación de correo rica en características + Võimalusterohke e-posti rakendus Sähköpostisovellus. Une application de courriel riche en fonctionnalités - Un aplicativo de correo electrónico con moitas funcionalidades + Unha aplicación de correo electrónico con moitas funcionalidades Sebuah aplikasi email yang kaya fitur Un programma di posta elettronica ricco di funzioni + 다기능 이메일 프로그램 Een e-mailtoepassing met veel mogelijkheden Zaawansowana aplikacja pocztowa Uma aplicação de e-mail rica em funcionalidades Um aplicativo de e-mail rico em recursos + E-mailová aplikácia bohatá na funkcie + Program z veliko funkcijami za elektronsko pošto Ett funktionsrikt e-postprogram Багата на можливості програма для роботи з електронною пошти xxA feature-rich email applicationxx @@ -92,13 +101,18 @@

El KMail és un client de correu electrònic d'última generació que s'integra bé amb els proveïdors de correu electrònic àmpliament emprats com el GMail. Proporciona moltes eines i característiques per a maximitzar la productivitat i fer que el treballa amb els comptes de correu electrònic siga fàcil i ràpid. El KMail admet una gran varietat de protocols de correu electrònic: POP3, IMAP, Microsoft Exchange (EWS) i molts més.

KMail is a state-of-the-art email client that integrates well with widely used email providers like GMail. It provides many tools and features to maximise your productivity and makes working with large email accounts easy and fast. KMail supports a large variety of email protocols - POP3, IMAP, Microsoft Exchange (EWS) and more.

KMail es un cliente de correo de última generación que se integra bien con proveedores de correo ampliamente usaos como GMail. Proporciona varias herramientas y funcionalidades para maximizar la productividad y hacer fácil y rápido el trabajo con grandes cuentas de correo. KMail implementa una gran variedad de protocolos de correo - POP3, IMAP, Microsoft Exchange (EWS) y todavía más.

+

KMail on tipptasemel e-posti klient, mis lõimub kenasti selliste levinud e-posti teenuse pakkujatega, nagu näiteks GMail. See pakub rohkelt tööriistu ja omadusi kasutaja elu hõlbustamiseks ning muudab ka mahukate e-posti kontodega tegelemise hõlpsaks ja kiireks. KMail toetab paljusid e-posti protokolle: POP3, IMAP, Microsoft Exchange (EWS) ja paljusid teisi.

KMail on nykyaikainen sähköpostiohjelma, joka integroituu hyvin laajalti käytettyihin sähköpostitarjoajiin kuten GMailiin. Se tarjoaa työkaluja ja piirteitä, joilla maksimoit tuottavuutesi ja hallitset vaivatta suuriakin sähköpostitilejä. KMail tukee useita sähköpostiyhteyskäytäntöjä: POP3:a, IMAPia, Microsoft Exchangea (EWS) jne.

KMail é un cliente de correo electrónico de última xeración que se integra ben con fornecedores de correo electrónico populares como GMail. Fornece moitas ferramentas para maximizar a produtividade e facilita e acelera o traballo con grandes contas de correo electrónico. KMail é compatíbel cunha gran variedade de protocolos de correo electrónico: POP3, IMAP, Microsoft Exchange (EWS) e máis.

KMail adalah klien email canggih yang terintegrasi baik dengan penyedia email yang banyak digunakan seperti GMail. Ini menyediakan banyak alat dan fitur untuk memaksimalkan produktivitas Anda dan membuat bekerja dengan akun email besar mudah dan cepat. KMail mendukung beragam protokol email - POP3, IMAP, Microsoft Exchange (EWS) dan banyak lagi.

KMail è un client di posta elettronica allo stato dell'arte che si integra bene con fornitori di posta molto usati come GMail. Fornisce molti strumenti e funzioni per massimizzare la tua produttività e rendere facile e veloce l'uso di grandi account di posta. KMail supporta un'ampia gamma di protocolli di posta elettronica - POP3, IMAP, Microsoft Exchange (EWS) ed altri.

+

KMail은 GMail과 같은 이메일 서비스를 사용하는 최신 이메일 클라이언트입니다. 여러 생산성 향상용 도구와 기능이 있으며 대형 이메일 계정 사용도 쉽고 빠릅니다. KMail은 POP3, IMAP, Microsoft Exchange(EWS) 등 여러 이메일 프로토콜을 지원합니다.

KMail is een zeer moderne e-mailclient die goed integreert met breed gebruikte e-mailleveranciers zoals GMail. Het biedt vele hulpmiddelen en functies om uw productiviteit te maximaliseren en maakt werken met grote e-mailaccounts gemakkelijk en snel. KMail ondersteunt een grote variëteit van e-mailprotocollen - POP3, IMAP, Microsoft Exchange (EWS) en meer.

KMail jest pełnowartościowym klientem pocztowym, który współgra z powszechnie wykorzystywanymi dostawcami pocztowymi takimi jak GMail. Zapewnia wiele narzędzi i daje wiele możliwości do maksymalizacji produktywności przez co czyni zarządzanie dużymi kontami pocztowymi łatwym i szybkim. KMail obsługuje różne protokoły pocztowe - POP3, IMAP, Microsoft Exchange (EWS) i więcej.

O KMail é um cliente de e-mail do estado-da-arte que se integra bem com os fornecedores de e-mail largamente usados, como o GMail. Ele oferece várias ferramentas e funcionalidades para maximizar a sua produtividade e torna simples e rápido o tratamento de contas de correio grandes. O KMail suporta uma grande variedade de protocolos de e-mail - POP3, IMAP, Microsoft Exchange (EWS), entre outros.

+

KMail é um cliente de e-mail que se integra muito bem com os provedores de e-mail amplamente utilizados, como o GMail. Ele oferece várias ferramentas e funcionalidades para maximizar a sua produtividade e torna simples e rápido o tratamento de contas de e-mail grandes. O KMail tem suporte a uma grande variedade de protocolos de e-mail - POP3, IMAP, Microsoft Exchange (EWS), entre outros.

+

KMail je najmodernejší e-mailový klient, ktorý sa dobre integruje s bežne používanými poskytovateľmi e-mailov, ako je GMail. Poskytuje mnoho nástrojov a funkcií na maximalizáciu vašej produktivity, uľahčuje a zrýchľuje prácu s veľkými e-mailovými účtami. KMail podporuje veľké množstvo e-mailových protokolov - POP3, IMAP, Microsoft Exchange (EWS) a ďalšie.

+

KMail je najsodobnejši odjemalec e-pošte, ki je dobro integriran s širokim uporabljeni ponudniki e-pošte, kot je GMail. Ponuja veliko orodij in funkcij za maksimiziranje vaše produktivnosti ter za lahko in hitro delo z veliko e-poštnimi računi. KMail podpira veliko različnih e-poštnih protokolov - POP3, IMAP, Microsoft Exchange (EWS) in druge.

Kmail är en toppmodern e-postprogram som är väl integrerad med använda i stor utsträckning, såsom GMail. Det tillhandahåller många verktyg och funktioner för att maximera din produktivitet och gör det snabbt och enkelt att arbeta med stora e-postkonton. Kmail stöder ett stort antal e-postprotokoll: POP3, IMAP, Microsoft Exchange (EWS) med flera.

KMail — самодостатня програма для роботи з електронною поштою, яка дуже просто інтегрується зі службами надання послуг електронної пошти, зокрема GMail. У ній передбачено багато засобів та можливостей максимального сприяння вашій продуктивності. Вона робить роботу із об'ємними архівами електронної пошти простою і швидкою. У KMail передбачено підтримку широкого діапазону протоколів електронної пошти — POP3, IMAP, Microsoft Exchange (EWS) тощо.

xxKMail is a state-of-the-art email client that integrates well with widely used email providers like GMail. It provides many tools and features to maximize your productivity and makes working with large email accounts easy and fast. KMail supports a large variety of email protocols - POP3, IMAP, Microsoft Exchange (EWS) and more.xx

@@ -148,58 +162,78 @@
  • Segur: el KMail té els ajustaments predeterminats segurs per a protegir la vostra privadesa, una implementació d'encriptatge extrem a extrem i detecció del correu brossa.
  • Secure - KMail has secure default settings to protect your privacy, great end-to-end encryption support, and spam detection.
  • Seguro - Kmail dispone de preferencias predeterminadas seguras, para proteger su confidencialidad, implementación de cifrado de principio a fin, y detección de correo basura.
  • +
  • Turvalisus - KMaili seadistused kaitsevad juba vaikimisi sinu privaatsust ning toetavad suurepäraselt suhtlemise krüptimist ja rämpsposti tuvastamist.
  • Turvallisuus: KMailin oletusasetukset turvaavat yksityisyytesi, salaavat viestin lähettäjältä vastaanottajalle ja tunnistavat roskapostin.
  • Seguro — KMail ten unha configuración predeterminada segura para protexer a súa intimidade, unha gran compatibilidade con cifrado de punto a punto, e detección de correo non desexado.
  • -
  • Aman - KMail memiliki setingan baku yang aman untuk melindungi privasi Anda, dukungan enkripsi end-to-end yang hebat, dan deteksi spam.
  • +
  • Aman - KMail memiliki setingan baku yang aman untuk memproteksi privasi Anda, dukungan enkripsi end-to-end yang hebat, dan deteksi spam.
  • Sicuro - KMail ha impostazioni predefinite sicure per proteggere la tua riservatezza, un notevole supporto per la cifratura tra entrambi i capi della comunicazione (end-to-end), e il rilevamento dello spam.
  • +
  • 보안 - KMail의 기본 설정은 개인 정보 보호, 종단간 암호화 지원, 스팸 감지를 활성화합니다.
  • Veilig - KMail heeft veilige standaard instellingen om uw privacy te beschermen, zeer goede ondersteuning van end-to-end encryptie en spamdetectie.
  • Bezpieczny - Domyślne ustawienia KMail są bezpieczne, tak aby chronić twoją prywatność, zapewnić dobrą obsługę szyfrowania i wykrywania spamu.
  • Seguro - o KMail tem configurações predefinidas seguras para proteger a sua privacidade, um suporte óptimo de encriptação de um extremo ao outro e detecção de lixo electrónico.
  • +
  • Seguro - O KMail tem configurações predefinidas seguras para proteger a sua privacidade, um excelente suporte para criptografia de ponta-a-ponta e detecção de spam.
  • +
  • Bezpečný - KMail má bezpečné predvolené nastavenia na ochranu vášho súkromia, skvelú podporu šifrovania end-to-end a detekciu spamu.
  • +
  • Varno - KMail ima varne privzete nastavitve za zaščito vaše zasebnosti, celovito podporo za šifriranje in odkrivanje neželene pošte.
  • Säkert: Kmail har säkra standardinställningar för att skydda din integritet, enastående genomgående krypteringsstöd, och skräppostdetektering.
  • Безпека — типові параметри роботи KMail є безпечними, вони захистять ваші конфіденційні дані, забезпечать наскрізне шифрування даних та запобігатимуть появі спаму.
  • xxSecure - KMail has secure default settings to protect your privacy, great end-to-end encryption support, and spam detection.xx
  • Powerful - Features include offline support, multiple sender identities, multi-language support, powerful filtering, searching and tagging functionality, mailing list management and very flexible configuration.
  • Potent: les característiques inclouen compatibilitat amb fora de línia, múltiples identitats de remitents, suport multilingüe, filtratge potent, funcionalitat de cerca i etiquetatge, gestió de les llistes de correu i una configuració molt flexible.
  • Potent: les característiques inclouen compatibilitat amb fora de línia, múltiples identitats de remitents, suport multilingüe, filtratge potent, funcionalitat de cerca i etiquetatge, gestió de les llistes de correu i una configuració molt flexible.
  • Powerful - Features include offline support, multiple sender identities, multi-language support, powerful filtering, searching and tagging functionality, mailing list management and very flexible configuration.
  • Potente - Sus características incluyen el uso sin conexión, múltiples identidades del remitente, uso de varios idiomas, potente filtrado, funcionalidad de búsqueda y etiquetado, gestión de listas de correo y configuración muy flexible.
  • +
  • Võimas - paljude omaduste hulka kuuluvad võrguta töötamise toetus, mitme saatja identiteedi võimalus, paljude keelte toetus, võimas filtreerimine, otsimine ja sildistamine, postiloendite haldus ja äärmiselt paindlik seadistamine.
  • Tehokkuus: Ominaisuuksina mm. verkoton tila, useammat lähettäjähenkilöydet, useiden kielten tuki, tehokas suodatus, haku- ja tunnistetoiminnot, postilistojen hallinta ja monipuoliset asetukset.
  • -
  • Potente — Entre as súas funcionalidades están traballar sen internet, dispoñer de múltiples identidades de remitente, dispoñibilidade en varios idiomas, potentes funcionalidades de filtro, busca e etiquetado, xestión de listas de correo e gran flexibilidade de configuración.
  • +
  • Potente — Entre as súas funcionalidades están traballar sen Internet, dispoñer de múltiples identidades de remitente, dispoñibilidade en varios idiomas, potentes funcionalidades de filtro, busca e etiquetado, xestión de listas de correo e gran flexibilidade de configuración.
  • Hebat - Fitur-fitur termasuk dukungan offline, multi identitas pengirim, dukungan multi-bahasa, pemfilteran yang hebat, fungsi pencarian dan penge-tag-an, pengelolaan milis dan konfigurasi yang sangat fleksibel.
  • Potente - le funzioni includono il supporto per il funzionamento non in linea, identità con mittenti diversi, supporto per diverse lingue, filtri potenti, funzioni di ricerca e assegnazione di etichette, gestione di mailing list e una configurazione davvero flessibile.
  • +
  • 강력함 - 오프라인 지원, 다중 보내는 사람 프로필, 다국어 지원, 강력한 필터, 검색, 태그 기능, 메일링 리스트 관리, 유연한 설정 기능이 있습니다.
  • Krachtig - Functies omvatten offline ondersteuning, meerdere identiteiten als verzender, ondersteuning van meerdere talen, krachtige functionaliteit voor filtering, zoeken en taggen, beheer van e-mailijsten en erg flexibele configuratie.
  • Zaawansowany - Możliwości uwzględniają obsługę programu bez sieci, wiele tożsamości osoby wysyłającej, wielojęzyczność, filtrowanie, wyszukiwanie, oznaczanie, lista mailingowa oraz elastyczne ustawienia.
  • Poderoso - As funcionalidades incluem o suporte desligado, múltiplas identidades de envio, suporte para várias línguas, funcionalidades de filtragem, pesquisa e marcação poderosas, gestão de listas de correio e uma configuração bastante flexível.
  • +
  • Poderoso - As funcionalidades incluem o suporte offline, múltiplas identidades de envio, suporte para vários idiomas, recursos de filtragem, pesquisa e marcação de etiquetas poderosos, gerenciamento de listas de discussão e uma configuração bastante flexível.
  • +
  • Výkonný - Medzi funkcie patrí podpora offline, viacnásobné identity odosielateľa, podpora viacerých jazykov, výkonné filtrovanie, vyhľadávanie a označovanie, správa zoznamov adries a veľmi flexibilná konfigurácia.
  • +
  • Zmogljiv - funkcije vključujejo podporo brez povezave, več identitet pošiljatelja, podporo za več jezikov, zmogljivo filtriranje, iskanje in označevanje, upravljanje s poštnimi seznami in zelo prilagodljive nastavitve.
  • Kraftfullt: Funktioner omfattar stöd för nerkopplad användning, flera avsändaridentiteter, stöd för flera språk, kraftfull filtrering, sökning och etikettfunktion, hantering av sändlistor och mycket flexibel inställning.
  • Потужність — серед можливостей програми можливість роботи у автономному режимі (без з'єднання із інтернетом), робота із декількома профілями надсилання повідомлень, підтримка багатомовності, потужні можливості з фільтрування, пошуку та встановлення міток, керування повідомленнями зі списків листування та надзвичайна гнучкість у налаштовуванні.
  • xxPowerful - Features include offline support, multiple sender identities, multi-language support, powerful filtering, searching and tagging functionality, mailing list management and very flexible configuration.xx
  • Integrated - Meeting invitations can be easily added as events into KOrganizer, address auto-completion, avatars and crypto preferences are loaded from KAddressBook.
  • Integrat: les invitacions a reunions es poden afegir amb facilitat com a esdeveniments al KOrganizer, la compleció automàtica de l'adreça, els avatars i les preferències de la criptografia es carreguen des de la llibreta d'adreces.
  • Integrat: les invitacions a reunions es poden afegir amb facilitat com a esdeveniments al KOrganizer, la compleció automàtica de l'adreça, els avatars i les preferències de la criptografia es carreguen des de la llibreta d'adreces.
  • Integrated - Meeting invitations can be easily added as events into KOrganizer, address auto-completion, avatars and crypto preferences are loaded from KAddressBook.
  • Integrado - Las invitaciones a reuniones pueden añadirse fácilmente como eventos en KOrganizer, el autocompletado de direcciones, avatares y preferencias de cifrado se cargan desde KAddressBook.
  • +
  • Lõimimine - kohtumiskutsete hõlpus lisamine sündmustena KOrganizerisse, aadresside automaatne lõpetamine, avatarid ja krüptoeelistused KAddressBookist
  • Integrointi: tapaamiskutsut voi helposti lisätä tapahtumiksi KOrganizeriin, täydentää osoitteet automaattisesti ja ladata avatarit ja salauskäytänteet KAddressBookista.
  • Integrado — As invitacións a reunións poden engadirse facilmente como eventos a KOrganizer, permite completar automaticamente enderezos, e carta as imaxes de usuario e as preferencias criptográficas de KAddressBook.
  • Terintegrasi - Undangan rapat bisa dengan mudah ditambahkan sebagai acara ke dalam KOrganizer, auto-penyelesaian alamat, avatar, dan preferensi crypto yang dimuat dari KAddressBook.
  • Integrato - gli inviti alle riunioni possono essere aggiunti in modo semplice come eventi in KOrganizer, mentre il completamento automatico degli indirizzi, gli avatar e le preferenze di cifratura sono caricati da KAddressBook.
  • +
  • 통합 - 받은 초대장을 KOrganizer에 행사로 추가하고, KAddressBook에서 주소 자동 완성, 아바타, 암호화 선호도를 선택할 수 있습니다.
  • Geïntegreerd - invitaties voor bijeenkomsten kunnen gemakkelijk als afspraken in KOrganizer worden toegevoegd, automatisch aanvullen van adressen, avatars en voorkeuren voor versleuteling worden geladen uit KAddressBook.
  • Zintegrowany - Zaproszenia na spotkania można łatwo dodać do wydarzeń w KOrganizerze. Uzupełnianie adresów, awatary i ustawienia kryptograficzne są wczytywane z KsiążkiAdresowej.
  • Integrado - Os convites para reuniões podem ser facilmente adicionados como eventos ao KOrganizer; as definições de completação automática de endereços, avatars e encriptação são carregadas a partir do KAddressBook.
  • +
  • Integrado - Os convites para reuniões podem ser facilmente adicionados como eventos ao KOrganizer, as preferências de completação automática de endereços, avatares e criptografia são carregadas a partir do KAddressBook.
  • +
  • Integrovaný - Pozvánky na schôdzky sa dajú ľahko pridávať, pretože udalosti do KOrganizer sa načítavajú z KAddressBook, automatické dopĺňanie adries, avatary a nastavenia šifrovania.
  • +
  • Integrirano - vabila na srečanje lahko preprosto dodate kot dogodke v KOrganizer, samodejno dokončanje naslovov, avatarji in nastavitve šifriranja so naložene iz programa KAddressBook.
  • Integrerat: Mötesinbjudan kan enkelt läggas till som händelser i Korganizer, automatisk komplettering av adresser, avatarer och kryptoinställningar läses in från adressboken.
  • Інтеграція — реалізовано можливості простого додавання запрошень на зустрічі як записів подій у KOrganizer, дані автоматичного доповнення адрес, аватари та параметри шифрування завантажуються напряму з KAddressBook.
  • xxIntegrated - Meeting invitations can be easily added as events into KOrganizer, address auto-completion, avatars and crypto preferences are loaded from KAddressBook.xx
  • Standard Compliant - Supports standard mail protocols, push email, server-side filtering and inline OpenPGP, PGP/MIME and S/MIME.
  • Compatible amb els estàndards: admet els protocols estàndards de correu, correu electrònic per enviament, filtre de servidor i OpenPGP, PGP/MIME i S/MIME inclòs.
  • Compatible amb els estàndards: admet els protocols estàndards de correu, correu electrònic per enviament, filtre de servidor i OpenPGP, PGP/MIME i S/MIME inclòs.
  • Standard Compliant - Supports standard mail protocols, push email, server-side filtering and inline OpenPGP, PGP/MIME and S/MIME.
  • Compatible con estándares - Implementa protocolos estándar de correos, envío de correos, filtrado en el servidor, y OpenPGP, PGP/MIME y S/MIME en línea.
  • +
  • Vastavus standarditele - toetatud on standardsed e-posti protokollid, tõukekirjad, serveripoolne filtreerimine ning Inline OpenPGP, PGP/MIME ja S/MIME.
  • Standardinmukaisuus: Tukee sähköpostin yhteyskäytäntöstandardeja, push-viestejä, palvelinpuolen suodatusta ja OpenPGP-, PGP/MIME- ja S/MIME-upotusta.
  • Cumpre cos estándares — É compatíbel con protocolos de correo estándar, correo electrónico «push», filtro do lado do servidor e OpenPGP, PGP/MIME e S/MIME entre liñas.
  • Kepatuhan Standar - Mendukung protokol mail standar, push email, pemfilteran sisi server dan OpenPGP inline, PGP/MIME dan S/MIME.
  • Aderente agli standard - supporta i protocolli di posta elettronica standard, la modalità push per i messaggi di posta, filtri lato server e OpenPGP in linea, PGP/MIME e S/MIME.
  • +
  • 표준 준수 - 표준 이메일 프로토콜, 푸시 이메일, 서버 측 필터링, 인라인 OpenPGP, PGP/MIME, S/MIME을 지원합니다.
  • Voldoet aan standaarden - ondersteuning van standaard e-mailprotocollen, push e-mail, filtering aan de kant van de server en inline OpenPGP, PGP/MIME en S/MIME.
  • Zgodny ze standardami - Obsługuje wiele protokołów pocztowych, popychanie poczty, filtrowanie po stronie serwera oraz OpenPGP, PGP/MIME i S/MIME w wierszu.
  • Compatível com as Normas - Suporta os protocolos-padrão de correio, filtragem do lado do servidor e OpenPGP, PGP/MIME e S/MIME incorporados.
  • +
  • Compatibilidade com os Padrões - Suporte aos protocolos-padrão de e-mail, filtragem do lado do servidor e OpenPGP, PGP/MIME e S/MIME integrados.
  • +
  • Podporuje štandardy - Podporuje štandardné poštové protokoly, push e-mail, filtrovanie na strane servera a inline OpenPGP, PGP/MIME a S/MIME.
  • +
  • Združljiv s standardi - Podpira standardne poštne protokole, potisno e-pošto, filtriranje pošte na poštnem strežniku in inline OpenPGP, PGP/MIME in S/MIME.
  • Standardkompatibelt: Stöder standardiserade e-postprotokoll, push e-post, filtrering på serversidan samt OpenPGP, PGP/MIME och S/MIME på plats.
  • Сумісність зі стандартами — передбачено підтримку стандартних протоколів електронної пошти, надсилання повідомлень, фільтрування на боці сервера та вбудовування OpenPGP, PGP/MIME і S/MIME.
  • xxStandard Compliant - Supports standard mail protocols, push email, server-side filtering and inline OpenPGP, PGP/MIME and S/MIME.xx
  • @@ -217,4 +251,10 @@ kmail + + + + + + diff --git a/src/data/org.kde.kmail2.desktop b/src/data/org.kde.kmail2.desktop --- a/src/data/org.kde.kmail2.desktop +++ b/src/data/org.kde.kmail2.desktop @@ -154,13 +154,14 @@ GenericName[zh_TW]=收發信軟體 Comment=Send, receive and manage your mail with KMail Comment[ar]=أرسل البريد واستلمه وأدره عبر «بريدك» -Comment[ca]=Envia, rep i administra el vostre correu amb el KMail -Comment[ca@valencia]=Envia, rep i administra el vostre correu amb el KMail +Comment[ca]=Envia, rep i gestiona el vostre correu amb el KMail +Comment[ca@valencia]=Envia, rep i gestiona el vostre correu amb el KMail Comment[da]=Send, modtag og håndtér din e-mail med KMail Comment[de]=Senden, empfangen und verwalten Ihrer E-Mails mit KMail Comment[en_GB]=Send, receive and manage your mail with KMail Comment[es]=Enviar, recibir y gestionar su correo con KMail Comment[et]=Kirjade saatmine, saamine ja haldamine KMailiga +Comment[eu]=Bidali, jaso eta kudeatu zure posta KMail erabiliz Comment[fi]=Lähetä, vastaanota ja hallitse postiasi KMaililla Comment[fr]=Envoyez, recevez et gérez vos courriels avec KMail Comment[gl]=Enviar, recibir e xestionar o correo con KMail. @@ -190,7 +191,6 @@ StartupNotify=true X-DBUS-StartupType=Unique X-DBUS-ServiceName=org.kde.kmail -X-KDE-ServiceTypes=DBUS/Mailer Categories=Qt;KDE;Office;Network;Email; MimeType=x-scheme-handler/mailto; InitialPreference=10 @@ -205,17 +205,21 @@ Name[de]=Neue Nachricht ... Name[en_GB]=New Message... Name[es]=Nuevo mensaje... +Name[et]=Uus kiri ... +Name[eu]=Mezu berria... Name[fi]=Uusi viesti… Name[fr]=Nouveau message... Name[gl]=Nova mensaxe… +Name[ia]=Nove message... Name[it]=Nuovo messaggio... Name[ko]=새 메시지... Name[nl]=Nieuw bericht... Name[nn]=Ny melding … Name[pl]=Nowa wiadomość... Name[pt]=Nova Mensagem... Name[pt_BR]=Nova mensagem... Name[ru]=Написать письмо... +Name[sk]=Nová správa... Name[sl]=Novo sporočilo ... Name[sv]=Nytt brev... Name[uk]=Нове повідомлення… @@ -236,18 +240,20 @@ Name[en_GB]=Check Mail Name[es]=Comprobar correo Name[et]=E-posti kontrollimine +Name[eu]=Egiaztatu posta Name[fi]=Tarkista posti Name[fr]=Relever le courriel Name[gl]=Comprobar o correo +Name[ia]=Verifica posta Name[it]=Controlla posta Name[ko]=메일 확인 Name[nl]=E-mail controleren Name[nn]=Sjekk e-post Name[pl]=Sprawdź pocztę Name[pt]=Verificar o Correio Name[pt_BR]=Verificar e-mails Name[ru]=Проверить почту -Name[sk]=S&kontrolovať poštu +Name[sk]=Skontrolovať poštu Name[sl]=Preveri pošto Name[sr]=Провери пошту Name[sr@ijekavian]=Провери пошту diff --git a/src/dialog/addemailtoexistingcontactdialog.h b/src/dialog/addemailtoexistingcontactdialog.h --- a/src/dialog/addemailtoexistingcontactdialog.h +++ b/src/dialog/addemailtoexistingcontactdialog.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2013-2019 Montel Laurent + Copyright (c) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -31,7 +31,7 @@ explicit AddEmailToExistingContactDialog(QWidget *parent); ~AddEmailToExistingContactDialog(); - Akonadi::Item selectedContact() const; + Q_REQUIRED_RESULT Akonadi::Item selectedContact() const; private: void slotSelectionChanged(); diff --git a/src/dialog/addemailtoexistingcontactdialog.cpp b/src/dialog/addemailtoexistingcontactdialog.cpp --- a/src/dialog/addemailtoexistingcontactdialog.cpp +++ b/src/dialog/addemailtoexistingcontactdialog.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2013-2019 Montel Laurent + Copyright (c) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -38,7 +38,7 @@ AddEmailToExistingContactDialog::AddEmailToExistingContactDialog(QWidget *parent) : QDialog(parent) { - setWindowTitle(i18n("Select Contact")); + setWindowTitle(i18nc("@title:window", "Select Contact")); setModal(true); Akonadi::Session *session = new Akonadi::Session("AddEmailToExistingContactDialog", this); diff --git a/src/dialog/archivefolderdialog.h b/src/dialog/archivefolderdialog.h --- a/src/dialog/archivefolderdialog.h +++ b/src/dialog/archivefolderdialog.h @@ -23,7 +23,7 @@ class QCheckBox; class KUrlRequester; -class KComboBox; +class QComboBox; class QPushButton; namespace Akonadi { class Collection; @@ -49,14 +49,14 @@ void slotAccepted(); void slotUrlChanged(const QString &); - bool allowToDeleteFolders(const Akonadi::Collection &folder) const; - QString standardArchivePath(const QString &folderName); + Q_REQUIRED_RESULT bool allowToDeleteFolders(const Akonadi::Collection &folder) const; + Q_REQUIRED_RESULT QString standardArchivePath(const QString &folderName); QWidget *mParentWidget = nullptr; QCheckBox *mDeleteCheckBox = nullptr; QCheckBox *mRecursiveCheckBox = nullptr; MailCommon::FolderRequester *mFolderRequester = nullptr; - KComboBox *mFormatComboBox = nullptr; + QComboBox *mFormatComboBox = nullptr; KUrlRequester *mUrlRequester = nullptr; QPushButton *mOkButton = nullptr; }; diff --git a/src/dialog/archivefolderdialog.cpp b/src/dialog/archivefolderdialog.cpp --- a/src/dialog/archivefolderdialog.cpp +++ b/src/dialog/archivefolderdialog.cpp @@ -1,4 +1,5 @@ /* Copyright 2009 Klarälvdalens Datakonsult AB + Copyright 2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -18,18 +19,18 @@ */ #include "archivefolderdialog.h" -#include "MailCommon/BackupJob" +#include #include "kmkernel.h" #include "kmmainwidget.h" -#include "MailCommon/FolderRequester" -#include "MessageViewer/MessageViewerUtil" +#include +#include #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -79,7 +80,7 @@ int row = 0; - // TODO: Explaination label + // TODO: Explanation label QLabel *folderLabel = new QLabel(i18n("&Folder:"), mainWidget); mainLayout->addWidget(folderLabel, row, 0); @@ -93,16 +94,16 @@ QLabel *formatLabel = new QLabel(i18n("F&ormat:"), mainWidget); mainLayout->addWidget(formatLabel, row, 0); - mFormatComboBox = new KComboBox(mainWidget); + mFormatComboBox = new QComboBox(mainWidget); formatLabel->setBuddy(mFormatComboBox); // These combobox values have to stay in sync with the ArchiveType enum from BackupJob! mFormatComboBox->addItem(i18n("Compressed Zip Archive (.zip)")); mFormatComboBox->addItem(i18n("Uncompressed Archive (.tar)")); mFormatComboBox->addItem(i18n("BZ2-Compressed Tar Archive (.tar.bz2)")); mFormatComboBox->addItem(i18n("GZ-Compressed Tar Archive (.tar.gz)")); mFormatComboBox->setCurrentIndex(2); - connect(mFormatComboBox, QOverload::of(&KComboBox::activated), this, &ArchiveFolderDialog::slotFixFileExtension); + connect(mFormatComboBox, qOverload(&QComboBox::activated), this, &ArchiveFolderDialog::slotFixFileExtension); mainLayout->addWidget(mFormatComboBox, row, 1); row++; diff --git a/src/dialog/kmknotify.h b/src/dialog/kmknotify.h --- a/src/dialog/kmknotify.h +++ b/src/dialog/kmknotify.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2011-2019 Montel Laurent + Copyright (C) 2011-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/dialog/kmknotify.cpp b/src/dialog/kmknotify.cpp --- a/src/dialog/kmknotify.cpp +++ b/src/dialog/kmknotify.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2011-2019 Montel Laurent + Copyright (C) 2011-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -36,7 +36,7 @@ KMKnotify::KMKnotify(QWidget *parent) : QDialog(parent) { - setWindowTitle(i18n("Notification")); + setWindowTitle(i18nc("@title:window", "Notification")); QVBoxLayout *mainLayout = new QVBoxLayout(this); m_comboNotify = new QComboBox(this); @@ -58,7 +58,7 @@ mainLayout->addWidget(buttonBox); - connect(m_comboNotify, QOverload::of(&QComboBox::activated), this, &KMKnotify::slotComboChanged); + connect(m_comboNotify, qOverload(&QComboBox::activated), this, &KMKnotify::slotComboChanged); connect(okButton, &QPushButton::clicked, this, &KMKnotify::slotOk); connect(m_notifyWidget, &KNotifyConfigWidget::changed, this, &KMKnotify::slotConfigChanged); initCombobox(); @@ -107,7 +107,7 @@ //TODO add other notifyrc here if necessary for (const QString ¬ify : lstNotify) { - const QString fullPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("knotifications5/") + notify); + const QString fullPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("knotifications5/") + notify); if (!fullPath.isEmpty()) { const int slash = fullPath.lastIndexOf(QLatin1Char('/')); diff --git a/agents/archivemailagent/autotests/archivemailwidgettest.h b/src/dialog/spellcheckerconfigdialog.h copy from agents/archivemailagent/autotests/archivemailwidgettest.h copy to src/dialog/spellcheckerconfigdialog.h --- a/agents/archivemailagent/autotests/archivemailwidgettest.h +++ b/src/dialog/spellcheckerconfigdialog.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,20 +17,21 @@ Boston, MA 02110-1301, USA. */ -#ifndef ARCHIVEMAILWIDGETTEST_H -#define ARCHIVEMAILWIDGETTEST_H +#ifndef SPELLCHECKERCONFIGDIALOG_H +#define SPELLCHECKERCONFIGDIALOG_H -#include +#include -class ArchiveMailWidgetTest : public QObject +class SpellCheckerConfigDialog : public Sonnet::ConfigDialog { Q_OBJECT public: - explicit ArchiveMailWidgetTest(QObject *parent = nullptr); - ~ArchiveMailWidgetTest(); + explicit SpellCheckerConfigDialog(QWidget *parent = nullptr); + ~SpellCheckerConfigDialog(); -private Q_SLOTS: - void shouldHaveDefaultValue(); +private: + void readConfig(); + void writeConfig(); }; -#endif // ARCHIVEMAILWIDGETTEST_H +#endif // SPELLCHECKERCONFIGDIALOG_H diff --git a/src/dialog/spellcheckerconfigdialog.cpp b/src/dialog/spellcheckerconfigdialog.cpp new file mode 100644 --- /dev/null +++ b/src/dialog/spellcheckerconfigdialog.cpp @@ -0,0 +1,75 @@ +/* + Copyright (C) 2019-2020 Laurent Montel + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "spellcheckerconfigdialog.h" +#include "kmkernel.h" +#include "kmail_debug.h" +#include +#include + +#include + +#include + +SpellCheckerConfigDialog::SpellCheckerConfigDialog(QWidget *parent) + : Sonnet::ConfigDialog(parent) +{ + // Hackish way to hide the "Enable spell check by default" checkbox + // Our highlighter ignores this setting, so we should not expose its UI + QCheckBox *enabledByDefaultCB = findChild(QStringLiteral("m_checkerEnabledByDefaultCB")); + if (enabledByDefaultCB) { + enabledByDefaultCB->hide(); + } else { + qCWarning(KMAIL_LOG) << "Could not find any checkbox named 'm_checkerEnabledByDefaultCB'. Sonnet::ConfigDialog must have changed!"; + } + QLabel *textLabel = findChild(QStringLiteral("textLabel1")); + if (textLabel) { + textLabel->hide(); + } else { + qCWarning(KMAIL_LOG) << "Could not find any label named 'textLabel'. Sonnet::ConfigDialog must have changed!"; + } + Sonnet::DictionaryComboBox *dictionaryComboBox = findChild(QStringLiteral("m_langCombo")); + if (dictionaryComboBox) { + dictionaryComboBox->hide(); + } else { + qCWarning(KMAIL_LOG) << "Could not find any Sonnet::DictionaryComboBox named 'dictionaryComboBox'. Sonnet::ConfigDialog must have changed!"; + } + readConfig(); +} + +SpellCheckerConfigDialog::~SpellCheckerConfigDialog() +{ + writeConfig(); +} + +void SpellCheckerConfigDialog::readConfig() +{ + KConfigGroup notifyDialog(KMKernel::self()->config(), "KMKnotifyDialog"); + const QSize size = notifyDialog.readEntry("Size", QSize(600, 400)); + if (size.isValid()) { + resize(size); + } +} + +void SpellCheckerConfigDialog::writeConfig() +{ + KConfigGroup notifyDialog(KMKernel::self()->config(), "KMKnotifyDialog"); + notifyDialog.writeEntry("Size", size()); + notifyDialog.sync(); +} diff --git a/src/editor/attachment/attachmentcontroller.h b/src/editor/attachment/attachmentcontroller.h --- a/src/editor/attachment/attachmentcontroller.h +++ b/src/editor/attachment/attachmentcontroller.h @@ -23,7 +23,7 @@ #ifndef KMAIL_ATTACHMENTCONTROLLER_H #define KMAIL_ATTACHMENTCONTROLLER_H -#include "messagecomposer/attachmentcontrollerbase.h" +#include #include class KMComposerWin; class QModelIndex; diff --git a/src/editor/attachment/attachmentcontroller.cpp b/src/editor/attachment/attachmentcontroller.cpp --- a/src/editor/attachment/attachmentcontroller.cpp +++ b/src/editor/attachment/attachmentcontroller.cpp @@ -28,7 +28,7 @@ #include "editor/kmcomposerwin.h" #include "kmkernel.h" #include "kmreadermainwin.h" -#include "mailcommon/mailutil.h" +#include #include #include #include @@ -127,16 +127,17 @@ void AttachmentController::onShowAttachment(KMime::Content *content, const QByteArray &charset) { + const QString charsetStr = QString::fromLatin1(charset); if (content->bodyAsMessage()) { KMime::Message::Ptr m(new KMime::Message); m->setContent(content->bodyAsMessage()->encodedContent()); m->parse(); KMReaderMainWin *win = new KMReaderMainWin(); - win->showMessage(QString::fromLatin1(charset), m); + win->showMessage(charsetStr, m); win->show(); } else { KMReaderMainWin *win - = new KMReaderMainWin(content, MessageViewer::Viewer::Text, QString::fromLatin1(charset)); + = new KMReaderMainWin(content, MessageViewer::Viewer::Text, charsetStr); win->show(); } } diff --git a/src/editor/attachment/attachmentview.h b/src/editor/attachment/attachmentview.h --- a/src/editor/attachment/attachmentview.h +++ b/src/editor/attachment/attachmentview.h @@ -1,6 +1,6 @@ /* * This file is part of KMail. - * Copyright (C) 2012-2019 Laurent Montel + * Copyright (C) 2012-2020 Laurent Montel * Copyright (c) 2009 Constantin Berzan * * Parts based on KMail code by: diff --git a/src/editor/attachment/attachmentview.cpp b/src/editor/attachment/attachmentview.cpp --- a/src/editor/attachment/attachmentview.cpp +++ b/src/editor/attachment/attachmentview.cpp @@ -1,6 +1,6 @@ /* * This file is part of KMail. - * Copyright (c) 2011-2019 Laurent Montel + * Copyright (c) 2011-2020 Laurent Montel * * Copyright (c) 2009 Constantin Berzan * @@ -39,7 +39,6 @@ #include #include -#include #include #include diff --git a/src/editor/codec/codecaction.h b/src/editor/codec/codecaction.h --- a/src/editor/codec/codecaction.h +++ b/src/editor/codec/codecaction.h @@ -21,10 +21,10 @@ #define CODECACTION_H // Qt -#include +#include // KDE -#include +#include // TODO since the reader is now in a separate lib, we can probably have this // class for the composer only. The reader can use KCodecAction directly anyway. @@ -49,7 +49,7 @@ mode. In Reader mode it probably makes more sense to use KCodecAction::currentCodec() and KCodecAction::currentAutoDetectScript(). */ - QList mimeCharsets() const; + Q_REQUIRED_RESULT QVector mimeCharsets() const; void setAutoCharset(); void setCharset(const QByteArray &charset); diff --git a/src/editor/codec/codecaction.cpp b/src/editor/codec/codecaction.cpp --- a/src/editor/codec/codecaction.cpp +++ b/src/editor/codec/codecaction.cpp @@ -61,9 +61,9 @@ { } -QList CodecAction::mimeCharsets() const +QVector CodecAction::mimeCharsets() const { - QList ret; + QVector ret; qCDebug(KMAIL_LOG) << "current item" << currentItem() << currentText(); if (currentItem() == 0) { // 'Default' selected: return the preferred charsets. diff --git a/src/editor/codec/codecmanager.h b/src/editor/codec/codecmanager.h --- a/src/editor/codec/codecmanager.h +++ b/src/editor/codec/codecmanager.h @@ -21,7 +21,7 @@ #define CODECMANAGER_H #include -#include +#include class CodecManager { public: @@ -33,7 +33,7 @@ /** A list of preferred charsets to use when composing messages. */ - QList preferredCharsets() const; + Q_REQUIRED_RESULT QVector preferredCharsets() const; /** Re-read the preferred charsets from settings. @@ -46,7 +46,7 @@ // Singleton. The only instance lives in sInstance->instance CodecManager(); - QList mPreferredCharsets; + QVector mPreferredCharsets; }; #endif /* CODECMANAGER_H */ diff --git a/src/editor/codec/codecmanager.cpp b/src/editor/codec/codecmanager.cpp --- a/src/editor/codec/codecmanager.cpp +++ b/src/editor/codec/codecmanager.cpp @@ -30,8 +30,8 @@ #include // KDE libs -#include -#include +#include +#include CodecManager::CodecManager() { @@ -45,7 +45,7 @@ return &instance; } -QList CodecManager::preferredCharsets() const +QVector CodecManager::preferredCharsets() const { return mPreferredCharsets; } diff --git a/src/editor/composer.h b/src/editor/composer.h --- a/src/editor/composer.h +++ b/src/editor/composer.h @@ -56,16 +56,21 @@ }; typedef QFlags VisibleHeaderFlags; + struct AttachmentInfo { + QString comment; + QUrl url; + }; + public: // mailserviceimpl /** * From MailComposerIface */ virtual void send(int how) = 0; virtual void addAttachmentsAndSend(const QList &urls, const QString &comment, int how) = 0; - virtual void addAttachment(const QUrl &url, const QString &comment) = 0; + virtual void addAttachment(const QList &url, bool showWarning) = 0; virtual void addAttachment(const QString &name, KMime::Headers::contentEncoding cte, const QString &charset, const QByteArray &data, const QByteArray &mimeType) = 0; public: // kmcommand - virtual QString dbusObjectPath() const = 0; + virtual Q_REQUIRED_RESULT QString dbusObjectPath() const = 0; public: // kmkernel, kmcommands, callback /** * Set the message the composer shall work with. This discards @@ -85,6 +90,8 @@ virtual void addExtraCustomHeaders(const QMap &header) = 0; + virtual void showAndActivateComposer() = 0; + public: // kmcommand /** * If this folder is set, the original message is inserted back after diff --git a/src/editor/kmcomposercreatenewcomposerjob.h b/src/editor/kmcomposercreatenewcomposerjob.h --- a/src/editor/kmcomposercreatenewcomposerjob.h +++ b/src/editor/kmcomposercreatenewcomposerjob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/src/editor/kmcomposercreatenewcomposerjob.cpp b/src/editor/kmcomposercreatenewcomposerjob.cpp --- a/src/editor/kmcomposercreatenewcomposerjob.cpp +++ b/src/editor/kmcomposercreatenewcomposerjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/src/editor/kmcomposereditorng.h b/src/editor/kmcomposereditorng.h --- a/src/editor/kmcomposereditorng.h +++ b/src/editor/kmcomposereditorng.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -18,7 +18,7 @@ #ifndef KMCOMPOSEREDITORNG_H #define KMCOMPOSEREDITORNG_H -#include "messagecomposer/richtextcomposerng.h" +#include class KMComposerWin; namespace KPIMTextEdit { class RichTextComposerEmailQuoteHighlighter; @@ -30,17 +30,18 @@ explicit KMComposerEditorNg(KMComposerWin *win, QWidget *parent); ~KMComposerEditorNg() override; - QString smartQuote(const QString &msg) override; + Q_REQUIRED_RESULT QString smartQuote(const QString &msg) override; void setHighlighterColors(KPIMTextEdit::RichTextComposerEmailQuoteHighlighter *highlighter) override; void showSpellConfigDialog(const QString &configFileName); - MessageComposer::PluginEditorConvertTextInterface::ConvertTextStatus convertPlainText(MessageComposer::TextPart *textPart) override; + Q_REQUIRED_RESULT MessageComposer::PluginEditorConvertTextInterface::ConvertTextStatus convertPlainText(MessageComposer::TextPart *textPart) override; Q_SIGNALS: void insertSnippet(); protected: + bool processModifyText(QKeyEvent *event) override; void addExtraMenuEntry(QMenu *menu, QPoint pos) override; bool canInsertFromMimeData(const QMimeData *source) const override; void insertFromMimeData(const QMimeData *source) override; diff --git a/src/editor/kmcomposereditorng.cpp b/src/editor/kmcomposereditorng.cpp --- a/src/editor/kmcomposereditorng.cpp +++ b/src/editor/kmcomposereditorng.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -21,6 +21,7 @@ #include "util.h" #include "kmail_debug.h" #include "job/dndfromarkjob.h" +#include "dialog/spellcheckerconfigdialog.h" #include #include @@ -124,30 +125,10 @@ void KMComposerEditorNg::showSpellConfigDialog(const QString &configFileName) { Q_UNUSED(configFileName); - QPointer dialog = new Sonnet::ConfigDialog(this); + QPointer dialog = new SpellCheckerConfigDialog(this); if (!spellCheckingLanguage().isEmpty()) { dialog->setLanguage(spellCheckingLanguage()); } - // Hackish way to hide the "Enable spell check by default" checkbox - // Our highlighter ignores this setting, so we should not expose its UI - QCheckBox *enabledByDefaultCB = dialog->findChild(QStringLiteral("m_checkerEnabledByDefaultCB")); - if (enabledByDefaultCB) { - enabledByDefaultCB->hide(); - } else { - qCWarning(KMAIL_LOG) << "Could not find any checkbox named 'm_checkerEnabledByDefaultCB'. Sonnet::ConfigDialog must have changed!"; - } - QLabel *textLabel = dialog->findChild(QStringLiteral("textLabel1")); - if (textLabel) { - textLabel->hide(); - } else { - qCWarning(KMAIL_LOG) << "Could not find any label named 'textLabel'. Sonnet::ConfigDialog must have changed!"; - } - Sonnet::DictionaryComboBox *dictionaryComboBox = dialog->findChild(QStringLiteral("m_langCombo")); - if (dictionaryComboBox) { - dictionaryComboBox->hide(); - } else { - qCWarning(KMAIL_LOG) << "Could not find any Sonnet::DictionaryComboBox named 'dictionaryComboBox'. Sonnet::ConfigDialog must have changed!"; - } if (dialog->exec()) { setSpellCheckingLanguage(dialog->language()); @@ -162,3 +143,11 @@ } return MessageComposer::PluginEditorConvertTextInterface::ConvertTextStatus::NotConverted; } + +bool KMComposerEditorNg::processModifyText(QKeyEvent *event) +{ + if (!mComposerWin->processModifyText(event)) { + return MessageComposer::RichTextComposerNg::processModifyText(event); + } + return true; +} diff --git a/src/editor/kmcomposerglobalaction.h b/src/editor/kmcomposerglobalaction.h --- a/src/editor/kmcomposerglobalaction.h +++ b/src/editor/kmcomposerglobalaction.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/editor/kmcomposerglobalaction.cpp b/src/editor/kmcomposerglobalaction.cpp --- a/src/editor/kmcomposerglobalaction.cpp +++ b/src/editor/kmcomposerglobalaction.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -18,7 +18,7 @@ #include "kmcomposerglobalaction.h" #include "kmcomposerwin.h" -#include +#include #include @@ -129,7 +129,6 @@ } } - void KMComposerGlobalAction::slotInsertEmoticon(const QString &str) { QWidget *fw = mComposerWin->focusWidget(); @@ -139,12 +138,12 @@ if (::qobject_cast(fw)) { static_cast(fw)->insertPlainText(str); - } else if (::qobject_cast(fw)) { - //Don't insert emoticon in mail linedit - //static_cast(fw)->insert(str); } else if (::qobject_cast(fw)) { static_cast(fw)->insertPlainText(str); } + //} else if (::qobject_cast(fw)) { + //Don't insert emoticon in mail linedit + //static_cast(fw)->insert(str); } void KMComposerGlobalAction::slotInsertText(const QString &str) @@ -156,10 +155,9 @@ if (::qobject_cast(fw)) { static_cast(fw)->insertPlainText(str); - } else if (::qobject_cast(fw)) { - //Don't insert emoticon in mail linedit - //static_cast(fw)->insert(str); } else if (::qobject_cast(fw)) { static_cast(fw)->insertPlainText(str); } + //Don't insert text in mail linedit + //} else if (::qobject_cast(fw)) { } diff --git a/src/editor/kmcomposerupdatetemplatejob.h b/src/editor/kmcomposerupdatetemplatejob.h --- a/src/editor/kmcomposerupdatetemplatejob.h +++ b/src/editor/kmcomposerupdatetemplatejob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/src/editor/kmcomposerupdatetemplatejob.cpp b/src/editor/kmcomposerupdatetemplatejob.cpp --- a/src/editor/kmcomposerupdatetemplatejob.cpp +++ b/src/editor/kmcomposerupdatetemplatejob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/src/editor/kmcomposerwin.h b/src/editor/kmcomposerwin.h --- a/src/editor/kmcomposerwin.h +++ b/src/editor/kmcomposerwin.h @@ -1,6 +1,6 @@ /* * This file is part of KMail. - * Copyright (c) 2011-2019 Laurent Montel + * Copyright (c) 2011-2020 Laurent Montel * * Copyright (c) 2009 Constantin Berzan * @@ -27,24 +27,25 @@ // KMail includes #include "editor/composer.h" -#include "MessageComposer/RecipientsEditor" +#include #include // Qt includes #include #include +#include // LIBKDEPIM includes -#include "MessageComposer/RichTextComposerNg" +#include #include // KDEPIMLIBS includes #include #include // Other includes -#include "Libkleo/Enum" -#include +#include +#include class QUrl; @@ -62,19 +63,18 @@ class KToggleAction; class QUrl; class KRecentFilesAction; -class SnippetWidget; class AttachmentMissingWarning; class ExternalEditorWarning; class CryptoStateIndicatorWidget; -class StatusBarLabelToggledState; class PotentialPhishingEmailWarning; class KMComposerGlobalAction; class KMailPluginEditorManagerInterface; class KMailPluginEditorCheckBeforeSendManagerInterface; class KMailPluginEditorInitManagerInterface; class IncorrectIdentityFolderWarning; class KMailPluginEditorConvertTextManagerInterface; class KMailPluginGrammarEditorManagerInterface; +class AttachmentAddedFromExternalWarning; namespace MailTransport { class Transport; } @@ -94,10 +94,13 @@ namespace MessageComposer { class ComposerLineEdit; class Composer; +class StatusBarLabelToggledState; } namespace MailCommon { class FolderRequester; +class SnippetTreeView; +struct SnippetInfo; } namespace PimCommon { @@ -126,28 +129,26 @@ public: static Composer *create(const KMime::Message::Ptr &msg, bool lastSignState, bool lastEncryptState, TemplateContext context = NoTemplate, uint identity = 0, const QString &textSelection = QString(), const QString &customTemplate = QString()); - QString dbusObjectPath() const override; - QString smartQuote(const QString &msg); + Q_REQUIRED_RESULT QString dbusObjectPath() const override; + Q_REQUIRED_RESULT QString smartQuote(const QString &msg); /** * Start of D-Bus callable stuff. The D-Bus methods need to be public slots, * otherwise they can't be accessed. */ - // TODO clean-up dbus stuff; make the adaptor a friend; etc. public Q_SLOTS: Q_SCRIPTABLE void send(int how) override; - - Q_SCRIPTABLE void addAttachmentsAndSend(const QList &urls, const QString &comment, int how) override; - - Q_SCRIPTABLE void addAttachment(const QUrl &url, const QString &comment) override; - - Q_SCRIPTABLE void addAttachment(const QString &name, KMime::Headers::contentEncoding cte, const QString &charset, const QByteArray &data, const QByteArray &mimeType) override; - /** * End of D-Bus callable stuff */ + void addAttachmentsAndSend(const QList &urls, const QString &comment, int how) override; + + void addAttachment(const QList &infos, bool showWarning) override; + + void addAttachment(const QString &name, KMime::Headers::contentEncoding cte, const QString &charset, const QByteArray &data, const QByteArray &mimeType) override; + Q_SIGNALS: void identityChanged(const KIdentityManagement::Identity &identity); @@ -186,7 +187,7 @@ /** * Returns @c true while the message composing is in progress. */ - bool isComposing() const override; + Q_REQUIRED_RESULT bool isComposing() const override; /** Disabled signing and encryption completely for this composer window. */ void setSigningAndEncryptionDisabled(bool v) override; @@ -212,7 +213,8 @@ void addExtraCustomHeaders(const QMap &header) override; - MessageComposer::PluginEditorConvertTextInterface::ConvertTextStatus convertPlainText(MessageComposer::TextPart *textPart); + Q_REQUIRED_RESULT MessageComposer::PluginEditorConvertTextInterface::ConvertTextStatus convertPlainText(MessageComposer::TextPart *textPart); + Q_REQUIRED_RESULT bool processModifyText(QKeyEvent *event); private: /** * Write settings to app's config file. @@ -357,13 +359,15 @@ void slotPrintComposeResult(KJob *job); void slotSendFailed(const QString &msg, MessageComposer::ComposerViewBase::FailedType type); - void slotSendSuccessful(); + void slotSendSuccessful(Akonadi::Item::Id id); /** * toggle automatic spellchecking */ void slotAutoSpellCheckingToggled(bool); + void showAndActivateComposer() override; + void setAutoSaveFileName(const QString &fileName) override; void slotSpellCheckingLanguage(const QString &language); void forceAutoSaveMessage(); @@ -406,7 +410,7 @@ /** Don't check for forgotten attachments for a mail, eg. when sending out invitations. */ void disableForgottenAttachmentsCheck() override; - uint currentIdentity() const; + Q_REQUIRED_RESULT uint currentIdentity() const; QList customToolsList() const; QList pluginToolsActionListForPopupMenu() const; private: @@ -416,7 +420,7 @@ */ void readConfig(bool reload = false); - QUrl insertFile(); + Q_REQUIRED_RESULT QUrl insertFile(); /** * Updates the visibility and text of the signature and encryption state indicators. */ @@ -426,7 +430,7 @@ void sendNow(bool shortcutUsed); void updateSignature(uint uoid, uint uOldId); - Kleo::CryptoMessageFormat cryptoMessageFormat() const; + Q_REQUIRED_RESULT Kleo::CryptoMessageFormat cryptoMessageFormat() const; void printComposeResult(KJob *job, bool preview); void printComposer(bool preview); /** @@ -460,7 +464,7 @@ * Checks how many recipients are and warns if there are too many. * @return true, if the user accepted the warning and the message should be sent */ - bool checkRecipientNumber() const; + Q_REQUIRED_RESULT bool checkRecipientNumber() const; /** * Initialization methods @@ -472,13 +476,13 @@ /** * Header fields. */ - QString subject() const; - QString from() const; + Q_REQUIRED_RESULT QString subject() const; + Q_REQUIRED_RESULT QString from() const; /** * Ask for confirmation if the message was changed before close. */ - bool queryClose() override; + Q_REQUIRED_RESULT bool queryClose() override; /** * Turn encryption on/off. If setByUser is true then a message box is shown @@ -492,7 +496,7 @@ */ void setSigning(bool sign, bool setByUser = false); - MessageComposer::ComposerViewBase::MissingAttachment userForgotAttachment(); + Q_REQUIRED_RESULT MessageComposer::ComposerViewBase::MissingAttachment userForgotAttachment(); /** * Send the message. */ @@ -509,7 +513,7 @@ * * The caller takes ownership of the composer. */ - MessageComposer::Composer *createSimpleComposer(); + Q_REQUIRED_RESULT MessageComposer::Composer *createSimpleComposer(); bool canSignEncryptAttachments() const; @@ -542,11 +546,13 @@ void insertUrls(const QMimeData *source, const QList &urlList); void initializePluginActions(); - bool showErrorMessage(KJob *job); - int validateLineWrapWidth(); + Q_REQUIRED_RESULT bool showErrorMessage(KJob *job); + Q_REQUIRED_RESULT int validateLineWrapWidth(); void slotSelectionChanged(); void slotMessage(const QString &str); void slotEditorPluginInsertText(const QString &str); + void insertSnippetInfo(const MailCommon::SnippetInfo &info); + Q_REQUIRED_RESULT bool sendLaterRegistered() const; Akonadi::Collection mCollectionForNewMessage; QMap mExtraHeaders; @@ -582,7 +588,7 @@ QFont mBodyFont; QFont mFixedFont; uint mId = 0; - TemplateContext mContext; + TemplateContext mContext = NoTemplate; KRecentFilesAction *mRecentAction = nullptr; @@ -625,17 +631,18 @@ MessageComposer::Composer *mDummyComposer = nullptr; // used for auto saving, printing, etc. Not for sending, which happens in ComposerViewBase - QList< MessageComposer::Composer * > mMiscComposers; + QVector< MessageComposer::Composer * > mMiscComposers; int mLabelWidth = 0; QString mdbusObjectPath; static int s_composerNumber; QMetaObject::Connection mIdentityConnection; + QMetaObject::Connection mUpdateWindowTitleConnection; MessageComposer::ComposerViewBase *mComposerBase = nullptr; - SnippetWidget *mSnippetWidget = nullptr; + MailCommon::SnippetTreeView *mSnippetWidget = nullptr; PimCommon::CustomToolsWidgetNg *mCustomToolsWidget = nullptr; AttachmentMissingWarning *mAttachmentMissing = nullptr; ExternalEditorWarning *mExternalEditorWarning = nullptr; @@ -648,8 +655,8 @@ bool mSendNowByShortcutUsed = false; KSplitterCollapserButton *mSnippetSplitterCollapser = nullptr; KToggleAction *mFollowUpToggleAction = nullptr; - StatusBarLabelToggledState *mStatusBarLabelToggledOverrideMode = nullptr; - StatusBarLabelToggledState *mStatusBarLabelSpellCheckingChangeMode = nullptr; + MessageComposer::StatusBarLabelToggledState *mStatusBarLabelToggledOverrideMode = nullptr; + MessageComposer::StatusBarLabelToggledState *mStatusBarLabelSpellCheckingChangeMode = nullptr; PotentialPhishingEmailWarning *mPotentialPhishingEmailWarning = nullptr; IncorrectIdentityFolderWarning *mIncorrectIdentityFolderWarning = nullptr; KMComposerGlobalAction *mGlobalAction = nullptr; @@ -660,6 +667,8 @@ KMailPluginEditorInitManagerInterface *mPluginEditorInitManagerInterface = nullptr; KMailPluginEditorConvertTextManagerInterface *mPluginEditorConvertTextManagerInterface = nullptr; KMailPluginGrammarEditorManagerInterface *mPluginEditorGrammarManagerInterface = nullptr; + + AttachmentAddedFromExternalWarning *mAttachmentFromExternalMissing = nullptr; }; #endif diff --git a/src/editor/kmcomposerwin.cpp b/src/editor/kmcomposerwin.cpp --- a/src/editor/kmcomposerwin.cpp +++ b/src/editor/kmcomposerwin.cpp @@ -1,6 +1,6 @@ /* * This file is part of KMail. - * Copyright (c) 2011-2019 Laurent Montel + * Copyright (c) 2011-2020 Laurent Montel * * Copyright (c) 2009 Constantin Berzan * @@ -36,13 +36,12 @@ #include "editor/potentialphishingemail/potentialphishingemailjob.h" #include "editor/potentialphishingemail/potentialphishingemailwarning.h" #include "editor/warningwidgets/incorrectidentityfolderwarning.h" -#include "editor/widgets/snippetwidget.h" +#include "editor/warningwidgets/attachmentaddedfromexternalwarning.h" #include "job/addressvalidationjob.h" #include "job/createnewcontactjob.h" #include "job/saveasfilejob.h" #include "job/savedraftjob.h" #include "job/dndfromarkjob.h" -#include "kconfigwidgets_version.h" #include "kmail_debug.h" #include "kmcommands.h" #include "kmcomposercreatenewcomposerjob.h" @@ -60,8 +59,7 @@ #include "warningwidgets/externaleditorwarning.h" #include "widgets/cryptostateindicatorwidget.h" #include "widgets/kactionmenutransport.h" -#include "widgets/statusbarlabeltoggledstate.h" - +#include "undosend/undosendmanager.h" #include #include #include @@ -101,6 +99,8 @@ #include #include #include +#include +#include #include #include @@ -124,6 +124,10 @@ #include #include #include +#include +#include +#include + #include #include @@ -143,9 +147,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -159,11 +163,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -174,41 +176,36 @@ #include #include #include -#include -#include - #include -#include -#include -#include #include - +#include // Qt includes #include #include #include #include -#include #include #include #include #include -#include -#include #include #include #include #include #include -#include #include #include #include // GPGME #include #include +#include + +#include +#include + using Sonnet::DictionaryComboBox; using MailTransport::TransportManager; using MailTransport::Transport; @@ -308,7 +305,7 @@ MailTransport::TransportComboBox *transport = new MailTransport::TransportComboBox(mHeadersArea); transport->setToolTip(i18n("Select the outgoing account to use for sending this message")); mComposerBase->setTransportCombo(transport); - connect(transport, QOverload::of(&MailTransport::TransportComboBox::activated), this, &KMComposerWin::slotTransportChanged); + connect(transport, qOverload(&MailTransport::TransportComboBox::activated), this, &KMComposerWin::slotTransportChanged); connect(transport, &MailTransport::TransportComboBox::transportRemoved, this, &KMComposerWin::slotTransportRemoved); mEdtFrom = new MessageComposer::ComposerLineEdit(false, mHeadersArea); mEdtFrom->setObjectName(QStringLiteral("fromLine")); @@ -364,14 +361,17 @@ mRichTextEditorwidget = new KPIMTextEdit::RichTextEditorWidget(composerEditorNg, mCryptoStateIndicatorWidget); connect(composerEditorNg, &KMComposerEditorNg::insertEmoticon, mGlobalAction, &KMComposerGlobalAction::slotInsertEmoticon); - //Don't use new connect api here. It crashs + //Don't use new connect api here. It crashes connect(composerEditorNg, SIGNAL(textChanged()), this, SLOT(slotEditorTextChanged())); connect(composerEditorNg, &KMComposerEditorNg::selectionChanged, this, &KMComposerWin::slotSelectionChanged); //connect(editor, &KMComposerEditor::textChanged, this, &KMComposeWin::slotEditorTextChanged); mComposerBase->setEditor(composerEditorNg); mIncorrectIdentityFolderWarning = new IncorrectIdentityFolderWarning(this); vbox->addWidget(mIncorrectIdentityFolderWarning); + mAttachmentFromExternalMissing = new AttachmentAddedFromExternalWarning(this); + vbox->addWidget(mAttachmentFromExternalMissing); + vbox->addWidget(mCryptoStateIndicatorWidget); vbox->addWidget(mRichTextEditorwidget); @@ -390,16 +390,18 @@ connect(composerEditorNg, &KMComposerEditorNg::spellCheckStatus, this, &KMComposerWin::slotSpellCheckingStatus); connect(composerEditorNg, &KMComposerEditorNg::insertModeChanged, this, &KMComposerWin::slotOverwriteModeChanged); connect(composerEditorNg, &KMComposerEditorNg::spellCheckingFinished, this, &KMComposerWin::slotDelayedCheckSendNow); - mSnippetWidget = new SnippetWidget(composerEditorNg, actionCollection(), mSnippetSplitter); + mSnippetWidget = new MailCommon::SnippetTreeView(actionCollection(), mSnippetSplitter); + connect(mSnippetWidget, &MailCommon::SnippetTreeView::insertSnippetInfo, this, &KMComposerWin::insertSnippetInfo); + connect(composerEditorNg, &KMComposerEditorNg::insertSnippet, mSnippetWidget->snippetsManager(), &MailCommon::SnippetsManager::insertSnippet); mSnippetWidget->setVisible(KMailSettings::self()->showSnippetManager()); mSnippetSplitter->addWidget(mSnippetWidget); mSnippetSplitter->setCollapsible(0, false); mSnippetSplitterCollapser = new KSplitterCollapserButton(mSnippetWidget, mSnippetSplitter); mSnippetSplitterCollapser->setVisible(KMailSettings::self()->showSnippetManager()); mSplitter->setOpaqueResize(true); - setWindowTitle(i18n("Composer")); + setWindowTitle(i18nc("@title:window", "Composer")); setMinimumSize(200, 200); mCustomToolsWidget = new PimCommon::CustomToolsWidgetNg(this); @@ -430,6 +432,7 @@ mPluginEditorManagerInterface->setParentWidget(this); mPluginEditorManagerInterface->setRichTextEditor(mRichTextEditorwidget->editor()); mPluginEditorManagerInterface->setActionCollection(actionCollection()); + mPluginEditorManagerInterface->setComposerInterface(mComposerBase); mPluginEditorCheckBeforeSendManagerInterface->setParentWidget(this); @@ -455,11 +458,11 @@ applyMainWindowSettings(KMKernel::self()->config()->group("Composer")); - connect(mEdtSubject, &PimCommon::LineEditWithAutoCorrection::textChanged, this, &KMComposerWin::slotUpdateWindowTitle); - mIdentityConnection = connect(identity, &KIdentityManagement::IdentityCombo::identityChanged, [this](uint val) { + mUpdateWindowTitleConnection = connect(mEdtSubject, &PimCommon::LineEditWithAutoCorrection::textChanged, this, &KMComposerWin::slotUpdateWindowTitle); + mIdentityConnection = connect(identity, &KIdentityManagement::IdentityCombo::identityChanged, this, [this](uint val) { slotIdentityChanged(val); }); - connect(kmkernel->identityManager(), QOverload::of(&KIdentityManagement::IdentityManager::changed), this, [this](uint val) { + connect(kmkernel->identityManager(), qOverload(&KIdentityManagement::IdentityManager::changed), this, [this](uint val) { if (mComposerBase->identityCombo()->currentIdentity() == val) { slotIdentityChanged(val); } @@ -492,7 +495,7 @@ setMessage(aMsg, lastSignState, lastEncryptState); } - mComposerBase->recipientsEditor()->setFocus(); + mComposerBase->recipientsEditor()->setFocusBottom(); composerEditorNg->composerActions()->updateActionStates(); // set toolbar buttons to correct values mDone = true; @@ -506,6 +509,7 @@ KMComposerWin::~KMComposerWin() { + disconnect(mUpdateWindowTitleConnection); // When we have a collection set, store the message back to that collection. // Note that when we save the message or sent it, mFolder is set back to 0. // So this for example kicks in when opening a draft and then closing the window. @@ -517,6 +521,84 @@ delete mComposerBase; } +void KMComposerWin::insertSnippetInfo(const MailCommon::SnippetInfo &info) +{ + { + if (!info.to.isEmpty()) { + const QStringList lst = info.to.split(QLatin1Char(',')); + for (const QString &addr : lst) { + mComposerBase->recipientsEditor()->addRecipient(addr, MessageComposer::Recipient::To); + } + } + } + { + if (!info.cc.isEmpty()) { + const QStringList lst = info.cc.split(QLatin1Char(',')); + for (const QString &addr : lst) { + mComposerBase->recipientsEditor()->addRecipient(addr, MessageComposer::Recipient::Cc); + } + } + } + { + if (!info.bcc.isEmpty()) { + const QStringList lst = info.bcc.split(QLatin1Char(',')); + for (const QString &addr : lst) { + mComposerBase->recipientsEditor()->addRecipient(addr, MessageComposer::Recipient::Bcc); + } + } + } + { + if (!info.attachment.isEmpty()) { + const QStringList lst = info.attachment.split(QLatin1Char(',')); + for (const QString &attach : lst) { + MessageComposer::ConvertSnippetVariablesJob *job = new MessageComposer::ConvertSnippetVariablesJob(this); + job->setText(attach); + MessageComposer::ComposerViewInterface *interface = new MessageComposer::ComposerViewInterface(mComposerBase); + job->setComposerViewInterface(interface); + connect(job, &MessageComposer::ConvertSnippetVariablesJob::textConverted, this, [this](const QString &str) { + if (!str.isEmpty()) { + const QUrl localUrl = QUrl::fromLocalFile(str); + AttachmentInfo info; + info.url = localUrl; + addAttachment(QList() << info, false); + } + }); + job->start(); + } + } + } + { + if (!info.subject.isEmpty()) { + //Convert subject + MessageComposer::ConvertSnippetVariablesJob *job = new MessageComposer::ConvertSnippetVariablesJob(this); + job->setText(info.subject); + MessageComposer::ComposerViewInterface *interface = new MessageComposer::ComposerViewInterface(mComposerBase); + job->setComposerViewInterface(interface); + connect(job, &MessageComposer::ConvertSnippetVariablesJob::textConverted, this, [this](const QString &str) { + if (!str.isEmpty()) { + if (mComposerBase->subject().isEmpty()) { //Add subject only if we don't have subject + mEdtSubject->setText(str); + } + } + }); + job->start(); + } + } + { + if (!info.text.isEmpty()) { + //Convert plain text + MessageComposer::ConvertSnippetVariablesJob *job = new MessageComposer::ConvertSnippetVariablesJob(this); + job->setText(info.text); + MessageComposer::ComposerViewInterface *interface = new MessageComposer::ComposerViewInterface(mComposerBase); + job->setComposerViewInterface(interface); + connect(job, &MessageComposer::ConvertSnippetVariablesJob::textConverted, this, [this](const QString &str) { + mComposerBase->editor()->insertPlainText(str); + }); + job->start(); + } + } +} + void KMComposerWin::slotSpellCheckingLanguage(const QString &language) { mComposerBase->editor()->setSpellCheckingLanguage(language); @@ -565,9 +647,19 @@ send(how); } -void KMComposerWin::addAttachment(const QUrl &url, const QString &comment) +void KMComposerWin::addAttachment(const QList &infos, bool showWarning) { - mComposerBase->addAttachment(url, comment, false); + QStringList lst; + for (const AttachmentInfo &info : infos) { + if (showWarning) { + lst.append(info.url.toDisplayString()); + } + mComposerBase->addAttachment(info.url, info.comment, false); + } + if (showWarning) { + mAttachmentFromExternalMissing->setAttachmentNames(lst); + mAttachmentFromExternalMissing->animatedShow(); + } } void KMComposerWin::addAttachment(const QString &name, KMime::Headers::contentEncoding cte, const QString &charset, const QByteArray &data, const QByteArray &mimeType) @@ -621,10 +713,7 @@ mComposerBase->dictionary()->setCurrentByDictionaryName(ident.dictionary()); - QString fccName; - if (!ident.fcc().isEmpty()) { - fccName = ident.fcc(); - } + const QString fccName = ident.fcc(); setFcc(fccName); } @@ -653,7 +742,7 @@ MessageComposer::Composer *KMComposerWin::createSimpleComposer() { - QList< QByteArray > charsets = mCodecAction->mimeCharsets(); + QVector< QByteArray > charsets = mCodecAction->mimeCharsets(); if (!mOriginalPreferredCharset.isEmpty()) { charsets.insert(0, mOriginalPreferredCharset); } @@ -836,9 +925,9 @@ mGrid->addWidget(mComposerBase->recipientsEditor(), row, 0, 1, 2); ++row; connect(mEdtFrom, &MessageComposer::ComposerLineEdit::focusDown, mComposerBase->recipientsEditor(), &KPIM::MultiplyingLineEditor::setFocusTop); - connect(mComposerBase->recipientsEditor(), &KPIM::MultiplyingLineEditor::focusUp, mEdtFrom, QOverload<>::of(&QWidget::setFocus)); + connect(mComposerBase->recipientsEditor(), &KPIM::MultiplyingLineEditor::focusUp, mEdtFrom, qOverload<>(&QWidget::setFocus)); - connect(mComposerBase->recipientsEditor(), &KPIM::MultiplyingLineEditor::focusDown, mEdtSubject, QOverload<>::of(&QWidget::setFocus)); + connect(mComposerBase->recipientsEditor(), &KPIM::MultiplyingLineEditor::focusDown, mEdtSubject, qOverload<>(&QWidget::setFocus)); connect(mEdtSubject, &PimCommon::SpellCheckLineEdit::focusUp, mComposerBase->recipientsEditor(), &KPIM::MultiplyingLineEditor::setFocusBottom); prevFocus = mComposerBase->recipientsEditor(); @@ -1106,7 +1195,6 @@ mRecentAction->addUrl(QUrl(url)); } - action = new QAction(QIcon::fromTheme(QStringLiteral("x-office-address-book")), i18n("&Address Book"), this); KMail::Util::addQActionHelpText(action, i18n("Open Address Book")); actionCollection()->addAction(QStringLiteral("addressbook"), action); @@ -1255,7 +1343,7 @@ KStandardAction::configureToolbars(this, &KMComposerWin::slotEditToolbars, actionCollection()); KStandardAction::preferences(kmkernel, &KMKernel::slotShowConfigurationDialog, actionCollection()); - action = new QAction(i18n("&Spellchecker..."), this); + action = new QAction(QIcon::fromTheme(QStringLiteral("tools-check-spelling")), i18n("&Spellchecker..."), this); action->setIconText(i18n("Spellchecker")); actionCollection()->addAction(QStringLiteral("setup_spellchecker"), action); connect(action, &QAction::triggered, this, &KMComposerWin::slotSpellcheckConfig); @@ -1289,7 +1377,7 @@ mCryptoModuleAction = new KSelectAction(i18n("&Cryptographic Message Format"), this); actionCollection()->addAction(QStringLiteral("options_select_crypto"), mCryptoModuleAction); - connect(mCryptoModuleAction, QOverload::of(&KSelectAction::triggered), this, &KMComposerWin::slotCryptoModuleSelected); + connect(mCryptoModuleAction, qOverload(&KSelectAction::triggered), this, &KMComposerWin::slotCryptoModuleSelected); mCryptoModuleAction->setToolTip(i18n("Select a cryptographic format for this message")); mCryptoModuleAction->setItems(listCryptoFormat); @@ -1351,16 +1439,16 @@ localEditorManagerActionsType.next(); QList lst = localEditorManagerActionsType.value(); if (!lst.isEmpty()) { - const QString actionlistname = QStringLiteral("kmaileditor") + MessageComposer::PluginActionType::actionXmlExtension(localEditorManagerActionsType.key()); + const QString actionlistname = QLatin1String("kmaileditor") + MessageComposer::PluginActionType::actionXmlExtension(localEditorManagerActionsType.key()); hashActions.insert(actionlistname, lst); } } QHashIterator > localEditorConvertTextManagerActionsType(mPluginEditorConvertTextManagerInterface->actionsType()); while (localEditorConvertTextManagerActionsType.hasNext()) { localEditorConvertTextManagerActionsType.next(); QList lst = localEditorConvertTextManagerActionsType.value(); if (!lst.isEmpty()) { - const QString actionlistname = QStringLiteral("kmaileditor") + MessageComposer::PluginActionType::actionXmlExtension(localEditorConvertTextManagerActionsType.key()); + const QString actionlistname = QLatin1String("kmaileditor") + MessageComposer::PluginActionType::actionXmlExtension(localEditorConvertTextManagerActionsType.key()); if (hashActions.contains(actionlistname)) { lst = hashActions.value(actionlistname) + lst; hashActions.remove(actionlistname); @@ -1370,7 +1458,7 @@ } const QList customToolsWidgetActionList = mCustomToolsWidget->actionList(); - const QString actionlistname = QStringLiteral("kmaileditor") + MessageComposer::PluginActionType::actionXmlExtension(MessageComposer::PluginActionType::Tools); + const QString actionlistname = QLatin1String("kmaileditor") + MessageComposer::PluginActionType::actionXmlExtension(MessageComposer::PluginActionType::Tools); for (KToggleAction *act : customToolsWidgetActionList) { QList lst; lst << act; @@ -1442,15 +1530,15 @@ mCursorColumnLabel->setTextFormat(Qt::PlainText); statusBar()->addPermanentWidget(mCursorColumnLabel); - mStatusBarLabelToggledOverrideMode = new StatusBarLabelToggledState(this); + mStatusBarLabelToggledOverrideMode = new MessageComposer::StatusBarLabelToggledState(this); mStatusBarLabelToggledOverrideMode->setStateString(i18n("OVR"), i18n("INS")); statusBar()->addPermanentWidget(mStatusBarLabelToggledOverrideMode, 0); - connect(mStatusBarLabelToggledOverrideMode, &StatusBarLabelToggledState::toggleModeChanged, this, &KMComposerWin::slotOverwriteModeWasChanged); + connect(mStatusBarLabelToggledOverrideMode, &MessageComposer::StatusBarLabelToggledState::toggleModeChanged, this, &KMComposerWin::slotOverwriteModeWasChanged); - mStatusBarLabelSpellCheckingChangeMode = new StatusBarLabelToggledState(this); + mStatusBarLabelSpellCheckingChangeMode = new MessageComposer::StatusBarLabelToggledState(this); mStatusBarLabelSpellCheckingChangeMode->setStateString(i18n("Spellcheck: on"), i18n("Spellcheck: off")); statusBar()->addPermanentWidget(mStatusBarLabelSpellCheckingChangeMode, 0); - connect(mStatusBarLabelSpellCheckingChangeMode, &StatusBarLabelToggledState::toggleModeChanged, this, &KMComposerWin::slotAutoSpellCheckingToggled); + connect(mStatusBarLabelSpellCheckingChangeMode, &MessageComposer::StatusBarLabelToggledState::toggleModeChanged, this, &KMComposerWin::slotAutoSpellCheckingToggled); } void KMComposerWin::setupEditor() @@ -1575,7 +1663,7 @@ // load the mId into the gui, sticky or not, without emitting mComposerBase->identityCombo()->setCurrentIdentity(mId); - mIdentityConnection = connect(mComposerBase->identityCombo(), &KIdentityManagement::IdentityCombo::identityChanged, [this](uint val) { + mIdentityConnection = connect(mComposerBase->identityCombo(), &KIdentityManagement::IdentityCombo::identityChanged, this, [this](uint val) { slotIdentityChanged(val); }); @@ -1693,7 +1781,7 @@ // // Espen 2000-05-16 // Delay the signature appending. It may start a fileseletor. - // Not user friendy if this modal fileseletor opens before the + // Not user friendly if this modal fileseletor opens before the // composer. // if (MessageComposer::MessageComposerSettings::self()->prependSignature()) { @@ -1739,6 +1827,10 @@ if (col.isValid()) { mComposerBase->setFcc(col); mFccFolder->setCollection(col); + mIncorrectIdentityFolderWarning->clearFccInvalid(); + } else { + mIncorrectIdentityFolderWarning->fccIsInvalid(); + qCWarning(KMAIL_LOG) << "setFcc: collection invalid " << idString; } } @@ -1830,7 +1922,7 @@ } mComposerBase->setSubject(subject()); //be sure the composer knows the subject - MessageComposer::ComposerViewBase::MissingAttachment missingAttachments = mComposerBase->checkForMissingAttachments(KMailSettings::self()->attachmentKeywords()); + const MessageComposer::ComposerViewBase::MissingAttachment missingAttachments = mComposerBase->checkForMissingAttachments(KMailSettings::self()->attachmentKeywords()); return missingAttachments; } @@ -1869,8 +1961,11 @@ } } -void KMComposerWin::slotSendSuccessful() +void KMComposerWin::slotSendSuccessful(Akonadi::Item::Id id) { + if (id != -1) { + UndoSendManager::self()->addItem(id, subject(), KMailSettings::self()->undoSendDelay()); + } setModified(false); mComposerBase->cleanupAutoSave(); mFolder = Akonadi::Collection(); // see dtor @@ -1898,7 +1993,10 @@ void KMComposerWin::slotAddressBook() { - KRun::runCommand(QStringLiteral("kaddressbook"), window()); + KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(QStringLiteral("kaddressbook"), {}, this); + job->setDesktopName(QStringLiteral("org.kde.kaddressbook")); + job->setUiDelegate(new KDialogJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); + job->start(); } void KMComposerWin::slotInsertFile() @@ -1973,8 +2071,8 @@ bool KMComposerWin::showErrorMessage(KJob *job) { if (job->error()) { - if (static_cast(job)->uiDelegate()) { - static_cast(job)->uiDelegate()->showErrorMessage(); + if (auto uiDelegate = static_cast(job)->uiDelegate()) { + uiDelegate->showErrorMessage(); } else { qCDebug(KMAIL_LOG) << " job->errorString() :" << job->errorString(); } @@ -2147,9 +2245,13 @@ if (items.isEmpty() && collections.isEmpty()) { if (allLocalURLs || forceAttachment) { + QList infoList; for (const QUrl &url : urlList) { - addAttachment(url, QString()); + AttachmentInfo info; + info.url = url; + infoList.append(info); } + addAttachment(infoList, false); } else { QMenu p; const int sizeUrl(urlList.size()); @@ -2160,11 +2262,15 @@ if (selectedAction == addAsTextAction) { insertUrls(source, urlList); } else if (selectedAction == addAsAttachmentAction) { + QList infoList; for (const QUrl &url : urlList) { if (url.isValid()) { - addAttachment(url, QString()); + AttachmentInfo info; + info.url = url; + infoList.append(info); } } + addAttachment(infoList, false); } } return true; @@ -2187,6 +2293,9 @@ void KMComposerWin::slotPasteAsAttachment() { const QMimeData *mimeData = QApplication::clipboard()->mimeData(); + if (!mimeData) { + return; + } if (insertFromMimeData(mimeData, true)) { return; } @@ -2288,6 +2397,7 @@ void KMComposerWin::slotUpdateWindowTitle() { QString s(mEdtSubject->toPlainText()); + mComposerBase->setSubject(s); // Remove characters that show badly in most window decorations: // newlines tend to become boxes. if (s.isEmpty()) { @@ -2509,10 +2619,12 @@ void KMComposerWin::doSend(MessageComposer::MessageSender::SendMethod method, MessageComposer::MessageSender::SaveIn saveIn, bool willSendItWithoutReediting) { - const MessageComposer::ComposerViewBase::MissingAttachment forgotAttachment = userForgotAttachment(); - if ((forgotAttachment == MessageComposer::ComposerViewBase::FoundMissingAttachmentAndAddedAttachment) - || (forgotAttachment == MessageComposer::ComposerViewBase::FoundMissingAttachmentAndCancel)) { - return; + if (saveIn == MessageComposer::MessageSender::SaveInNone) { + const MessageComposer::ComposerViewBase::MissingAttachment forgotAttachment = userForgotAttachment(); + if ((forgotAttachment == MessageComposer::ComposerViewBase::FoundMissingAttachmentAndAddedAttachment) + || (forgotAttachment == MessageComposer::ComposerViewBase::FoundMissingAttachmentAndCancel)) { + return; + } } //TODO generate new message from plugins. @@ -2527,6 +2639,20 @@ if (!MessageComposer::Util::sendMailDispatcherIsOnline()) { method = MessageComposer::MessageSender::SendLater; } + if (KMailSettings::self()->enabledUndoSend()) { + mComposerBase->setSendLaterInfo(nullptr); + const bool wasRegistered = sendLaterRegistered(); + if (wasRegistered) { + auto info = new MessageComposer::SendLaterInfo; + info->setRecurrence(false); + info->setSubject(subject()); + info->setDateTime(QDateTime::currentDateTime().addSecs(KMailSettings::self()->undoSendDelay())); + mComposerBase->setSendLaterInfo(info); + } + method = MessageComposer::MessageSender::SendLater; + willSendItWithoutReediting = true; + saveIn = MessageComposer::MessageSender::SaveInOutbox; + } } if (saveIn == MessageComposer::MessageSender::SaveInNone || willSendItWithoutReediting) { // don't save as draft or template, send immediately @@ -2604,7 +2730,7 @@ setEnabled(false); // Validate the To:, CC: and BCC fields - AddressValidationJob *job = new AddressValidationJob(recipients.join(QStringLiteral(", ")), this, this); + AddressValidationJob *job = new AddressValidationJob(recipients.join(QLatin1String(", ")), this, this); job->setDefaultDomain(defaultDomainName); job->setProperty("method", static_cast(method)); job->setProperty("saveIn", static_cast(saveIn)); @@ -2649,7 +2775,7 @@ void KMComposerWin::applyComposerSetting(MessageComposer::ComposerViewBase *mComposerBase) { - QList< QByteArray > charsets = mCodecAction->mimeCharsets(); + QVector< QByteArray > charsets = mCodecAction->mimeCharsets(); if (!mOriginalPreferredCharset.isEmpty()) { charsets.insert(0, mOriginalPreferredCharset); } @@ -2695,6 +2821,12 @@ mComposerBase->send(method, saveIn, false); } +bool KMComposerWin::sendLaterRegistered() const +{ + return MessageComposer::SendLaterUtil::sentLaterAgentWasRegistered() + && MessageComposer::SendLaterUtil::sentLaterAgentEnabled(); +} + void KMComposerWin::slotSendLater() { if (!TransportManager::self()->showTransportCreationDialog(this, TransportManager::IfNoTransportExists)) { @@ -2705,25 +2837,25 @@ } mComposerBase->setSendLaterInfo(nullptr); if (mComposerBase->editor()->checkExternalEditorFinished()) { - const bool wasRegistered = (SendLater::SendLaterUtil::sentLaterAgentWasRegistered() && SendLater::SendLaterUtil::sentLaterAgentEnabled()); + const bool wasRegistered = sendLaterRegistered(); if (wasRegistered) { - SendLater::SendLaterInfo *info = nullptr; - QPointer dlg = new SendLater::SendLaterDialog(info, this); + MessageComposer::SendLaterInfo *info = nullptr; + QPointer dlg = new MessageComposer::SendLaterDialog(info, this); if (dlg->exec()) { info = dlg->info(); - const SendLater::SendLaterDialog::SendLaterAction action = dlg->action(); + const MessageComposer::SendLaterDialog::SendLaterAction action = dlg->action(); delete dlg; switch (action) { - case SendLater::SendLaterDialog::Unknown: + case MessageComposer::SendLaterDialog::Unknown: qCDebug(KMAIL_LOG) << "Sendlater action \"Unknown\": Need to fix it."; break; - case SendLater::SendLaterDialog::Canceled: + case MessageComposer::SendLaterDialog::Canceled: return; break; - case SendLater::SendLaterDialog::PutInOutbox: + case MessageComposer::SendLaterDialog::PutInOutbox: doSend(MessageComposer::MessageSender::SendLater); break; - case SendLater::SendLaterDialog::SendDeliveryAtTime: + case MessageComposer::SendLaterDialog::SendDeliveryAtTime: mComposerBase->setSendLaterInfo(info); if (info->isRecurrence()) { doSend(MessageComposer::MessageSender::SendLater, MessageComposer::MessageSender::SaveInTemplates, true); @@ -2988,6 +3120,13 @@ mStatusBarLabelSpellCheckingChangeMode->setToggleMode(on); } +void KMComposerWin::showAndActivateComposer() +{ + show(); + raise(); + activateWindow(); +} + void KMComposerWin::slotSpellCheckingStatus(const QString &status) { mStatusbarLabel->setText(status); @@ -3331,6 +3470,11 @@ mExtraHeaders = headers; } +bool KMComposerWin::processModifyText(QKeyEvent *event) +{ + return mPluginEditorManagerInterface->processProcessKeyEvent(event); +} + MessageComposer::PluginEditorConvertTextInterface::ConvertTextStatus KMComposerWin::convertPlainText(MessageComposer::TextPart *textPart) { return mPluginEditorConvertTextManagerInterface->convertTextToFormat(textPart); diff --git a/src/editor/plugininterface/kmailplugineditorcheckbeforesendmanagerinterface.h b/src/editor/plugininterface/kmailplugineditorcheckbeforesendmanagerinterface.h --- a/src/editor/plugininterface/kmailplugineditorcheckbeforesendmanagerinterface.h +++ b/src/editor/plugininterface/kmailplugineditorcheckbeforesendmanagerinterface.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2016-2019 Montel Laurent + Copyright (C) 2016-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/editor/plugininterface/kmailplugineditorcheckbeforesendmanagerinterface.cpp b/src/editor/plugininterface/kmailplugineditorcheckbeforesendmanagerinterface.cpp --- a/src/editor/plugininterface/kmailplugineditorcheckbeforesendmanagerinterface.cpp +++ b/src/editor/plugininterface/kmailplugineditorcheckbeforesendmanagerinterface.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2016-2019 Montel Laurent + Copyright (C) 2016-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/editor/plugininterface/kmailplugineditorconverttextmanagerinterface.h b/src/editor/plugininterface/kmailplugineditorconverttextmanagerinterface.h --- a/src/editor/plugininterface/kmailplugineditorconverttextmanagerinterface.h +++ b/src/editor/plugininterface/kmailplugineditorconverttextmanagerinterface.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2018-2019 Montel Laurent + Copyright (C) 2018-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -45,17 +45,17 @@ KPIMTextEdit::RichTextComposer *richTextEditor() const; void setRichTextEditor(KPIMTextEdit::RichTextComposer *richTextEditor); - QHash > actionsType(); - QList actionsType(MessageComposer::PluginActionType::Type type); + Q_REQUIRED_RESULT QHash > actionsType(); + Q_REQUIRED_RESULT QList actionsType(MessageComposer::PluginActionType::Type type); void reformatText(); MessageComposer::PluginEditorConvertTextInterface::ConvertTextStatus convertTextToFormat(MessageComposer::TextPart *textPart); void setInitialData(const MessageComposer::PluginEditorConverterInitialData &data); void setDataBeforeConvertingText(const MessageComposer::PluginEditorConverterBeforeConvertingData &data); void enableDisablePluginActions(bool richText); - QList statusBarWidgetList(); + Q_REQUIRED_RESULT QList statusBarWidgetList(); Q_SIGNALS: void reformatingTextDone(); diff --git a/src/editor/plugininterface/kmailplugineditorconverttextmanagerinterface.cpp b/src/editor/plugininterface/kmailplugineditorconverttextmanagerinterface.cpp --- a/src/editor/plugininterface/kmailplugineditorconverttextmanagerinterface.cpp +++ b/src/editor/plugininterface/kmailplugineditorconverttextmanagerinterface.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2018-2019 Montel Laurent + Copyright (C) 2018-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -165,7 +165,7 @@ if (interface->plugin()->hasPopupMenuSupport()) { type = MessageComposer::PluginActionType::PopupMenu; if (currentAction) { - QList lst = mActionHash.value(type); + lst = mActionHash.value(type); if (!lst.isEmpty()) { QAction *act = new QAction(this); act->setSeparator(true); @@ -178,7 +178,7 @@ } if (interface->plugin()->hasToolBarSupport()) { type = MessageComposer::PluginActionType::ToolBar; - QList lst = mActionHash.value(type); + lst = mActionHash.value(type); if (!lst.isEmpty()) { QAction *act = new QAction(this); act->setSeparator(true); diff --git a/src/editor/plugininterface/kmailplugineditorinitmanagerinterface.h b/src/editor/plugininterface/kmailplugineditorinitmanagerinterface.h --- a/src/editor/plugininterface/kmailplugineditorinitmanagerinterface.h +++ b/src/editor/plugininterface/kmailplugineditorinitmanagerinterface.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Montel Laurent + Copyright (C) 2017-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/editor/plugininterface/kmailplugineditorinitmanagerinterface.cpp b/src/editor/plugininterface/kmailplugineditorinitmanagerinterface.cpp --- a/src/editor/plugininterface/kmailplugineditorinitmanagerinterface.cpp +++ b/src/editor/plugininterface/kmailplugineditorinitmanagerinterface.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Montel Laurent + Copyright (C) 2017-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/editor/plugininterface/kmailplugineditormanagerinterface.h b/src/editor/plugininterface/kmailplugineditormanagerinterface.h --- a/src/editor/plugininterface/kmailplugineditormanagerinterface.h +++ b/src/editor/plugininterface/kmailplugineditormanagerinterface.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -22,12 +22,13 @@ #include #include -#include "messagecomposer/plugineditorinterface.h" +#include namespace KPIMTextEdit { class RichTextEditor; } namespace MessageComposer { class PluginEditorInterface; +class ComposerViewBase; } class KActionCollection; class KMailPluginEditorManagerInterface : public QObject @@ -48,9 +49,14 @@ KActionCollection *actionCollection() const; void setActionCollection(KActionCollection *actionCollection); - QHash > actionsType(); - QList actionsType(MessageComposer::PluginActionType::Type type); - QList statusBarWidgetList(); + Q_REQUIRED_RESULT QHash > actionsType(); + Q_REQUIRED_RESULT QList actionsType(MessageComposer::PluginActionType::Type type); + Q_REQUIRED_RESULT QList statusBarWidgetList(); + + MessageComposer::ComposerViewBase *composerInterface() const; + void setComposerInterface(MessageComposer::ComposerViewBase *composerInterface); + + Q_REQUIRED_RESULT bool processProcessKeyEvent(QKeyEvent *event); Q_SIGNALS: void textSelectionChanged(bool hasSelection); @@ -61,6 +67,7 @@ Q_DISABLE_COPY(KMailPluginEditorManagerInterface) void slotPluginActivated(MessageComposer::PluginEditorInterface *interface); KPIMTextEdit::RichTextEditor *mRichTextEditor = nullptr; + MessageComposer::ComposerViewBase *mComposerInterface = nullptr; QWidget *mParentWidget = nullptr; KActionCollection *mActionCollection = nullptr; QList mListPluginInterface; diff --git a/src/editor/plugininterface/kmailplugineditormanagerinterface.cpp b/src/editor/plugininterface/kmailplugineditormanagerinterface.cpp --- a/src/editor/plugininterface/kmailplugineditormanagerinterface.cpp +++ b/src/editor/plugininterface/kmailplugineditormanagerinterface.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -18,8 +18,9 @@ */ #include "kmailplugineditormanagerinterface.h" -#include "messagecomposer/plugineditormanager.h" -#include "messagecomposer/plugineditor.h" +#include +#include +#include #include "kmail_debug.h" #include @@ -72,6 +73,9 @@ for (MessageComposer::PluginEditor *plugin : lstPlugin) { if (plugin->isEnabled()) { MessageComposer::PluginEditorInterface *interface = static_cast(plugin->createInterface(this)); + MessageComposer::PluginComposerInterface *composerInterface = new MessageComposer::PluginComposerInterface; + composerInterface->setComposerViewBase(mComposerInterface); + interface->setComposerInterface(composerInterface); interface->setRichTextEditor(mRichTextEditor); interface->setParentWidget(mParentWidget); interface->createAction(mActionCollection); @@ -89,6 +93,30 @@ interface->exec(); } +MessageComposer::ComposerViewBase *KMailPluginEditorManagerInterface::composerInterface() const +{ + return mComposerInterface; +} + +void KMailPluginEditorManagerInterface::setComposerInterface(MessageComposer::ComposerViewBase *composerInterface) +{ + mComposerInterface = composerInterface; +} + +bool KMailPluginEditorManagerInterface::processProcessKeyEvent(QKeyEvent *event) +{ + if (!mListPluginInterface.isEmpty()) { + for (MessageComposer::PluginEditorInterface *interface : qAsConst(mListPluginInterface)) { + if (static_cast(interface->plugin())->canProcessKeyEvent()) { + if (interface->processProcessKeyEvent(event)) { + return true; + } + } + } + } + return false; +} + KActionCollection *KMailPluginEditorManagerInterface::actionCollection() const { return mActionCollection; @@ -139,7 +167,7 @@ } if (interface->plugin()->hasPopupMenuSupport()) { type = MessageComposer::PluginActionType::PopupMenu; - QList lst = mActionHash.value(type); + lst = mActionHash.value(type); if (!lst.isEmpty()) { QAction *act = new QAction(this); act->setSeparator(true); @@ -151,7 +179,7 @@ } if (interface->plugin()->hasToolBarSupport()) { type = MessageComposer::PluginActionType::ToolBar; - QList lst = mActionHash.value(type); + lst = mActionHash.value(type); if (!lst.isEmpty()) { QAction *act = new QAction(this); act->setSeparator(true); diff --git a/src/editor/plugininterface/kmailplugingrammareditormanagerinterface.h b/src/editor/plugininterface/kmailplugingrammareditormanagerinterface.h --- a/src/editor/plugininterface/kmailplugingrammareditormanagerinterface.h +++ b/src/editor/plugininterface/kmailplugingrammareditormanagerinterface.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/editor/plugininterface/kmailplugingrammareditormanagerinterface.cpp b/src/editor/plugininterface/kmailplugingrammareditormanagerinterface.cpp --- a/src/editor/plugininterface/kmailplugingrammareditormanagerinterface.cpp +++ b/src/editor/plugininterface/kmailplugingrammareditormanagerinterface.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/editor/potentialphishingemail/autotests/potentialphishingdetaildialogtest.h b/src/editor/potentialphishingemail/autotests/potentialphishingdetaildialogtest.h --- a/src/editor/potentialphishingemail/autotests/potentialphishingdetaildialogtest.h +++ b/src/editor/potentialphishingemail/autotests/potentialphishingdetaildialogtest.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/editor/potentialphishingemail/autotests/potentialphishingdetaildialogtest.cpp b/src/editor/potentialphishingemail/autotests/potentialphishingdetaildialogtest.cpp --- a/src/editor/potentialphishingemail/autotests/potentialphishingdetaildialogtest.cpp +++ b/src/editor/potentialphishingemail/autotests/potentialphishingdetaildialogtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/editor/potentialphishingemail/autotests/potentialphishingdetailwidgettest.h b/src/editor/potentialphishingemail/autotests/potentialphishingdetailwidgettest.h --- a/src/editor/potentialphishingemail/autotests/potentialphishingdetailwidgettest.h +++ b/src/editor/potentialphishingemail/autotests/potentialphishingdetailwidgettest.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/editor/potentialphishingemail/autotests/potentialphishingdetailwidgettest.cpp b/src/editor/potentialphishingemail/autotests/potentialphishingdetailwidgettest.cpp --- a/src/editor/potentialphishingemail/autotests/potentialphishingdetailwidgettest.cpp +++ b/src/editor/potentialphishingemail/autotests/potentialphishingdetailwidgettest.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/editor/potentialphishingemail/autotests/potentialphishingemailjobtest.h b/src/editor/potentialphishingemail/autotests/potentialphishingemailjobtest.h --- a/src/editor/potentialphishingemail/autotests/potentialphishingemailjobtest.h +++ b/src/editor/potentialphishingemail/autotests/potentialphishingemailjobtest.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/editor/potentialphishingemail/autotests/potentialphishingemailjobtest.cpp b/src/editor/potentialphishingemail/autotests/potentialphishingemailjobtest.cpp --- a/src/editor/potentialphishingemail/autotests/potentialphishingemailjobtest.cpp +++ b/src/editor/potentialphishingemail/autotests/potentialphishingemailjobtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by @@ -86,9 +86,9 @@ void PotentialPhishingEmailJobTest::shouldEmitSignal() { PotentialPhishingEmailJob *job = new PotentialPhishingEmailJob; - QSignalSpy spy(job, SIGNAL(potentialPhishingEmailsFound(QStringList))); + QSignalSpy spy(job, &PotentialPhishingEmailJob::potentialPhishingEmailsFound); job->setPotentialPhishingEmails((QStringList() << QStringLiteral("\"bla@kde.org\" "))); - job->start(); + QVERIFY(job->start()); QCOMPARE(spy.count(), 1); } diff --git a/src/editor/potentialphishingemail/autotests/potentialphishingemailwarningtest.h b/src/editor/potentialphishingemail/autotests/potentialphishingemailwarningtest.h --- a/src/editor/potentialphishingemail/autotests/potentialphishingemailwarningtest.h +++ b/src/editor/potentialphishingemail/autotests/potentialphishingemailwarningtest.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/editor/potentialphishingemail/autotests/potentialphishingemailwarningtest.cpp b/src/editor/potentialphishingemail/autotests/potentialphishingemailwarningtest.cpp --- a/src/editor/potentialphishingemail/autotests/potentialphishingemailwarningtest.cpp +++ b/src/editor/potentialphishingemail/autotests/potentialphishingemailwarningtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/editor/potentialphishingemail/potentialphishingdetaildialog.h b/src/editor/potentialphishingemail/potentialphishingdetaildialog.h --- a/src/editor/potentialphishingemail/potentialphishingdetaildialog.h +++ b/src/editor/potentialphishingemail/potentialphishingdetaildialog.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/editor/potentialphishingemail/potentialphishingdetaildialog.cpp b/src/editor/potentialphishingemail/potentialphishingdetaildialog.cpp --- a/src/editor/potentialphishingemail/potentialphishingdetaildialog.cpp +++ b/src/editor/potentialphishingemail/potentialphishingdetaildialog.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by @@ -30,7 +30,7 @@ PotentialPhishingDetailDialog::PotentialPhishingDetailDialog(QWidget *parent) : QDialog(parent) { - setWindowTitle(i18n("Details")); + setWindowTitle(i18nc("@title:window", "Details")); QVBoxLayout *topLayout = new QVBoxLayout(this); setModal(true); diff --git a/src/editor/potentialphishingemail/potentialphishingdetailwidget.h b/src/editor/potentialphishingemail/potentialphishingdetailwidget.h --- a/src/editor/potentialphishingemail/potentialphishingdetailwidget.h +++ b/src/editor/potentialphishingemail/potentialphishingdetailwidget.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/editor/potentialphishingemail/potentialphishingdetailwidget.cpp b/src/editor/potentialphishingemail/potentialphishingdetailwidget.cpp --- a/src/editor/potentialphishingemail/potentialphishingdetailwidget.cpp +++ b/src/editor/potentialphishingemail/potentialphishingdetailwidget.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by @@ -20,9 +20,9 @@ #include "potentialphishingdetailwidget.h" #include -#include #include #include +#include #include #include diff --git a/src/editor/potentialphishingemail/potentialphishingemailjob.h b/src/editor/potentialphishingemail/potentialphishingemailjob.h --- a/src/editor/potentialphishingemail/potentialphishingemailjob.h +++ b/src/editor/potentialphishingemail/potentialphishingemailjob.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by @@ -34,10 +34,10 @@ void setEmailWhiteList(const QStringList &emails); void setPotentialPhishingEmails(const QStringList &emails); - QStringList potentialPhisingEmails() const; - bool start(); + Q_REQUIRED_RESULT QStringList potentialPhisingEmails() const; + Q_REQUIRED_RESULT bool start(); - QStringList checkEmails() const; + Q_REQUIRED_RESULT QStringList checkEmails() const; Q_SIGNALS: void potentialPhishingEmailsFound(const QStringList &emails); diff --git a/src/editor/potentialphishingemail/potentialphishingemailjob.cpp b/src/editor/potentialphishingemail/potentialphishingemailjob.cpp --- a/src/editor/potentialphishingemail/potentialphishingemailjob.cpp +++ b/src/editor/potentialphishingemail/potentialphishingemailjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/editor/potentialphishingemail/potentialphishingemailwarning.h b/src/editor/potentialphishingemail/potentialphishingemailwarning.h --- a/src/editor/potentialphishingemail/potentialphishingemailwarning.h +++ b/src/editor/potentialphishingemail/potentialphishingemailwarning.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/editor/potentialphishingemail/potentialphishingemailwarning.cpp b/src/editor/potentialphishingemail/potentialphishingemailwarning.cpp --- a/src/editor/potentialphishingemail/potentialphishingemailwarning.cpp +++ b/src/editor/potentialphishingemail/potentialphishingemailwarning.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/editor/validatesendmailshortcut.h b/src/editor/validatesendmailshortcut.h --- a/src/editor/validatesendmailshortcut.h +++ b/src/editor/validatesendmailshortcut.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014-2019 Montel Laurent + Copyright (c) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -23,10 +23,10 @@ class ValidateSendMailShortcut { public: - ValidateSendMailShortcut(KActionCollection *actionCollection, QWidget *parent = nullptr); + explicit ValidateSendMailShortcut(KActionCollection *actionCollection, QWidget *parent = nullptr); ~ValidateSendMailShortcut(); - bool validate(); + Q_REQUIRED_RESULT bool validate(); private: QWidget *mParent = nullptr; diff --git a/src/editor/validatesendmailshortcut.cpp b/src/editor/validatesendmailshortcut.cpp --- a/src/editor/validatesendmailshortcut.cpp +++ b/src/editor/validatesendmailshortcut.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2014-2019 Montel Laurent + Copyright (c) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -17,7 +17,7 @@ #include "validatesendmailshortcut.h" #include "kmail_debug.h" -#include "Libkdepim/PIMMessageBox" +#include #include "settings/kmailsettings.h" #include @@ -45,22 +45,22 @@ i18n("Remove Shortcut"), i18n("Ask Before Sending"), i18n("Sending Without Confirmation")); - if (result == KMessageBox::Yes) { + if (result == QDialogButtonBox::Yes) { QAction *act = mActionCollection->action(QStringLiteral("send_mail")); if (act) { act->setShortcut(QKeySequence()); mActionCollection->writeSettings(); } else { qCDebug(KMAIL_LOG) << "Unable to find action named \"send_mail\""; } sendNow = false; - } else if (result == KMessageBox::No) { + } else if (result == QDialogButtonBox::No) { KMailSettings::self()->setConfirmBeforeSendWhenUseShortcut(true); sendNow = true; - } else if (result == KMessageBox::Ok) { + } else if (result == QDialogButtonBox::Ok) { KMailSettings::self()->setConfirmBeforeSendWhenUseShortcut(false); sendNow = true; - } else if (result == KMessageBox::Cancel) { + } else if (result == QDialogButtonBox::Cancel) { return false; } KMailSettings::self()->setCheckSendDefaultActionShortcut(true); diff --git a/src/editor/warningwidgets/externaleditorwarning.h b/src/editor/warningwidgets/attachmentaddedfromexternalwarning.h copy from src/editor/warningwidgets/externaleditorwarning.h copy to src/editor/warningwidgets/attachmentaddedfromexternalwarning.h --- a/src/editor/warningwidgets/externaleditorwarning.h +++ b/src/editor/warningwidgets/attachmentaddedfromexternalwarning.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,17 +17,20 @@ Boston, MA 02110-1301, USA. */ -#ifndef EXTERNALEDITORWARNING_H -#define EXTERNALEDITORWARNING_H +#ifndef ATTACHMENTADDEDFROMEXTERNALWARNING_H +#define ATTACHMENTADDEDFROMEXTERNALWARNING_H +#include #include -class ExternalEditorWarning : public KMessageWidget +class AttachmentAddedFromExternalWarning : public KMessageWidget { Q_OBJECT public: - explicit ExternalEditorWarning(QWidget *parent = nullptr); - ~ExternalEditorWarning(); + explicit AttachmentAddedFromExternalWarning(QWidget *parent = nullptr); + ~AttachmentAddedFromExternalWarning(); + + void setAttachmentNames(const QStringList &lst); }; -#endif // EXTERNALEDITORWARNING_H +#endif // ATTACHMENTADDEDFROMEXTERNALWARNING_H diff --git a/src/searchdialog/searchpatternwarning.cpp b/src/editor/warningwidgets/attachmentaddedfromexternalwarning.cpp copy from src/searchdialog/searchpatternwarning.cpp copy to src/editor/warningwidgets/attachmentaddedfromexternalwarning.cpp --- a/src/searchdialog/searchpatternwarning.cpp +++ b/src/editor/warningwidgets/attachmentaddedfromexternalwarning.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,37 +17,27 @@ Boston, MA 02110-1301, USA. */ -#include "searchpatternwarning.h" - +#include "attachmentaddedfromexternalwarning.h" #include -using namespace KMail; -SearchPatternWarning::SearchPatternWarning(QWidget *parent) +AttachmentAddedFromExternalWarning::AttachmentAddedFromExternalWarning(QWidget *parent) : KMessageWidget(parent) { setVisible(false); setCloseButtonVisible(true); setMessageType(Information); setWordWrap(true); } -SearchPatternWarning::~SearchPatternWarning() -{ -} - -void SearchPatternWarning::setError(const QStringList &lstError) -{ - setText(i18n("Search failed some errors were found:
    • %1
    ", lstError.join(QStringLiteral("
  • ")))); -} - -void SearchPatternWarning::showWarningPattern(const QStringList &lstError) +AttachmentAddedFromExternalWarning::~AttachmentAddedFromExternalWarning() { - setError(lstError); - animatedShow(); } -void SearchPatternWarning::hideWarningPattern() +void AttachmentAddedFromExternalWarning::setAttachmentNames(const QStringList &lst) { - setText(QString()); - animatedHide(); + if (lst.count() == 1) { + setText(i18n("This attachment:
    • %1
    was added externally. Remove it if it's an error.", lst.at(0))); + } else { + setText(i18n("These attachments:
    • %1
    were added externally. Remove them if it's an error.", lst.join(QLatin1String("
  • ")))); + } } diff --git a/src/editor/warningwidgets/attachmentmissingwarning.h b/src/editor/warningwidgets/attachmentmissingwarning.h --- a/src/editor/warningwidgets/attachmentmissingwarning.h +++ b/src/editor/warningwidgets/attachmentmissingwarning.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/editor/warningwidgets/attachmentmissingwarning.cpp b/src/editor/warningwidgets/attachmentmissingwarning.cpp --- a/src/editor/warningwidgets/attachmentmissingwarning.cpp +++ b/src/editor/warningwidgets/attachmentmissingwarning.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Montel Laurent + Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/editor/warningwidgets/autotests/externaleditorwarningtest.h b/src/editor/warningwidgets/autotests/externaleditorwarningtest.h --- a/src/editor/warningwidgets/autotests/externaleditorwarningtest.h +++ b/src/editor/warningwidgets/autotests/externaleditorwarningtest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Montel Laurent + Copyright (C) 2017-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/editor/warningwidgets/autotests/externaleditorwarningtest.cpp b/src/editor/warningwidgets/autotests/externaleditorwarningtest.cpp --- a/src/editor/warningwidgets/autotests/externaleditorwarningtest.cpp +++ b/src/editor/warningwidgets/autotests/externaleditorwarningtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Montel Laurent + Copyright (C) 2017-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/editor/warningwidgets/autotests/incorrectidentityfolderwarningtest.h b/src/editor/warningwidgets/autotests/incorrectidentityfolderwarningtest.h --- a/src/editor/warningwidgets/autotests/incorrectidentityfolderwarningtest.h +++ b/src/editor/warningwidgets/autotests/incorrectidentityfolderwarningtest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Montel Laurent + Copyright (C) 2017-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/editor/warningwidgets/autotests/incorrectidentityfolderwarningtest.cpp b/src/editor/warningwidgets/autotests/incorrectidentityfolderwarningtest.cpp --- a/src/editor/warningwidgets/autotests/incorrectidentityfolderwarningtest.cpp +++ b/src/editor/warningwidgets/autotests/incorrectidentityfolderwarningtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Montel Laurent + Copyright (C) 2017-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -19,9 +19,8 @@ #include "incorrectidentityfolderwarningtest.h" #include "../incorrectidentityfolderwarning.h" -#include #include - +#include QTEST_MAIN(IncorrectIdentityFolderWarningTest) IncorrectIdentityFolderWarningTest::IncorrectIdentityFolderWarningTest(QObject *parent) diff --git a/src/editor/warningwidgets/externaleditorwarning.h b/src/editor/warningwidgets/externaleditorwarning.h --- a/src/editor/warningwidgets/externaleditorwarning.h +++ b/src/editor/warningwidgets/externaleditorwarning.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/editor/warningwidgets/externaleditorwarning.cpp b/src/editor/warningwidgets/externaleditorwarning.cpp --- a/src/editor/warningwidgets/externaleditorwarning.cpp +++ b/src/editor/warningwidgets/externaleditorwarning.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/editor/warningwidgets/incorrectidentityfolderwarning.h b/src/editor/warningwidgets/incorrectidentityfolderwarning.h --- a/src/editor/warningwidgets/incorrectidentityfolderwarning.h +++ b/src/editor/warningwidgets/incorrectidentityfolderwarning.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Montel Laurent + Copyright (C) 2017-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -33,6 +33,7 @@ void fccIsInvalid(); void identityInvalid(); void dictionaryInvalid(); + void clearFccInvalid(); private: void addNewLine(QString &str); diff --git a/src/editor/warningwidgets/incorrectidentityfolderwarning.cpp b/src/editor/warningwidgets/incorrectidentityfolderwarning.cpp --- a/src/editor/warningwidgets/incorrectidentityfolderwarning.cpp +++ b/src/editor/warningwidgets/incorrectidentityfolderwarning.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Montel Laurent + Copyright (C) 2017-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -58,6 +58,14 @@ updateText(); } +void IncorrectIdentityFolderWarning::clearFccInvalid() +{ + if (mFccIsInvalid) { + mFccIsInvalid = false; + updateText(); + } +} + void IncorrectIdentityFolderWarning::addNewLine(QString &str) { if (!str.isEmpty()) { @@ -83,8 +91,13 @@ addNewLine(text); text += i18n("Dictionary was not found. Please verify that you will use a correct dictionary."); } - setText(text); - animatedShow(); + if (text.isEmpty()) { + animatedHide(); + setText(QString()); + } else { + setText(text); + animatedShow(); + } } void IncorrectIdentityFolderWarning::slotHideAnnimationFinished() diff --git a/src/editor/widgets/cryptostateindicatorwidget.h b/src/editor/widgets/cryptostateindicatorwidget.h --- a/src/editor/widgets/cryptostateindicatorwidget.h +++ b/src/editor/widgets/cryptostateindicatorwidget.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/editor/widgets/cryptostateindicatorwidget.cpp b/src/editor/widgets/cryptostateindicatorwidget.cpp --- a/src/editor/widgets/cryptostateindicatorwidget.cpp +++ b/src/editor/widgets/cryptostateindicatorwidget.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -18,7 +18,7 @@ */ #include "cryptostateindicatorwidget.h" -#include "MessageCore/MessageCoreUtil" +#include #include #include diff --git a/src/editor/widgets/snippetwidget.h b/src/editor/widgets/snippetwidget.h deleted file mode 100644 --- a/src/editor/widgets/snippetwidget.h +++ /dev/null @@ -1,46 +0,0 @@ -/*************************************************************************** - * snippet feature from kdevelop/plugins/snippet/ * - * * - * Copyright (C) 2007 by Robert Gruber * - * rgruber@users.sourceforge.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef KMAIL_SNIPPETWIDGET_H -#define KMAIL_SNIPPETWIDGET_H - -#include - -namespace MailCommon { -class SnippetsManager; -} - -class KActionCollection; -class KMComposerEditorNg; - -class QContextMenuEvent; - -/** - * @author Robert Gruber - */ -class SnippetWidget : public QTreeView -{ - Q_OBJECT -public: - explicit SnippetWidget(KMComposerEditorNg *editor, KActionCollection *actionCollection, QWidget *parent = nullptr); - ~SnippetWidget() override; - -protected: - void contextMenuEvent(QContextMenuEvent *) override; - void dropEvent(QDropEvent *) override; - -private: - MailCommon::SnippetsManager *mSnippetsManager = nullptr; -}; - -#endif diff --git a/src/editor/widgets/snippetwidget.cpp b/src/editor/widgets/snippetwidget.cpp deleted file mode 100644 --- a/src/editor/widgets/snippetwidget.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/*************************************************************************** - * snippet feature from kdevelop/plugins/snippet/ * - * * - * Copyright (C) 2007 by Robert Gruber * - * rgruber@users.sourceforge.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "snippetwidget.h" - -#include "editor/kmcomposereditorng.h" - -#include - -#include -#include -#include - -#include -#include - -SnippetWidget::SnippetWidget(KMComposerEditorNg *editor, KActionCollection *actionCollection, QWidget *parent) - : QTreeView(parent) -{ - header()->hide(); - setAcceptDrops(true); - setDragEnabled(true); - setRootIsDecorated(true); - setAlternatingRowColors(true); - mSnippetsManager = new MailCommon::SnippetsManager(actionCollection, this, this); - mSnippetsManager->setEditor(editor, "insertPlainText", SIGNAL(insertSnippet())); - - setModel(mSnippetsManager->model()); - setSelectionModel(mSnippetsManager->selectionModel()); - - connect(this, &QAbstractItemView::activated, - mSnippetsManager->insertSnippetAction(), &QAction::trigger); - connect(mSnippetsManager->model(), &QAbstractItemModel::rowsInserted, - this, &QTreeView::expandAll); - connect(mSnippetsManager->model(), &QAbstractItemModel::rowsRemoved, - this, &QTreeView::expandAll); - - expandAll(); -} - -SnippetWidget::~SnippetWidget() -{ -} - -void SnippetWidget::contextMenuEvent(QContextMenuEvent *event) -{ - QMenu popup; - - const bool itemSelected = mSnippetsManager->selectionModel()->hasSelection(); - - bool canAddSnippet = true; - if (itemSelected) { - popup.setTitle(mSnippetsManager->selectedName()); - if (mSnippetsManager->snippetGroupSelected()) { - popup.addAction(mSnippetsManager->editSnippetGroupAction()); - popup.addAction(mSnippetsManager->deleteSnippetGroupAction()); - } else { - canAddSnippet = false; // subsnippets are not permitted - popup.addAction(mSnippetsManager->addSnippetAction()); - popup.addAction(mSnippetsManager->editSnippetAction()); - popup.addAction(mSnippetsManager->deleteSnippetAction()); - popup.addAction(mSnippetsManager->insertSnippetAction()); - } - popup.addSeparator(); - } else { - popup.setTitle(i18n("Text Snippets")); - } - if (canAddSnippet) { - popup.addAction(mSnippetsManager->addSnippetAction()); - } - popup.addAction(mSnippetsManager->addSnippetGroupAction()); - - popup.exec(event->globalPos()); -} - -void SnippetWidget::dropEvent(QDropEvent *event) -{ - if (event->source() == this) { - event->setDropAction(Qt::MoveAction); - } - QTreeView::dropEvent(event); -} diff --git a/src/folderarchive/autotests/folderarchiveaccountinfotest.h b/src/folderarchive/autotests/folderarchiveaccountinfotest.h --- a/src/folderarchive/autotests/folderarchiveaccountinfotest.h +++ b/src/folderarchive/autotests/folderarchiveaccountinfotest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/folderarchive/autotests/folderarchiveaccountinfotest.cpp b/src/folderarchive/autotests/folderarchiveaccountinfotest.cpp --- a/src/folderarchive/autotests/folderarchiveaccountinfotest.cpp +++ b/src/folderarchive/autotests/folderarchiveaccountinfotest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/folderarchive/folderarchiveaccountinfo.h b/src/folderarchive/folderarchiveaccountinfo.h --- a/src/folderarchive/folderarchiveaccountinfo.h +++ b/src/folderarchive/folderarchiveaccountinfo.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -35,27 +35,27 @@ FolderByYears }; - bool isValid() const; + Q_REQUIRED_RESULT bool isValid() const; - QString instanceName() const; + Q_REQUIRED_RESULT QString instanceName() const; void setInstanceName(const QString &instance); void setArchiveTopLevel(Akonadi::Collection::Id id); - Akonadi::Collection::Id archiveTopLevel() const; + Q_REQUIRED_RESULT Akonadi::Collection::Id archiveTopLevel() const; void setFolderArchiveType(FolderArchiveType type); - FolderArchiveType folderArchiveType() const; + Q_REQUIRED_RESULT FolderArchiveType folderArchiveType() const; void setEnabled(bool enabled); - bool enabled() const; + Q_REQUIRED_RESULT bool enabled() const; void setKeepExistingStructure(bool b); - bool keepExistingStructure() const; + Q_REQUIRED_RESULT bool keepExistingStructure() const; void writeConfig(KConfigGroup &config); void readConfig(const KConfigGroup &config); - bool operator==(const FolderArchiveAccountInfo &other) const; + Q_REQUIRED_RESULT bool operator==(const FolderArchiveAccountInfo &other) const; private: Akonadi::Collection::Id mArchiveTopLevelCollectionId = -1; diff --git a/src/folderarchive/folderarchiveaccountinfo.cpp b/src/folderarchive/folderarchiveaccountinfo.cpp --- a/src/folderarchive/folderarchiveaccountinfo.cpp +++ b/src/folderarchive/folderarchiveaccountinfo.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/folderarchive/folderarchiveagentcheckcollection.h b/src/folderarchive/folderarchiveagentcheckcollection.h --- a/src/folderarchive/folderarchiveagentcheckcollection.h +++ b/src/folderarchive/folderarchiveagentcheckcollection.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/folderarchive/folderarchiveagentcheckcollection.cpp b/src/folderarchive/folderarchiveagentcheckcollection.cpp --- a/src/folderarchive/folderarchiveagentcheckcollection.cpp +++ b/src/folderarchive/folderarchiveagentcheckcollection.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/folderarchive/folderarchiveagentjob.h b/src/folderarchive/folderarchiveagentjob.h --- a/src/folderarchive/folderarchiveagentjob.h +++ b/src/folderarchive/folderarchiveagentjob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/folderarchive/folderarchiveagentjob.cpp b/src/folderarchive/folderarchiveagentjob.cpp --- a/src/folderarchive/folderarchiveagentjob.cpp +++ b/src/folderarchive/folderarchiveagentjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/folderarchive/folderarchivecache.h b/src/folderarchive/folderarchivecache.h --- a/src/folderarchive/folderarchivecache.h +++ b/src/folderarchive/folderarchivecache.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -40,7 +40,7 @@ void addToCache(const QString &resourceName, Akonadi::Collection::Id id); - Akonadi::Collection::Id collectionId(FolderArchiveAccountInfo *info); + Q_REQUIRED_RESULT Akonadi::Collection::Id collectionId(FolderArchiveAccountInfo *info); void clearCacheWithContainsCollection(Akonadi::Collection::Id id); diff --git a/src/folderarchive/folderarchivecache.cpp b/src/folderarchive/folderarchivecache.cpp --- a/src/folderarchive/folderarchivecache.cpp +++ b/src/folderarchive/folderarchivecache.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/folderarchive/folderarchivemanager.h b/src/folderarchive/folderarchivemanager.h --- a/src/folderarchive/folderarchivemanager.h +++ b/src/folderarchive/folderarchivemanager.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/folderarchive/folderarchivemanager.cpp b/src/folderarchive/folderarchivemanager.cpp --- a/src/folderarchive/folderarchivemanager.cpp +++ b/src/folderarchive/folderarchivemanager.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -32,8 +32,6 @@ #include #include #include -#include -#include #include "kmail_debug.h" #include diff --git a/src/folderarchive/folderarchiveutil.h b/src/folderarchive/folderarchiveutil.h --- a/src/folderarchive/folderarchiveutil.h +++ b/src/folderarchive/folderarchiveutil.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -22,9 +22,9 @@ #include namespace FolderArchive { namespace FolderArchiveUtil { -QString groupConfigPattern(); -bool resourceSupportArchiving(const QString &resource); -QString configFileName(); +Q_REQUIRED_RESULT QString groupConfigPattern(); +Q_REQUIRED_RESULT bool resourceSupportArchiving(const QString &resource); +Q_REQUIRED_RESULT QString configFileName(); } } diff --git a/src/folderarchive/folderarchiveutil.cpp b/src/folderarchive/folderarchiveutil.cpp --- a/src/folderarchive/folderarchiveutil.cpp +++ b/src/folderarchive/folderarchiveutil.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/foldershortcutactionmanager.cpp b/src/foldershortcutactionmanager.cpp --- a/src/foldershortcutactionmanager.cpp +++ b/src/foldershortcutactionmanager.cpp @@ -19,7 +19,7 @@ #include "foldershortcutactionmanager.h" #include -#include "mailcommon/mailkernel.h" +#include #include #include @@ -100,7 +100,7 @@ if (collection.isValid()) { shortcutChanged(collection); } - if (model->rowCount(child) > 0) { + if (model->hasChildren(child)) { updateShortcutsForIndex(child, 0, model->rowCount(child) - 1); } } diff --git a/src/identity/identityaddvcarddialog.h b/src/identity/identityaddvcarddialog.h --- a/src/identity/identityaddvcarddialog.h +++ b/src/identity/identityaddvcarddialog.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2012-2019 Montel Laurent + Copyright (c) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -36,9 +36,9 @@ explicit IdentityAddVcardDialog(const QStringList &shadowIdentities, QWidget *parent = nullptr); ~IdentityAddVcardDialog(); - DuplicateMode duplicateMode() const; - QString duplicateVcardFromIdentity() const; - QUrl existingVCard() const; + Q_REQUIRED_RESULT DuplicateMode duplicateMode() const; + Q_REQUIRED_RESULT QString duplicateVcardFromIdentity() const; + Q_REQUIRED_RESULT QUrl existingVCard() const; private: QButtonGroup *mButtonGroup = nullptr; diff --git a/src/identity/identityaddvcarddialog.cpp b/src/identity/identityaddvcarddialog.cpp --- a/src/identity/identityaddvcarddialog.cpp +++ b/src/identity/identityaddvcarddialog.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2012-2019 Montel Laurent + Copyright (c) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -32,7 +32,7 @@ IdentityAddVcardDialog::IdentityAddVcardDialog(const QStringList &shadowIdentities, QWidget *parent) : QDialog(parent) { - setWindowTitle(i18n("Create own vCard")); + setWindowTitle(i18nc("@title:window", "Create own vCard")); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); QVBoxLayout *mainLayout = new QVBoxLayout(this); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); @@ -67,7 +67,7 @@ QHBoxLayout *hlay = new QHBoxLayout(); // inherits spacing vlay->addLayout(hlay); - mVCardPath = new KUrlRequester; + mVCardPath = new KUrlRequester(this); mVCardPath->setObjectName(QStringLiteral("kurlrequester_vcardpath")); mVCardPath->setMimeTypeFilters({QStringLiteral("text/vcard"), QStringLiteral("all/allfiles")}); diff --git a/src/identity/identitydialog.h b/src/identity/identitydialog.h --- a/src/identity/identitydialog.h +++ b/src/identity/identitydialog.h @@ -38,7 +38,7 @@ class KEditListWidget; class QComboBox; class KJob; -class KLineEdit; +class QLineEdit; class QPushButton; class QTabWidget; @@ -99,19 +99,19 @@ void slotVCardRemoved(); void slotHelp(); - bool keyMatchesEmailAddress(const GpgME::Key &key, const QString &email); - bool checkFolderExists(const QString &folder); - bool validateAddresses(const QString &addresses); + Q_REQUIRED_RESULT bool keyMatchesEmailAddress(const GpgME::Key &key, const QString &email); + Q_REQUIRED_RESULT bool checkFolderExists(const QString &folder); + Q_REQUIRED_RESULT bool validateAddresses(const QString &addresses); void updateVcardButton(); void editVcard(const QString &filename); void unregisterSpecialCollection(qint64 id); QString mVcardFilename; // "general" tab: - KLineEdit *mNameEdit = nullptr; - KLineEdit *mOrganizationEdit = nullptr; - KLineEdit *mEmailEdit = nullptr; + QLineEdit *mNameEdit = nullptr; + QLineEdit *mOrganizationEdit = nullptr; + QLineEdit *mEmailEdit = nullptr; KEditListWidget *mAliasEdit = nullptr; // "cryptography" tab: QWidget *mCryptographyTab = nullptr; @@ -123,9 +123,9 @@ QCheckBox *mAutoSign = nullptr; QCheckBox *mAutoEncrypt = nullptr; // "advanced" tab: - KLineEdit *mReplyToEdit = nullptr; - KLineEdit *mBccEdit = nullptr; - KLineEdit *mCcEdit = nullptr; + QLineEdit *mReplyToEdit = nullptr; + QLineEdit *mBccEdit = nullptr; + QLineEdit *mCcEdit = nullptr; Sonnet::DictionaryComboBox *mDictionaryCombo = nullptr; IdentityFolderRequester *mFccFolderRequester = nullptr; QCheckBox *mSentMailFolderCheck = nullptr; @@ -136,7 +136,7 @@ QCheckBox *mAttachMyVCard = nullptr; QPushButton *mEditVCard = nullptr; PimCommon::AutoCorrectionLanguage *mAutoCorrectionLanguage = nullptr; - KLineEdit *mDefaultDomainEdit = nullptr; + QLineEdit *mDefaultDomainEdit = nullptr; // "templates" tab: TemplateParser::TemplatesConfiguration *mWidget = nullptr; diff --git a/src/identity/identitydialog.cpp b/src/identity/identitydialog.cpp --- a/src/identity/identitydialog.cpp +++ b/src/identity/identitydialog.cpp @@ -3,7 +3,7 @@ This file is part of KMail, the KDE mail client. Copyright (c) 2002 Marc Mutz - Copyright (C) 2014-2019 Laurent Montel + Copyright (C) 2014-2020 Laurent Montel KMail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -38,35 +38,36 @@ #include #include -#include "MessageComposer/MessageComposerSettings" +#include #include // other KMail headers: #include "xfaceconfigurator.h" #include -#include "mailcommon/folderrequester.h" +#include #ifndef KCM_KPIMIDENTITIES_STANDALONE #include "settings/kmailsettings.h" #include "kmkernel.h" #endif -#include "mailcommon/mailkernel.h" +#include #include "job/addressvalidationjob.h" #include #include #include -#include "TemplateParser/TemplatesConfiguration" +#include #include "templatesconfiguration_kfg.h" // other kdepim headers: #include #include -#include "PimCommon/AutoCorrectionLanguage" +#include #include #include +#include // libkleopatra: #include #include @@ -78,16 +79,15 @@ #include #include -#include -#include -#include +#include +#include +#include using MailTransport::TransportManager; // other KDE headers: #include -#include -#include -#include +#include +#include #include "kmail_debug.h" #include #include @@ -272,7 +272,7 @@ IdentityDialog::IdentityDialog(QWidget *parent) : QDialog(parent) { - setWindowTitle(i18n("Edit Identity")); + setWindowTitle(i18nc("@title:window", "Edit Identity")); QVBoxLayout *mainLayout = new QVBoxLayout(this); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help, this); @@ -304,7 +304,8 @@ // "Name" line edit and label: ++row; - mNameEdit = new KLineEdit(tab); + mNameEdit = new QLineEdit(tab); + new LineEditCatchReturnKey(mNameEdit, this); glay->addWidget(mNameEdit, row, 1); QLabel *label = new QLabel(i18n("&Your name:"), tab); label->setBuddy(mNameEdit); @@ -319,7 +320,8 @@ // "Organization" line edit and label: ++row; - mOrganizationEdit = new KLineEdit(tab); + mOrganizationEdit = new QLineEdit(tab); + new LineEditCatchReturnKey(mOrganizationEdit, this); glay->addWidget(mOrganizationEdit, row, 1); label = new QLabel(i18n("Organi&zation:"), tab); label->setBuddy(mOrganizationEdit); @@ -335,7 +337,8 @@ // "Email Address" line edit and label: // (row 3: spacer) ++row; - mEmailEdit = new KLineEdit(tab); + mEmailEdit = new QLineEdit(tab); + new LineEditCatchReturnKey(mEmailEdit, this); glay->addWidget(mEmailEdit, row, 1); label = new QLabel(i18n("&Email address:"), tab); label->setBuddy(mEmailEdit); @@ -626,7 +629,8 @@ // "default domain" input field: ++row; QHBoxLayout *hbox = new QHBoxLayout; - mDefaultDomainEdit = new KLineEdit(tab); + mDefaultDomainEdit = new QLineEdit(tab); + new LineEditCatchReturnKey(mDefaultDomainEdit, this); mDefaultDomainEdit->setClearButtonEnabled(true); hbox->addWidget(mDefaultDomainEdit); QToolButton *restoreDefaultDomainName = new QToolButton; @@ -872,7 +876,7 @@ void IdentityDialog::setIdentity(KIdentityManagement::Identity &ident) { - setWindowTitle(i18n("Edit Identity \"%1\"", ident.identityName())); + setWindowTitle(i18nc("@title:window", "Edit Identity \"%1\"", ident.identityName())); // "General" tab: mNameEdit->setText(ident.fullName()); diff --git a/src/identity/identityeditvcarddialog.h b/src/identity/identityeditvcarddialog.h --- a/src/identity/identityeditvcarddialog.h +++ b/src/identity/identityeditvcarddialog.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2012-2019 Montel Laurent + Copyright (c) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -39,8 +39,9 @@ * @brief saveVcard * @return The file path for current vcard. */ - QString saveVcard() const; + Q_REQUIRED_RESULT QString saveVcard() const; + void reject() override; Q_SIGNALS: void vcardRemoved(); diff --git a/src/identity/identityeditvcarddialog.cpp b/src/identity/identityeditvcarddialog.cpp --- a/src/identity/identityeditvcarddialog.cpp +++ b/src/identity/identityeditvcarddialog.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2012-2019 Montel Laurent + Copyright (c) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -45,13 +45,13 @@ connect(buttonBox, &QDialogButtonBox::rejected, this, &IdentityEditVcardDialog::reject); if (QFileInfo::exists(fileName)) { - setWindowTitle(i18n("Edit own vCard")); + setWindowTitle(i18nc("@title:window", "Edit own vCard")); QPushButton *user1Button = new QPushButton; buttonBox->addButton(user1Button, QDialogButtonBox::ActionRole); user1Button->setText(i18n("Delete current vCard")); connect(user1Button, &QPushButton::clicked, this, &IdentityEditVcardDialog::slotDeleteCurrentVCard); } else { - setWindowTitle(i18n("Create own vCard")); + setWindowTitle(i18nc("@title:window", "Create own vCard")); } topLayout->addWidget(mContactEditor); @@ -127,3 +127,13 @@ } return mVcardFileName; } + +void IdentityEditVcardDialog::reject() +{ + if (KMessageBox::questionYesNo( + this, + i18nc("@info", "Do you really want to cancel?"), + i18nc("@title:window", "Confirmation")) == KMessageBox::Yes) { + QDialog::reject(); // Discard current changes + } +} diff --git a/src/identity/identityfolderrequester.h b/src/identity/identityfolderrequester.h --- a/src/identity/identityfolderrequester.h +++ b/src/identity/identityfolderrequester.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2016-2019 Montel Laurent + Copyright (c) 2016-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/identity/identityfolderrequester.cpp b/src/identity/identityfolderrequester.cpp --- a/src/identity/identityfolderrequester.cpp +++ b/src/identity/identityfolderrequester.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2016-2019 Montel Laurent + Copyright (C) 2016-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/identity/identityinvalidfolder.h b/src/identity/identityinvalidfolder.h --- a/src/identity/identityinvalidfolder.h +++ b/src/identity/identityinvalidfolder.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2016-2019 Montel Laurent + Copyright (c) 2016-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/identity/identityinvalidfolder.cpp b/src/identity/identityinvalidfolder.cpp --- a/src/identity/identityinvalidfolder.cpp +++ b/src/identity/identityinvalidfolder.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2016-2019 Montel Laurent + Copyright (C) 2016-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as diff --git a/src/identity/identitylistview.h b/src/identity/identitylistview.h --- a/src/identity/identitylistview.h +++ b/src/identity/identitylistview.h @@ -53,7 +53,7 @@ IdentityListViewItem(IdentityListView *parent, const KIdentityManagement::Identity &ident); IdentityListViewItem(IdentityListView *parent, QTreeWidgetItem *after, const KIdentityManagement::Identity &ident); - uint uoid() const; + Q_REQUIRED_RESULT uint uoid() const; KIdentityManagement::Identity &identity() const; virtual void setIdentity(const KIdentityManagement::Identity &ident); diff --git a/src/identity/identitypage.h b/src/identity/identitypage.h --- a/src/identity/identitypage.h +++ b/src/identity/identitypage.h @@ -44,7 +44,7 @@ explicit IdentityPage(QWidget *parent = nullptr); ~IdentityPage() override; - QString helpAnchor() const; + Q_REQUIRED_RESULT QString helpAnchor() const; void load(); void save() override; diff --git a/src/identity/identitypage.cpp b/src/identity/identitypage.cpp --- a/src/identity/identitypage.cpp +++ b/src/identity/identitypage.cpp @@ -60,8 +60,8 @@ mIPage.mIdentityList->setIdentityManager(mIdentityManager); connect(mIPage.mIdentityList, &QTreeWidget::itemSelectionChanged, this, &IdentityPage::slotIdentitySelectionChanged); - connect(this, QOverload::of(&IdentityPage::changed), this, &IdentityPage::slotIdentitySelectionChanged); - connect(mIPage.mIdentityList, QOverload::of(&IdentityListView::rename), + connect(this, qOverload(&IdentityPage::changed), this, &IdentityPage::slotIdentitySelectionChanged); + connect(mIPage.mIdentityList, qOverload(&IdentityListView::rename), this, &IdentityPage::slotRenameIdentityFromItem); connect(mIPage.mIdentityList, &QTreeWidget::itemDoubleClicked, this, &IdentityPage::slotModifyIdentity); connect(mIPage.mIdentityList, &IdentityListView::contextMenu, this, &IdentityPage::slotContextMenu); diff --git a/src/identity/newidentitydialog.h b/src/identity/newidentitydialog.h --- a/src/identity/newidentitydialog.h +++ b/src/identity/newidentitydialog.h @@ -27,7 +27,7 @@ #include class QComboBox; -class KLineEdit; +class QLineEdit; class QButtonGroup; namespace KIdentityManagement { @@ -48,14 +48,14 @@ }; explicit NewIdentityDialog(KIdentityManagement::IdentityManager *manager, QWidget *parent = nullptr); - QString identityName() const; - QString duplicateIdentity() const; - DuplicateMode duplicateMode() const; + Q_REQUIRED_RESULT QString identityName() const; + Q_REQUIRED_RESULT QString duplicateIdentity() const; + Q_REQUIRED_RESULT DuplicateMode duplicateMode() const; private: void slotHelp(); void slotEnableOK(const QString &); - KLineEdit *mLineEdit = nullptr; + QLineEdit *mLineEdit = nullptr; QComboBox *mComboBox = nullptr; QButtonGroup *mButtonGroup = nullptr; KIdentityManagement::IdentityManager *mIdentityManager = nullptr; diff --git a/src/identity/newidentitydialog.cpp b/src/identity/newidentitydialog.cpp --- a/src/identity/newidentitydialog.cpp +++ b/src/identity/newidentitydialog.cpp @@ -24,10 +24,10 @@ #include "newidentitydialog.h" #include - +#include #include #include -#include +#include #include #include @@ -47,7 +47,7 @@ : QDialog(parent) , mIdentityManager(manager) { - setWindowTitle(i18n("New Identity")); + setWindowTitle(i18nc("@title:window", "New Identity")); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help, this); QVBoxLayout *mainLayout = new QVBoxLayout(this); mOkButton = buttonBox->button(QDialogButtonBox::Ok); @@ -66,14 +66,15 @@ // row 0: line edit with label QHBoxLayout *hlay = new QHBoxLayout(); // inherits spacing vlay->addLayout(hlay); - mLineEdit = new KLineEdit(page); + mLineEdit = new QLineEdit(page); mLineEdit->setFocus(); mLineEdit->setClearButtonEnabled(true); + new KPIM::LineEditCatchReturnKey(mLineEdit, this); QLabel *l = new QLabel(i18n("&New identity:"), page); l->setBuddy(mLineEdit); hlay->addWidget(l); hlay->addWidget(mLineEdit, 1); - connect(mLineEdit, &KLineEdit::textChanged, this, &NewIdentityDialog::slotEnableOK); + connect(mLineEdit, &QLineEdit::textChanged, this, &NewIdentityDialog::slotEnableOK); mButtonGroup = new QButtonGroup(page); diff --git a/src/identity/xfaceconfigurator.h b/src/identity/xfaceconfigurator.h --- a/src/identity/xfaceconfigurator.h +++ b/src/identity/xfaceconfigurator.h @@ -35,10 +35,10 @@ explicit XFaceConfigurator(QWidget *parent = nullptr); ~XFaceConfigurator(); - bool isXFaceEnabled() const; + Q_REQUIRED_RESULT bool isXFaceEnabled() const; void setXFaceEnabled(bool enable); - QString xface() const; + Q_REQUIRED_RESULT QString xface() const; void setXFace(const QString &text); private: diff --git a/src/identity/xfaceconfigurator.cpp b/src/identity/xfaceconfigurator.cpp --- a/src/identity/xfaceconfigurator.cpp +++ b/src/identity/xfaceconfigurator.cpp @@ -35,14 +35,14 @@ #include #include #include -#include "kpimtextedit/plaintexteditor.h" -#include "kpimtextedit/plaintexteditorwidget.h" -#include +#include +#include +#include #include #include #include -#include +#include #include #include @@ -108,14 +108,14 @@ QStackedWidget *widgetStack = new QStackedWidget(this); widgetStack->setEnabled(false); // since !mEnableCheck->isChecked() vlay->addWidget(widgetStack, 1); - connect(sourceCombo, QOverload::of(&QComboBox::highlighted), widgetStack, &QStackedWidget::setCurrentIndex); - connect(sourceCombo, QOverload::of(&QComboBox::activated), widgetStack, &QStackedWidget::setCurrentIndex); + connect(sourceCombo, qOverload(&QComboBox::highlighted), widgetStack, &QStackedWidget::setCurrentIndex); + connect(sourceCombo, qOverload(&QComboBox::activated), widgetStack, &QStackedWidget::setCurrentIndex); connect(mEnableCheck, &QCheckBox::toggled, sourceCombo, &QComboBox::setEnabled); connect(mEnableCheck, &QCheckBox::toggled, widgetStack, &QStackedWidget::setEnabled); connect(mEnableCheck, &QCheckBox::toggled, label, &QLabel::setEnabled); // The focus might be still in the widget that is disabled connect(mEnableCheck, &QAbstractButton::clicked, - mEnableCheck, QOverload<>::of(&QWidget::setFocus)); + mEnableCheck, qOverload<>(&QWidget::setFocus)); int pageno = 0; // page 0: create X-Face from image file or address book entry @@ -276,7 +276,7 @@ if (!str.isEmpty()) { if (str.startsWith(QLatin1String("x-face:"), Qt::CaseInsensitive)) { - str = str.remove(QStringLiteral("x-face:"), Qt::CaseInsensitive); + str.remove(QStringLiteral("x-face:"), Qt::CaseInsensitive); mTextEdit->editor()->setPlainText(str); } KXFace xf; diff --git a/src/job/addemailtoexistingcontactjob.h b/src/job/addemailtoexistingcontactjob.h --- a/src/job/addemailtoexistingcontactjob.h +++ b/src/job/addemailtoexistingcontactjob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/job/addemailtoexistingcontactjob.cpp b/src/job/addemailtoexistingcontactjob.cpp --- a/src/job/addemailtoexistingcontactjob.cpp +++ b/src/job/addemailtoexistingcontactjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/job/addressvalidationjob.h b/src/job/addressvalidationjob.h --- a/src/job/addressvalidationjob.h +++ b/src/job/addressvalidationjob.h @@ -23,7 +23,7 @@ #ifndef ADDRESSVALIDATIONJOB_H #define ADDRESSVALIDATIONJOB_H -#include +#include class AddressValidationJob : public KJob { @@ -35,7 +35,7 @@ void start() override; - bool isValid() const; + Q_REQUIRED_RESULT bool isValid() const; void setDefaultDomain(const QString &domainName); diff --git a/src/job/addressvalidationjob.cpp b/src/job/addressvalidationjob.cpp --- a/src/job/addressvalidationjob.cpp +++ b/src/job/addressvalidationjob.cpp @@ -24,10 +24,10 @@ #include using MessageComposer::AliasesExpandJob; -#include "messagecomposer/messagecomposersettings.h" +#include #include -#include +#include #include diff --git a/src/job/composenewmessagejob.h b/src/job/composenewmessagejob.h --- a/src/job/composenewmessagejob.h +++ b/src/job/composenewmessagejob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/src/job/composenewmessagejob.cpp b/src/job/composenewmessagejob.cpp --- a/src/job/composenewmessagejob.cpp +++ b/src/job/composenewmessagejob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/src/job/createfollowupreminderonexistingmessagejob.h b/src/job/createfollowupreminderonexistingmessagejob.h --- a/src/job/createfollowupreminderonexistingmessagejob.h +++ b/src/job/createfollowupreminderonexistingmessagejob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -34,16 +34,16 @@ void start(); - Akonadi::Collection collection() const; + Q_REQUIRED_RESULT Akonadi::Collection collection() const; void setCollection(const Akonadi::Collection &collection); - QDate date() const; + Q_REQUIRED_RESULT QDate date() const; void setDate(const QDate &date); - Akonadi::Item messageItem() const; + Q_REQUIRED_RESULT Akonadi::Item messageItem() const; void setMessageItem(const Akonadi::Item &messageItem); - bool canStart() const; + Q_REQUIRED_RESULT bool canStart() const; private: Q_DISABLE_COPY(CreateFollowupReminderOnExistingMessageJob) diff --git a/src/job/createfollowupreminderonexistingmessagejob.cpp b/src/job/createfollowupreminderonexistingmessagejob.cpp --- a/src/job/createfollowupreminderonexistingmessagejob.cpp +++ b/src/job/createfollowupreminderonexistingmessagejob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -19,7 +19,7 @@ #include "createfollowupreminderonexistingmessagejob.h" #include "kmail_debug.h" -#include "MessageComposer/FollowupReminderCreateJob" +#include #include #include #include diff --git a/src/job/createforwardmessagejob.h b/src/job/createforwardmessagejob.h --- a/src/job/createforwardmessagejob.h +++ b/src/job/createforwardmessagejob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/src/job/createforwardmessagejob.cpp b/src/job/createforwardmessagejob.cpp --- a/src/job/createforwardmessagejob.cpp +++ b/src/job/createforwardmessagejob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/src/job/createnewcontactjob.h b/src/job/createnewcontactjob.h --- a/src/job/createnewcontactjob.h +++ b/src/job/createnewcontactjob.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2012-2019 Montel Laurent + Copyright (c) 2012-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/job/createnewcontactjob.cpp b/src/job/createnewcontactjob.cpp --- a/src/job/createnewcontactjob.cpp +++ b/src/job/createnewcontactjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2012-2019 Montel Laurent + Copyright (c) 2012-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by @@ -78,7 +78,7 @@ } if (canCreateItemCollections.isEmpty()) { QPointer dlg = new Akonadi::AgentTypeDialog(mParentWidget); - dlg->setWindowTitle(i18n("Add to Address Book")); + dlg->setWindowTitle(i18nc("@title:window", "Add to Address Book")); dlg->agentFilterProxyModel()->addMimeTypeFilter(KContacts::Addressee::mimeType()); dlg->agentFilterProxyModel()->addMimeTypeFilter(KContacts::ContactGroup::mimeType()); dlg->agentFilterProxyModel()->addCapabilityFilter(QStringLiteral("Resource")); diff --git a/src/job/createreplymessagejob.h b/src/job/createreplymessagejob.h --- a/src/job/createreplymessagejob.h +++ b/src/job/createreplymessagejob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/src/job/createreplymessagejob.cpp b/src/job/createreplymessagejob.cpp --- a/src/job/createreplymessagejob.cpp +++ b/src/job/createreplymessagejob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/src/job/createtaskjob.h b/src/job/createtaskjob.h --- a/src/job/createtaskjob.h +++ b/src/job/createtaskjob.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014-2019 Montel Laurent + Copyright (c) 2014-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/job/createtaskjob.cpp b/src/job/createtaskjob.cpp --- a/src/job/createtaskjob.cpp +++ b/src/job/createtaskjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2014-2019 Montel Laurent + Copyright (c) 2014-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/job/dndfromarkjob.h b/src/job/dndfromarkjob.h --- a/src/job/dndfromarkjob.h +++ b/src/job/dndfromarkjob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2018-2019 Laurent Montel + Copyright (C) 2018-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -30,7 +30,7 @@ public: explicit DndFromArkJob(QObject *parent = nullptr); static bool dndFromArk(const QMimeData *source); - bool extract(const QMimeData *source); + Q_REQUIRED_RESULT bool extract(const QMimeData *source); void setComposerWin(KMComposerWin *composerWin); private: diff --git a/src/job/dndfromarkjob.cpp b/src/job/dndfromarkjob.cpp --- a/src/job/dndfromarkjob.cpp +++ b/src/job/dndfromarkjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2018-2019 Laurent Montel + Copyright (C) 2018-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -28,6 +28,8 @@ #include #include +#include + DndFromArkJob::DndFromArkJob(QObject *parent) : QObject(parent) { @@ -63,10 +65,14 @@ message.setArguments({arkPath}); QDBusConnection::sessionBus().call(message); QDir dir(arkPath); - QStringList list = dir.entryList(QDir::NoDotAndDotDot | QDir::Files); + const QStringList list = dir.entryList(QDir::NoDotAndDotDot | QDir::Files); + QList infoList; for (int i = 0; i < list.size(); ++i) { - mComposerWin->addAttachment(QUrl::fromLocalFile(list.at(i)), QString()); + KMail::Composer::AttachmentInfo info; + info.url = QUrl::fromLocalFile(list.at(i)); + infoList.append(info); } + mComposerWin->addAttachment(infoList, false); delete linkDir; deleteLater(); return true; diff --git a/src/job/fillcomposerjob.h b/src/job/fillcomposerjob.h --- a/src/job/fillcomposerjob.h +++ b/src/job/fillcomposerjob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -32,7 +32,8 @@ { } - FillComposerJobSettings(bool hidden, const QString &to, const QString &cc, const QString &bcc, const QString &subject, const QString &body, const QString &attachName, const QByteArray &attachCte, const QByteArray &attachData, const QByteArray &attachType, const QByteArray &attachSubType, const QByteArray &attachParamAttr, const QString &attachParamValue, const QByteArray &attachContDisp, const QByteArray &attachCharset, unsigned int identity, bool forceShowWindow) + FillComposerJobSettings(bool hidden, const QString &to, const QString &cc, const QString &bcc, const QString &subject, const QString &body, const QString &attachName, const QByteArray &attachCte, const QByteArray &attachData, const QByteArray &attachType, const QByteArray &attachSubType, + const QByteArray &attachParamAttr, const QString &attachParamValue, const QByteArray &attachContDisp, const QByteArray &attachCharset, unsigned int identity, bool forceShowWindow) : mTo(to) , mCc(cc) , mBcc(bcc) diff --git a/src/job/fillcomposerjob.cpp b/src/job/fillcomposerjob.cpp --- a/src/job/fillcomposerjob.cpp +++ b/src/job/fillcomposerjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -21,7 +21,7 @@ #include "kmkernel.h" #include "composer.h" #include "editor/kmcomposerwin.h" -#include "messageviewer/messageviewersettings.h" +#include #include #include @@ -141,7 +141,7 @@ cWin->disableForgottenAttachmentsCheck(); } if (mSettings.mForceShowWindow || (!mSettings.mHidden && !iCalAutoSend)) { - cWin->show(); + cWin->showAndActivateComposer(); } else { // Always disable word wrap when we don't show the composer, since otherwise QTextEdit // gets the widget size wrong and wraps much too early. diff --git a/src/job/handleclickedurljob.h b/src/job/handleclickedurljob.h --- a/src/job/handleclickedurljob.h +++ b/src/job/handleclickedurljob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/src/job/handleclickedurljob.cpp b/src/job/handleclickedurljob.cpp --- a/src/job/handleclickedurljob.cpp +++ b/src/job/handleclickedurljob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -45,32 +45,32 @@ MessageHelper::initHeader(mMsg, KMKernel::self()->identityManager(), mIdentity); mMsg->contentType()->setCharset("utf-8"); - const QList > fields = MessageCore::StringUtil::parseMailtoUrl(mUrl); + const QVector > fields = MessageCore::StringUtil::parseMailtoUrl(mUrl); for (int i = 0; i < fields.count(); ++i) { const QPair element = fields.at(i); - if (element.first == QStringLiteral("to")) { + if (element.first == QLatin1String("to")) { mMsg->to()->fromUnicodeString(element.second, "utf-8"); - } else if (element.first == QStringLiteral("subject")) { + } else if (element.first == QLatin1String("subject")) { const QString subject = element.second; if (!subject.isEmpty()) { mMsg->subject()->fromUnicodeString(subject, "utf-8"); } - } else if (element.first == QStringLiteral("body")) { + } else if (element.first == QLatin1String("body")) { const QString body = element.second; if (!body.isEmpty()) { mMsg->setBody(body.toUtf8()); } - } else if (element.first == QStringLiteral("cc")) { + } else if (element.first == QLatin1String("cc")) { const QString cc = element.second; if (!cc.isEmpty()) { mMsg->cc()->fromUnicodeString(cc, "utf-8"); } - } else if (element.first == QStringLiteral("bcc")) { + } else if (element.first == QLatin1String("bcc")) { const QString bcc = element.second; if (!bcc.isEmpty()) { mMsg->bcc()->fromUnicodeString(bcc, "utf-8"); } - } else if (element.first == QStringLiteral("attach")) { + } else if (element.first == QLatin1String("attach")) { const QString attach = element.second; if (!attach.isEmpty()) { qCDebug(KMAIL_LOG) << "Attachment not supported yet"; diff --git a/src/job/markallmessagesasreadinfolderandsubfolderjob.h b/src/job/markallmessagesasreadinfolderandsubfolderjob.h --- a/src/job/markallmessagesasreadinfolderandsubfolderjob.h +++ b/src/job/markallmessagesasreadinfolderandsubfolderjob.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/job/markallmessagesasreadinfolderandsubfolderjob.cpp b/src/job/markallmessagesasreadinfolderandsubfolderjob.cpp --- a/src/job/markallmessagesasreadinfolderandsubfolderjob.cpp +++ b/src/job/markallmessagesasreadinfolderandsubfolderjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/job/newmessagejob.h b/src/job/newmessagejob.h --- a/src/job/newmessagejob.h +++ b/src/job/newmessagejob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/src/job/newmessagejob.cpp b/src/job/newmessagejob.cpp --- a/src/job/newmessagejob.cpp +++ b/src/job/newmessagejob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -68,8 +68,13 @@ win->setCollectionForNewMessage(mCollection); //Add the attachment if we have one + if (!mAttachURL.isEmpty() && mAttachURL.isValid()) { - win->addAttachment(mAttachURL, QString()); + QList infoList; + KMail::Composer::AttachmentInfo info; + info.url = mAttachURL; + infoList.append(info); + win->addAttachment(infoList, false); } //only show window when required diff --git a/src/job/opencomposerhiddenjob.h b/src/job/opencomposerhiddenjob.h --- a/src/job/opencomposerhiddenjob.h +++ b/src/job/opencomposerhiddenjob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -60,7 +60,7 @@ Q_DISABLE_COPY(OpenComposerHiddenJob) void slotOpenComposer(); OpenComposerHiddenJobSettings mSettings; - KMime::Message::Ptr mMsg; + KMime::Message::Ptr mMsg = nullptr; }; #endif // OPENCOMPOSERHIDDENJOB_H diff --git a/src/job/opencomposerhiddenjob.cpp b/src/job/opencomposerhiddenjob.cpp --- a/src/job/opencomposerhiddenjob.cpp +++ b/src/job/opencomposerhiddenjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -29,7 +29,6 @@ OpenComposerHiddenJob::OpenComposerHiddenJob(QObject *parent) : QObject(parent) - , mMsg(nullptr) { } @@ -72,7 +71,7 @@ : KMail::Composer::NoTemplate; KMail::Composer *cWin = KMail::makeComposer(mMsg, false, false, context); if (!mSettings.mHidden) { - cWin->show(); + cWin->showAndActivateComposer(); } else { // Always disable word wrap when we don't show the composer; otherwise, // QTextEdit gets the widget size wrong and wraps much too early. diff --git a/src/job/opencomposerjob.h b/src/job/opencomposerjob.h --- a/src/job/opencomposerjob.h +++ b/src/job/opencomposerjob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -30,7 +30,8 @@ { } - OpenComposerSettings(const QString &to, const QString &cc, const QString &bcc, const QString &subject, const QString &body, bool hidden, const QString &messageFile, const QStringList &attachmentPaths, const QStringList &customHeaders, const QString &replyTo, const QString &inReplyTo, const QString &identity) + OpenComposerSettings(const QString &to, const QString &cc, const QString &bcc, const QString &subject, const QString &body, bool hidden, const QString &messageFile, const QStringList &attachmentPaths, const QStringList &customHeaders, const QString &replyTo, const QString &inReplyTo, + const QString &identity) : mAttachmentPaths(attachmentPaths) , mCustomHeaders(customHeaders) , mTo(to) @@ -74,8 +75,8 @@ Q_DISABLE_COPY(OpenComposerJob) void slotOpenComposer(); OpenComposerSettings mOpenComposerSettings; - KMime::Message::Ptr mMsg; - KMail::Composer::TemplateContext mContext; + KMime::Message::Ptr mMsg = nullptr; + KMail::Composer::TemplateContext mContext = KMail::Composer::New; uint mIdentityId = 0; }; diff --git a/src/job/opencomposerjob.cpp b/src/job/opencomposerjob.cpp --- a/src/job/opencomposerjob.cpp +++ b/src/job/opencomposerjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Laurent Montel + Copyright (C) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -35,8 +35,6 @@ OpenComposerJob::OpenComposerJob(QObject *parent) : QObject(parent) - , mMsg(nullptr) - , mContext(KMail::Composer::New) { } @@ -102,7 +100,9 @@ } } else if (!mOpenComposerSettings.mBody.isEmpty()) { mContext = KMail::Composer::NoTemplate; - mMsg->setBody(mOpenComposerSettings.mBody.toLatin1()); + mMsg->setBody(mOpenComposerSettings.mBody.toUtf8()); + mMsg->assemble(); + mMsg->parse(); slotOpenComposer(); } else { TemplateParser::TemplateParserJob *parser = new TemplateParser::TemplateParserJob(mMsg, TemplateParser::TemplateParserJob::NewMessage); @@ -120,14 +120,20 @@ } QList attachURLs = QUrl::fromStringList(mOpenComposerSettings.mAttachmentPaths); QList::ConstIterator endAttachment(attachURLs.constEnd()); + QList infoList; for (QList::ConstIterator it = attachURLs.constBegin(); it != endAttachment; ++it) { QMimeDatabase mimeDb; if (mimeDb.mimeTypeForUrl(*it).name() == QLatin1String("inode/directory")) { if (KMessageBox::questionYesNo(nullptr, i18n("Do you want to attach this folder \"%1\"?", (*it).toDisplayString()), i18n("Attach Folder")) == KMessageBox::No) { continue; } } - cWin->addAttachment((*it), QString()); + KMail::Composer::AttachmentInfo info; + info.url = (*it); + infoList.append(info); + } + if (!infoList.isEmpty()) { + cWin->addAttachment(infoList, true); } if (!mOpenComposerSettings.mCustomHeaders.isEmpty()) { QMap extraCustomHeaders; @@ -149,7 +155,7 @@ } } if (!mOpenComposerSettings.mHidden) { - cWin->show(); + cWin->showAndActivateComposer(); } deleteLater(); } diff --git a/src/job/removecollectionjob.h b/src/job/removecollectionjob.h --- a/src/job/removecollectionjob.h +++ b/src/job/removecollectionjob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/job/removecollectionjob.cpp b/src/job/removecollectionjob.cpp --- a/src/job/removecollectionjob.cpp +++ b/src/job/removecollectionjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -24,8 +24,8 @@ #include #include #include "kmmainwidget.h" -#include "MailCommon/MailUtil" -#include "MailCommon/MailKernel" +#include +#include #include "kmkernel.h" RemoveCollectionJob::RemoveCollectionJob(QObject *parent) @@ -127,7 +127,9 @@ void RemoveCollectionJob::slotDeletionCollectionResult(KJob *job) { if (job) { - MailCommon::Util::showJobErrorMessage(job); + if (!MailCommon::Util::showJobErrorMessage(job)) { + //TODO + } } deleteLater(); } diff --git a/src/job/removeduplicatemailjob.h b/src/job/removeduplicatemailjob.h --- a/src/job/removeduplicatemailjob.h +++ b/src/job/removeduplicatemailjob.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/job/removeduplicatemailjob.cpp b/src/job/removeduplicatemailjob.cpp --- a/src/job/removeduplicatemailjob.cpp +++ b/src/job/removeduplicatemailjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -19,7 +19,7 @@ #include "removeduplicatemailjob.h" -#include "libkdepim/progressmanager.h" +#include #include #include #include diff --git a/src/job/removeduplicatemessageinfolderandsubfolderjob.h b/src/job/removeduplicatemessageinfolderandsubfolderjob.h --- a/src/job/removeduplicatemessageinfolderandsubfolderjob.h +++ b/src/job/removeduplicatemessageinfolderandsubfolderjob.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/job/removeduplicatemessageinfolderandsubfolderjob.cpp b/src/job/removeduplicatemessageinfolderandsubfolderjob.cpp --- a/src/job/removeduplicatemessageinfolderandsubfolderjob.cpp +++ b/src/job/removeduplicatemessageinfolderandsubfolderjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by @@ -22,7 +22,7 @@ #include #include "kmail_debug.h" #include -#include "libkdepim/progressmanager.h" +#include #include #include diff --git a/src/job/saveasfilejob.h b/src/job/saveasfilejob.h --- a/src/job/saveasfilejob.h +++ b/src/job/saveasfilejob.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/job/saveasfilejob.cpp b/src/job/saveasfilejob.cpp --- a/src/job/saveasfilejob.cpp +++ b/src/job/saveasfilejob.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015-2019 Montel Laurent + Copyright (c) 2015-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by @@ -38,7 +38,7 @@ void SaveAsFileJob::start() { QPointer dlg = new QFileDialog(mParentWidget); - dlg->setWindowTitle(i18n("Save File as")); + dlg->setWindowTitle(i18nc("@title:window", "Save File as")); dlg->setAcceptMode(QFileDialog::AcceptSave); QStringList lst; if (mHtmlMode) { diff --git a/src/job/savedraftjob.h b/src/job/savedraftjob.h --- a/src/job/savedraftjob.h +++ b/src/job/savedraftjob.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014-2019 Montel Laurent + Copyright (c) 2014-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/job/savedraftjob.cpp b/src/job/savedraftjob.cpp --- a/src/job/savedraftjob.cpp +++ b/src/job/savedraftjob.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2014-2019 Montel Laurent + Copyright (c) 2014-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by diff --git a/src/kcm_kmail.cpp b/src/kcm_kmail.cpp --- a/src/kcm_kmail.cpp +++ b/src/kcm_kmail.cpp @@ -30,7 +30,7 @@ #include "configuredialog/configureaccountpage.h" #include "configuredialog/configurepluginpage.h" #include "identity/identitypage.h" -#include +#include //---------------------------- // KCM stuff diff --git a/src/kmail_options.h b/src/kmail_options.h --- a/src/kmail_options.h +++ b/src/kmail_options.h @@ -22,7 +22,7 @@ i18n("Send BCC: to 'address'"), QStringLiteral("address")) << QCommandLineOption( - QStringList() << QStringLiteral("h") << QStringLiteral("replyTo"), + QStringList() << QStringLiteral("r") << QStringLiteral("replyTo"), i18n("Set replyTo to 'address'"), QStringLiteral("address")) << QCommandLineOption( @@ -58,6 +58,9 @@ QStringLiteral("view"), i18n("View the given message file"), QStringLiteral("url")); +#ifdef WITH_KUSERFEEDBACK + parser->addOption(QCommandLineOption(QStringLiteral("feedback"), i18n("Lists the available options for user feedback"))); +#endif parser->addOptions(options); parser->addPositionalArgument( diff --git a/src/kmail_part.cpp b/src/kmail_part.cpp --- a/src/kmail_part.cpp +++ b/src/kmail_part.cpp @@ -28,26 +28,24 @@ #include "kmmainwin.h" #include "kmmainwidget.h" -#include "kmstartup.h" -#include "aboutdata.h" #include +#include #include #include -#include +#include #include "kmail_debug.h" #include #include #include #include #include -#include "MailCommon/FolderTreeView" +#include #include "tag/tagactionmanager.h" #include "foldershortcutactionmanager.h" #include "kmmigrateapplication.h" #include - #include K_PLUGIN_FACTORY(KMailFactory, registerPlugin(); @@ -64,9 +62,6 @@ KMMigrateApplication migrate; migrate.migrate(); - // import i18n data and icons from libraries: - KMail::insertLibraryIcons(); - //local, do the init KMKernel *mKMailKernel = new KMKernel(); mKMailKernel->init(); @@ -97,6 +92,7 @@ KParts::StatusBarExtension *statusBar = new KParts::StatusBarExtension(this); statusBar->addStatusBarItem(mainWidget->vacationScriptIndicator(), 2, false); statusBar->addStatusBarItem(mainWidget->zoomLabelIndicator(), 3, false); + statusBar->addStatusBarItem(mainWidget->dkimWidgetInfo(), 4, false); setXMLFile(QStringLiteral("kmail_part.rc"), true); KSettings::Dispatcher::registerComponent(QStringLiteral("kmail2"), mKMailKernel, "slotConfigChanged"); @@ -120,27 +116,26 @@ bool KMailPart::openFile() { - mainWidget->show(); return true; } //----------------------------------------------------------------------------- void KMailPart::guiActivateEvent(KParts::GUIActivateEvent *e) { KParts::ReadOnlyPart::guiActivateEvent(e); - mainWidget->initializeFilterActions(); - mainWidget->tagActionManager()->createActions(); - mainWidget->folderShortcutActionManager()->createActions(); - mainWidget->populateMessageListStatusFilterCombo(); - mainWidget->initializePluginActions(); - /* - FIXME it doesn't work when we switch component. - const QString title = mainWidget->fullCollectionPath(); - if (!title.isEmpty()) { - Q_EMIT setWindowCaption(title); + if (e->activated()) { + mainWidget->initializeFilterActions(true); + mainWidget->tagActionManager()->createActions(); + mainWidget->folderShortcutActionManager()->createActions(); + mainWidget->populateMessageListStatusFilterCombo(); + mainWidget->initializePluginActions(); + + const QString title = mainWidget->fullCollectionPath(); + if (!title.isEmpty()) { + Q_EMIT setWindowCaption(title); + } } - */ } void KMailPart::exit() diff --git a/src/kmail_part.rc b/src/kmail_part.rc --- a/src/kmail_part.rc +++ b/src/kmail_part.rc @@ -2,7 +2,7 @@ the same menu entries at the same place in KMail and Kontact --> - + &File @@ -19,6 +19,9 @@ + + + @@ -29,8 +32,6 @@ - - @@ -287,6 +288,7 @@ + diff --git a/src/kmail_private_export.h b/src/kmail_private_export.h new file mode 100644 --- /dev/null +++ b/src/kmail_private_export.h @@ -0,0 +1,34 @@ +/* This file is part of the KDE project + Copyright (C) 2019-2020 Laurent Montel + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KMAILPRIVATE_EXPORT_H +#define KMAILPRIVATE_EXPORT_H + +#include "kmail_export.h" + +/* Classes which are exported only for unit tests */ +#ifdef BUILD_TESTING + #ifndef KMAILTESTS_TESTS_EXPORT + #define KMAILTESTS_TESTS_EXPORT KMAIL_EXPORT + # endif +#else /* not compiling tests */ + #define KMAILTESTS_TESTS_EXPORT +#endif + +#endif diff --git a/src/kmcommands.h b/src/kmcommands.h --- a/src/kmcommands.h +++ b/src/kmcommands.h @@ -3,9 +3,9 @@ #ifndef KMCommands_h #define KMCommands_h #include -#include "MessageList/View" -#include "mailcommon/searchpattern.h" -#include "messageviewer/viewer.h" +#include +#include +#include #include #include @@ -56,7 +56,7 @@ Undefined, OK, Canceled, Failed }; - // Trival constructor, don't retrieve any messages + // Trivial constructor, don't retrieve any messages explicit KMCommand(QWidget *parent = nullptr); KMCommand(QWidget *parent, const Akonadi::Item &); // Retrieve all messages in msgList when start is called. @@ -309,7 +309,7 @@ @param parent The parent widget of the command used for message boxes. @param msgs The messages of which the attachments should be saved. */ - KMSaveAttachmentsCommand(QWidget *parent, const Akonadi::Item::List &msgs); + KMSaveAttachmentsCommand(QWidget *parent, const Akonadi::Item::List &msgs, MessageViewer::Viewer *viewer); private: Result execute() override; diff --git a/src/kmcommands.cpp b/src/kmcommands.cpp --- a/src/kmcommands.cpp +++ b/src/kmcommands.cpp @@ -1,7 +1,7 @@ /* This file is part of KMail, the KDE mail client. Copyright (c) 2002 Don Sanders - Copyright (C) 2013-2019 Laurent Montel + Copyright (C) 2013-2020 Laurent Montel KMail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -318,7 +318,7 @@ // command is executed after the MousePressEvent), cf. bug #71761. if (mCountMsgs > 0) { mProgressDialog = new QProgressDialog(mParent); - mProgressDialog.data()->setWindowTitle(i18n("Please wait")); + mProgressDialog.data()->setWindowTitle(i18nc("@title:window", "Please wait")); mProgressDialog.data()->setLabelText(i18np("Please wait while the message is transferred", "Please wait while the %1 messages are transferred", mMsgList.count())); mProgressDialog.data()->setModal(true); @@ -530,23 +530,6 @@ KRecentDirs::add(recentDirClass, saveUrl.path()); } - bool fileExists = false; - if (saveUrl.isLocalFile()) { - fileExists = QFile::exists(saveUrl.toLocalFile()); - } else { - auto job = KIO::stat(saveUrl, KIO::StatJob::DestinationSide, 0); - KJobWidgets::setWindow(job, parentWidget()); - fileExists = job->exec(); - } - - if (fileExists) { - if (KMessageBox::warningContinueCancel(nullptr, - xi18nc("@info", "File %1 exists.Do you want to replace it?", - saveUrl.toDisplayString()), i18n("Save to File"), KGuiItem(i18n("&Replace"))) - != KMessageBox::Continue) { - return Canceled; - } - } KIO::Job *job = KIO::file_copy(mUrl, saveUrl, -1, KIO::Overwrite); connect(job, &KIO::Job::result, this, &KMUrlSaveCommand::slotUrlSaveResult); setEmitsCompletedItself(true); @@ -796,25 +779,43 @@ } startOfMessage += 1; // the message starts after the '\n' } + QList listMessages; + // check for multiple messages in the file bool multipleMessages = true; - int endOfMessage = mMsgString.indexOf(QLatin1String("\nFrom ")); + int endOfMessage = mMsgString.indexOf(QLatin1String("\nFrom "), startOfMessage); + while (endOfMessage != -1) { + KMime::Message *msg = new KMime::Message; + msg->setContent(KMime::CRLFtoLF(mMsgString.mid(startOfMessage, endOfMessage - startOfMessage).toUtf8())); + msg->parse(); + if (!msg->hasContent()) { + delete msg; + msg = nullptr; + doesNotContainMessage(); + return; + } + KMime::Message::Ptr mMsg(msg); + listMessages << mMsg; + startOfMessage = endOfMessage + 1; + endOfMessage = mMsgString.indexOf(QLatin1String("\nFrom "), startOfMessage); + } if (endOfMessage == -1) { endOfMessage = mMsgString.length(); multipleMessages = false; - } - KMime::Message *msg = new KMime::Message; - msg->setContent(KMime::CRLFtoLF(mMsgString.mid(startOfMessage, endOfMessage - startOfMessage).toUtf8())); - msg->parse(); - if (!msg->hasContent()) { - delete msg; - msg = nullptr; - doesNotContainMessage(); - return; + KMime::Message *msg = new KMime::Message; + msg->setContent(KMime::CRLFtoLF(mMsgString.mid(startOfMessage, endOfMessage - startOfMessage).toUtf8())); + msg->parse(); + if (!msg->hasContent()) { + delete msg; + msg = nullptr; + doesNotContainMessage(); + return; + } + KMime::Message::Ptr mMsg(msg); + listMessages << mMsg; } KMReaderMainWin *win = new KMReaderMainWin(); - KMime::Message::Ptr mMsg(msg); - win->showMessage(mEncoding, mMsg); + win->showMessage(mEncoding, listMessages); win->show(); if (multipleMessages) { KMessageBox::information(win, @@ -987,7 +988,7 @@ factory.setIdentityManager(KMKernel::self()->identityManager()); factory.setFolderIdentity(MailCommon::Util::folderIdentity(firstItem)); - QPair< KMime::Message::Ptr, QList< KMime::Content * > > fwdMsg = factory.createAttachedForward(msgList); + QPair< KMime::Message::Ptr, QVector< KMime::Content * > > fwdMsg = factory.createAttachedForward(msgList); if (!mWin) { mWin = KMail::makeComposer(fwdMsg.first, false, false, KMail::Composer::Forward, mIdentity); } @@ -1105,7 +1106,7 @@ KMCommand::Result KMPrintCommand::execute() { - KMReaderWin *printerWin = new KMReaderWin(nullptr, kmkernel->mainWin(), nullptr); + KMReaderWin *printerWin = new KMReaderWin(nullptr, parentWidget(), nullptr); printerWin->setPrinting(true); printerWin->readConfig(); printerWin->setPrintElementBackground(MessageViewer::MessageViewerSettings::self()->printBackgroundColorImages()); @@ -1278,8 +1279,8 @@ KConfigGroup tag(KMKernel::self()->config(), "MessageListView"); const QString oldTagList = tag.readEntry("TagSelected"); QStringList lst = oldTagList.split(QLatin1Char(',')); - for (const Akonadi::Tag &tag : qAsConst(mCreatedTags)) { - const QString url = tag.url().url(); + for (const Akonadi::Tag &createdTag : qAsConst(mCreatedTags)) { + const QString url = createdTag.url().url(); if (!lst.contains(url)) { lst.append(url); } @@ -1747,9 +1748,9 @@ fetchScope().fetchFullPayload(true); } -KMSaveAttachmentsCommand::KMSaveAttachmentsCommand(QWidget *parent, const Akonadi::Item::List &msgs) +KMSaveAttachmentsCommand::KMSaveAttachmentsCommand(QWidget *parent, const Akonadi::Item::List &msgs, MessageViewer::Viewer *viewer) : KMCommand(parent, msgs) - , mViewer(nullptr) + , mViewer(viewer) { fetchScope().fetchFullPayload(true); } @@ -1801,6 +1802,9 @@ KMail::Util::lastEncryptAndSignState(lastEncrypt, lastSign, msg); win->setMessage(newMsg, lastSign, lastEncrypt, false, true); + //Make sure to use current folder as requested by David + //We avoid to use an invalid folder when we open an email on two different computer. + win->setFcc(QString::number(item.parentCollection().id())); win->show(); return OK; @@ -1822,7 +1826,12 @@ KMail::Composer *win = KMail::makeComposer(msg, false, false, KMail::Composer::New, id); win->setFocusToSubject(); - win->addAttachment(mUrl, i18n("Image")); + QList infoList; + KMail::Composer::AttachmentInfo info; + info.url = mUrl; + info.comment = i18n("Image"); + infoList.append(info); + win->addAttachment(infoList, false); win->show(); return OK; } diff --git a/src/kmcomposerui.rc b/src/kmcomposerui.rc --- a/src/kmcomposerui.rc +++ b/src/kmcomposerui.rc @@ -1,5 +1,5 @@ - + &Message @@ -121,6 +121,7 @@
  • ")))); + setText(i18n("Search failed some errors were found:
    • %1
    ", lstError.join(QLatin1String("
  • ")))); } void SearchPatternWarning::showWarningPattern(const QStringList &lstError) diff --git a/src/searchdialog/searchwindow.h b/src/searchdialog/searchwindow.h --- a/src/searchdialog/searchwindow.h +++ b/src/searchdialog/searchwindow.h @@ -22,13 +22,13 @@ #ifndef KMAIL_SEARCHWINDOW_H #define KMAIL_SEARCHWINDOW_H -#include "MailCommon/SearchPattern" +#include #include "ui_searchwindow.h" #include #include #include -#include +#include #include #include @@ -90,14 +90,14 @@ * * @return The list of currently selected search result messages. */ - Akonadi::Item::List selectedMessages() const; + Q_REQUIRED_RESULT Akonadi::Item::List selectedMessages() const; /** * Provides access to the currently selected message. * * @return the currently selected message. */ - Akonadi::Item selectedMessage() const; + Q_REQUIRED_RESULT Akonadi::Item selectedMessage() const; /** * Loads a search pattern into the search window, appending its rules to the current one. diff --git a/src/searchdialog/searchwindow.cpp b/src/searchdialog/searchwindow.cpp --- a/src/searchdialog/searchwindow.cpp +++ b/src/searchdialog/searchwindow.cpp @@ -3,7 +3,7 @@ * Copyright (c) 1996-1998 Stefan Taferner * Copyright (c) 2001 Aaron J. Seigo * Copyright (c) 2010 Till Adam - * Copyright (C) 2011-2019 Laurent Montel + * Copyright (C) 2011-2020 Laurent Montel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,16 +24,17 @@ #include "searchwindow.h" #include "incompleteindexdialog.h" -#include "MailCommon/FolderRequester" +#include #include "kmcommands.h" +#include "kmkernel.h" #include "kmmainwidget.h" -#include "MailCommon/MailKernel" -#include "MailCommon/SearchPatternEdit" +#include +#include #include "searchdescriptionattribute.h" -#include "MailCommon/FolderTreeView" +#include #include "kmsearchmessagemodel.h" #include "searchpatternwarning.h" -#include "PimCommonAkonadi/SelectMultiCollectionDialog" +#include #include #include @@ -50,11 +51,11 @@ #include "kmail_debug.h" #include #include -#include +#include +#include #include #include #include -#include #include #include @@ -77,12 +78,7 @@ : QDialog(nullptr) , mKMMainWidget(widget) { - setWindowTitle(i18n("Find Messages")); - - KWindowSystem::setIcons(winId(), qApp->windowIcon().pixmap(IconSize(KIconLoader::Desktop), - IconSize(KIconLoader::Desktop)), - qApp->windowIcon().pixmap(IconSize(KIconLoader::Small), - IconSize(KIconLoader::Small))); + setWindowTitle(i18nc("@title:window", "Find Messages")); QVBoxLayout *mainLayout = new QVBoxLayout(this); @@ -133,9 +129,9 @@ mUi.mLbxMatches->setSortingEnabled(true); connect(mUi.mLbxMatches, &Akonadi::EntityTreeView::customContextMenuRequested, this, &SearchWindow::slotContextMenuRequested); - connect(mUi.mLbxMatches, QOverload::of(&Akonadi::EntityTreeView::doubleClicked), + connect(mUi.mLbxMatches, qOverload(&Akonadi::EntityTreeView::doubleClicked), this, &SearchWindow::slotViewMsg); - connect(mUi.mLbxMatches, QOverload::of(&Akonadi::EntityTreeView::currentChanged), + connect(mUi.mLbxMatches, qOverload(&Akonadi::EntityTreeView::currentChanged), this, &SearchWindow::slotCurrentChanged); connect(mUi.selectMultipleFolders, &QPushButton::clicked, this, &SearchWindow::slotSelectMultipleFolders); @@ -227,6 +223,7 @@ for (QAction *action : actList) { action->setShortcutContext(Qt::WidgetWithChildrenShortcut); } + mUi.mProgressIndicator->hide(); } SearchWindow::~SearchWindow() @@ -262,8 +259,11 @@ if (mResultModel) { mResultModel->deleteLater(); } - mResultModel = new KMSearchMessageModel(this); - mResultModel->setCollection(mFolder); + auto monitor = new Akonadi::Monitor(); + monitor->setCollectionMonitored(mFolder); + mResultModel = new KMSearchMessageModel(monitor, this); + mResultModel->setCollectionMonitored(mFolder); + monitor->setParent(mResultModel); QSortFilterProxyModel *sortproxy = new QSortFilterProxyModel(mResultModel); sortproxy->setDynamicSortFilter(true); sortproxy->setSortRole(Qt::EditRole); @@ -523,7 +523,7 @@ } connect(mSearchJob, &Akonadi::CollectionModifyJob::result, this, &SearchWindow::searchDone); - mUi.mProgressIndicator->start(); + mUi.mProgressIndicator->show(); enableGUI(); mUi.mStatusLbl->setText(i18n("Searching...")); } @@ -534,7 +534,7 @@ mSearchJob = nullptr; QMetaObject::invokeMethod(this, &SearchWindow::enableGUI, Qt::QueuedConnection); - mUi.mProgressIndicator->stop(); + mUi.mProgressIndicator->hide(); if (job->error()) { qCDebug(KMAIL_LOG) << job->errorString(); KMessageBox::sorry(this, i18n("Cannot get search result. %1", job->errorString())); @@ -614,7 +614,7 @@ void SearchWindow::slotStop() { - mUi.mProgressIndicator->stop(); + mUi.mProgressIndicator->hide(); if (mSearchJob) { mSearchJob->kill(KJob::Quietly); mSearchJob->deleteLater(); @@ -730,7 +730,7 @@ const QModelIndexList lst = mUi.mLbxMatches->selectionModel()->selectedRows(); for (const QModelIndex &index : lst) { - const Akonadi::Item item = index.data(Akonadi::ItemModel::ItemRole).value(); + const Akonadi::Item item = index.data(Akonadi::EntityTreeModel::ItemRole).value(); if (item.isValid()) { messages.append(item); } @@ -741,7 +741,7 @@ Akonadi::Item SearchWindow::selectedMessage() const { - return mUi.mLbxMatches->currentIndex().data(Akonadi::ItemModel::ItemRole).value(); + return mUi.mLbxMatches->currentIndex().data(Akonadi::EntityTreeModel::ItemRole).value(); } void SearchWindow::updateContextMenuActions() @@ -838,7 +838,7 @@ void SearchWindow::slotSaveAttachments() { - KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand(this, selectedMessages()); + KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand(this, selectedMessages(), nullptr); saveCommand->start(); } @@ -909,7 +909,7 @@ } enableGUI(); - mUi.mProgressIndicator->start(); + mUi.mProgressIndicator->hide(); mUi.mStatusLbl->setText(i18n("Checking index status...")); //Fetch collection ? for (const Akonadi::Collection &col : qAsConst(cols)) { diff --git a/src/settings/kmail.kcfg.cmake b/src/settings/kmail.kcfg.cmake --- a/src/settings/kmail.kcfg.cmake +++ b/src/settings/kmail.kcfg.cmake @@ -140,6 +140,14 @@ + + + true + + + + + true @@ -422,4 +430,13 @@ 100 + + + + false + + + 10 + + diff --git a/src/sieveimapinterface/kmailsieveimapinstanceinterface.h b/src/sieveimapinterface/kmailsieveimapinstanceinterface.h --- a/src/sieveimapinterface/kmailsieveimapinstanceinterface.h +++ b/src/sieveimapinterface/kmailsieveimapinstanceinterface.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Montel Laurent + Copyright (C) 2017-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -28,7 +28,7 @@ KMailSieveImapInstanceInterface(); ~KMailSieveImapInstanceInterface() override = default; - QVector sieveImapInstances() override; + Q_REQUIRED_RESULT QVector sieveImapInstances() override; private: Q_DISABLE_COPY(KMailSieveImapInstanceInterface) }; diff --git a/src/sieveimapinterface/kmailsieveimapinstanceinterface.cpp b/src/sieveimapinterface/kmailsieveimapinstanceinterface.cpp --- a/src/sieveimapinterface/kmailsieveimapinstanceinterface.cpp +++ b/src/sieveimapinterface/kmailsieveimapinstanceinterface.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Montel Laurent + Copyright (C) 2017-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/sieveimapinterface/kmsieveimappasswordprovider.h b/src/sieveimapinterface/kmsieveimappasswordprovider.h --- a/src/sieveimapinterface/kmsieveimappasswordprovider.h +++ b/src/sieveimapinterface/kmsieveimappasswordprovider.h @@ -20,20 +20,20 @@ #ifndef KMSIEVEIMAPPASSWORDPROVIDER_H #define KMSIEVEIMAPPASSWORDPROVIDER_H -#include +#include #include // for WId class KMSieveImapPasswordProvider : public KSieveUi::SieveImapPasswordProvider { public: KMSieveImapPasswordProvider(WId wid); - QString password(const QString &identifier) override; - QString sieveCustomPassword(const QString &identifier) override; + Q_REQUIRED_RESULT QString password(const QString &identifier) override; + Q_REQUIRED_RESULT QString sieveCustomPassword(const QString &identifier) override; private: - QString walletPassword(const QString &identifier); + Q_REQUIRED_RESULT QString walletPassword(const QString &identifier); WId m_wid; }; diff --git a/src/sieveimapinterface/kmsieveimappasswordprovider.cpp b/src/sieveimapinterface/kmsieveimappasswordprovider.cpp --- a/src/sieveimapinterface/kmsieveimappasswordprovider.cpp +++ b/src/sieveimapinterface/kmsieveimappasswordprovider.cpp @@ -19,7 +19,7 @@ #include "kmsieveimappasswordprovider.h" -#include +#include #include diff --git a/src/sieveimapinterface/tests/vacation/main.cpp b/src/sieveimapinterface/tests/vacation/main.cpp --- a/src/sieveimapinterface/tests/vacation/main.cpp +++ b/src/sieveimapinterface/tests/vacation/main.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2013-2019 Montel Laurent + Copyright (c) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -15,7 +15,6 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include #include #include #include diff --git a/src/tag/tagactionmanager.h b/src/tag/tagactionmanager.h --- a/src/tag/tagactionmanager.h +++ b/src/tag/tagactionmanager.h @@ -1,6 +1,6 @@ /* Copyright 2010 Thomas McGuire - Copyright 2011-2019 Laurent Montel + Copyright 2011-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -24,7 +24,7 @@ #include "kmail_export.h" #include "mailcommon/tag.h" #include - +#include class KJob; class KActionCollection; class KXMLGUIClient; @@ -112,7 +112,7 @@ void fillTagList(); void createTagAction(const MailCommon::Tag::Ptr &tag, bool addToMenu); - void createTagActions(const QList &); + void createTagActions(const QVector &); void checkTags(const QList &tags); QList checkedTags() const; @@ -132,7 +132,7 @@ QList mToolbarActions; // A sorted list of all tags - QList mTags; + QVector mTags; // Uri of a newly created tag qint64 mNewTagId = -1; diff --git a/src/tag/tagactionmanager.cpp b/src/tag/tagactionmanager.cpp --- a/src/tag/tagactionmanager.cpp +++ b/src/tag/tagactionmanager.cpp @@ -1,6 +1,6 @@ /* Copyright 2010 Thomas McGuire - Copyright 2011-2019 Laurent Montel + Copyright 2011-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -22,7 +22,7 @@ #include "messageactions.h" -#include "MailCommon/AddTagDialog" +#include #include #include @@ -173,7 +173,7 @@ Q_EMIT tagActionTriggered(Akonadi::Tag(tag.toLongLong())); } -void TagActionManager::createTagActions(const QList &tags) +void TagActionManager::createTagActions(const QVector &tags) { clearActions(); @@ -204,7 +204,7 @@ mMessageActions->messageStatusMenu()->menu()->addAction(mSeparatorNewTagAction); if (!mNewTagAction) { - mNewTagAction = new QAction(i18n("Add new tag..."), this); + mNewTagAction = new QAction(QIcon::fromTheme(QStringLiteral("tag-new")), i18n("Add new tag..."), this); connect(mNewTagAction, &QAction::triggered, this, &TagActionManager::newTagActionClicked); } mMessageActions->messageStatusMenu()->menu()->addAction(mNewTagAction); diff --git a/src/tag/tagselectdialog.h b/src/tag/tagselectdialog.h --- a/src/tag/tagselectdialog.h +++ b/src/tag/tagselectdialog.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2011-2019 Montel Laurent + Copyright (C) 2011-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -21,6 +21,7 @@ #define TAGSELECTDIALOG_H #include +#include #include #include #include "MailCommon/Tag" @@ -33,7 +34,7 @@ public: explicit TagSelectDialog(QWidget *parent, int numberOfSelectedMessages, const Akonadi::Item &selectedItem); ~TagSelectDialog(); - Akonadi::Tag::List selectedTag() const; + Q_REQUIRED_RESULT Akonadi::Tag::List selectedTag() const; void setActionCollection(const QList &actionCollectionList); @@ -50,7 +51,7 @@ Akonadi::Item mSelectedItem; Akonadi::Tag::List mCurrentSelectedTags; - QList mTagList; + QVector mTagList; QList mActionCollectionList; QListWidget *mListTag = nullptr; }; diff --git a/src/tag/tagselectdialog.cpp b/src/tag/tagselectdialog.cpp --- a/src/tag/tagselectdialog.cpp +++ b/src/tag/tagselectdialog.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2011-2019 Montel Laurent + Copyright (C) 2011-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -46,7 +46,7 @@ , mNumberOfSelectedMessages(numberOfSelectedMessages) , mSelectedItem(selectedItem) { - setWindowTitle(i18n("Select Tags")); + setWindowTitle(i18nc("@title:window", "Select Tags")); QVBoxLayout *mainLayout = new QVBoxLayout(this); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); @@ -66,6 +66,7 @@ QVBoxLayout *vbox = new QVBoxLayout; mainWidget->setLayout(vbox); + vbox->setContentsMargins(0, 0, 0, 0); mListTag = new QListWidget(this); mListTag->setObjectName(QStringLiteral("listtag")); KListWidgetSearchLine *listWidgetSearchLine = new KListWidgetSearchLine(this, mListTag); diff --git a/src/tests/ktoolinvocationtest.cpp b/src/tests/ktoolinvocationtest.cpp --- a/src/tests/ktoolinvocationtest.cpp +++ b/src/tests/ktoolinvocationtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2016-2019 Montel Laurent + Copyright (C) 2016-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/tests/searchdbustest.h b/src/tests/searchdbustest.h --- a/src/tests/searchdbustest.h +++ b/src/tests/searchdbustest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2016-2019 Montel Laurent + Copyright (C) 2016-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/tests/searchdbustest.cpp b/src/tests/searchdbustest.cpp --- a/src/tests/searchdbustest.cpp +++ b/src/tests/searchdbustest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2016-2019 Montel Laurent + Copyright (C) 2016-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/tests/searchmailertest.cpp b/src/tests/searchmailertest.cpp --- a/src/tests/searchmailertest.cpp +++ b/src/tests/searchmailertest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Montel Laurent + Copyright (C) 2017-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/ui/miscpagemaintab.ui b/src/ui/miscpagemaintab.ui --- a/src/ui/miscpagemaintab.ui +++ b/src/ui/miscpagemaintab.ui @@ -40,15 +40,15 @@ - + 0 0 - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "https://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> @@ -98,7 +98,7 @@ - + Jump to First Unread Message @@ -198,13 +198,6 @@ - - - KComboBox - QComboBox -
    kcombobox.h
    -
    -
    diff --git a/src/ui/searchwindow.ui b/src/ui/searchwindow.ui --- a/src/ui/searchwindow.ui +++ b/src/ui/searchwindow.ui @@ -156,7 +156,7 @@ - + @@ -200,9 +200,9 @@ 1 - KPIM::ProgressIndicatorWidget - QLabel -
    Libkdepim/ProgressIndicatorWidget
    + KBusyIndicatorWidget + QWidget +
    KBusyIndicatorWidget
    1
    diff --git a/src/ui/securitypagegeneraltab.ui b/src/ui/securitypagegeneraltab.ui --- a/src/ui/securitypagegeneraltab.ui +++ b/src/ui/securitypagegeneraltab.ui @@ -164,7 +164,7 @@ - Check Mail Url Tracking + Scan emails for tracking URLs diff --git a/src/undosend/autotests/CMakeLists.txt b/src/undosend/autotests/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/src/undosend/autotests/CMakeLists.txt @@ -0,0 +1,10 @@ +macro(add_kmail_undosend_unittest _source) + get_filename_component(_name ${_source} NAME_WE) + ecm_add_test(${_source} + TEST_NAME ${_name} + LINK_LIBRARIES kmailprivate Qt5::Test Qt5::Widgets QGpgme + ) +endmacro () + +add_kmail_undosend_unittest(undosendcomboboxtest.cpp) +add_kmail_undosend_unittest(undosendcreatejobtest.cpp) diff --git a/agents/mailfilteragent/autotests/configurewidgettest.h b/src/undosend/autotests/undosendcomboboxtest.h rename from agents/mailfilteragent/autotests/configurewidgettest.h rename to src/undosend/autotests/undosendcomboboxtest.h --- a/agents/mailfilteragent/autotests/configurewidgettest.h +++ b/src/undosend/autotests/undosendcomboboxtest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -16,17 +16,20 @@ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef CONFIGUREWIDGETTEST_H -#define CONFIGUREWIDGETTEST_H + +#ifndef UNDOSENDCOMBOBOXTEST_H +#define UNDOSENDCOMBOBOXTEST_H #include -class ConfigureWidgetTest : public QObject +class UndoSendComboboxTest : public QObject { Q_OBJECT public: - explicit ConfigureWidgetTest(QObject *parent = nullptr); - ~ConfigureWidgetTest(); + explicit UndoSendComboboxTest(QObject *parent = nullptr); + ~UndoSendComboboxTest() = default; +private Q_SLOTS: + void shouldHaveDefaultValues(); }; -#endif // CONFIGUREWIDGETTEST_H +#endif // UNDOSENDCOMBOBOXTEST_H diff --git a/agents/mailfilteragent/autotests/configurewidgettest.cpp b/src/undosend/autotests/undosendcomboboxtest.cpp rename from agents/mailfilteragent/autotests/configurewidgettest.cpp rename to src/undosend/autotests/undosendcomboboxtest.cpp --- a/agents/mailfilteragent/autotests/configurewidgettest.cpp +++ b/src/undosend/autotests/undosendcomboboxtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -16,16 +16,19 @@ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "configurewidgettest.h" + +#include "undosendcomboboxtest.h" +#include "undosend/undosendcombobox.h" #include +QTEST_MAIN(UndoSendComboboxTest) -ConfigureWidgetTest::ConfigureWidgetTest(QObject *parent) +UndoSendComboboxTest::UndoSendComboboxTest(QObject *parent) : QObject(parent) { } -ConfigureWidgetTest::~ConfigureWidgetTest() +void UndoSendComboboxTest::shouldHaveDefaultValues() { + UndoSendCombobox w; + QCOMPARE(w.count(), 5); } - -QTEST_MAIN(ConfigureWidgetTest) diff --git a/agents/archivemailagent/autotests/archivemailwidgettest.h b/src/undosend/autotests/undosendcreatejobtest.h copy from agents/archivemailagent/autotests/archivemailwidgettest.h copy to src/undosend/autotests/undosendcreatejobtest.h --- a/agents/archivemailagent/autotests/archivemailwidgettest.h +++ b/src/undosend/autotests/undosendcreatejobtest.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,20 +17,19 @@ Boston, MA 02110-1301, USA. */ -#ifndef ARCHIVEMAILWIDGETTEST_H -#define ARCHIVEMAILWIDGETTEST_H +#ifndef UNDOSENDCREATEJOBTEST_H +#define UNDOSENDCREATEJOBTEST_H #include -class ArchiveMailWidgetTest : public QObject +class UndoSendCreateJobTest : public QObject { Q_OBJECT public: - explicit ArchiveMailWidgetTest(QObject *parent = nullptr); - ~ArchiveMailWidgetTest(); - + explicit UndoSendCreateJobTest(QObject *parent = nullptr); + ~UndoSendCreateJobTest() = default; private Q_SLOTS: - void shouldHaveDefaultValue(); + void shouldHaveDefaultValues(); }; -#endif // ARCHIVEMAILWIDGETTEST_H +#endif // UNDOSENDCREATEJOBTEST_H diff --git a/agents/mailfilteragent/config/configurewidget.cpp b/src/undosend/autotests/undosendcreatejobtest.cpp rename from agents/mailfilteragent/config/configurewidget.cpp rename to src/undosend/autotests/undosendcreatejobtest.cpp --- a/agents/mailfilteragent/config/configurewidget.cpp +++ b/src/undosend/autotests/undosendcreatejobtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,13 +17,20 @@ Boston, MA 02110-1301, USA. */ -#include "configurewidget.h" +#include "undosendcreatejobtest.h" +#include "undosend/undosendcreatejob.h" +#include +QTEST_MAIN(UndoSendCreateJobTest) -ConfigureWidget::ConfigureWidget(QWidget *parent) - : QWidget(parent) +UndoSendCreateJobTest::UndoSendCreateJobTest(QObject *parent) + : QObject(parent) { } -ConfigureWidget::~ConfigureWidget() +void UndoSendCreateJobTest::shouldHaveDefaultValues() { + UndoSendCreateJob job; + QCOMPARE(job.akonadiIndex(), -1); + QCOMPARE(job.delay(), -1); + QVERIFY(job.subject().isEmpty()); } diff --git a/agents/archivemailagent/widgets/formatcombobox.h b/src/undosend/undosendcombobox.h copy from agents/archivemailagent/widgets/formatcombobox.h copy to src/undosend/undosendcombobox.h --- a/agents/archivemailagent/widgets/formatcombobox.h +++ b/src/undosend/undosendcombobox.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,21 +17,23 @@ Boston, MA 02110-1301, USA. */ -#ifndef FORMATCOMBOBOX_H -#define FORMATCOMBOBOX_H -#include "MailCommon/BackupJob" +#ifndef UNDOSENDCOMBOBOX_H +#define UNDOSENDCOMBOBOX_H #include +#include "kmail_private_export.h" -class FormatComboBox : public QComboBox +class KMAILTESTS_TESTS_EXPORT UndoSendCombobox : public QComboBox { Q_OBJECT public: - explicit FormatComboBox(QWidget *parent = nullptr); - ~FormatComboBox(); + explicit UndoSendCombobox(QWidget *parent = nullptr); + ~UndoSendCombobox(); - MailCommon::BackupJob::ArchiveType format() const; - void setFormat(MailCommon::BackupJob::ArchiveType type); + Q_REQUIRED_RESULT int delay() const; + void setDelay(int val); +private: + void initialize(); }; -#endif // FORMATCOMBOBOX_H +#endif // UNDOSENDCOMBOBOX_H diff --git a/src/editor/warningwidgets/externaleditorwarning.cpp b/src/undosend/undosendcombobox.cpp copy from src/editor/warningwidgets/externaleditorwarning.cpp copy to src/undosend/undosendcombobox.cpp --- a/src/editor/warningwidgets/externaleditorwarning.cpp +++ b/src/undosend/undosendcombobox.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,20 +17,34 @@ Boston, MA 02110-1301, USA. */ -#include "externaleditorwarning.h" - +#include "undosendcombobox.h" #include -ExternalEditorWarning::ExternalEditorWarning(QWidget *parent) - : KMessageWidget(parent) +UndoSendCombobox::UndoSendCombobox(QWidget *parent) + : QComboBox(parent) +{ + initialize(); +} + +UndoSendCombobox::~UndoSendCombobox() +{ +} + +void UndoSendCombobox::initialize() +{ + for (int i = 1; i < 6; i++) { + const int numberOfSeconds = i * 10; + addItem(i18n("%1 seconds", numberOfSeconds), numberOfSeconds); + } +} + +int UndoSendCombobox::delay() const { - setVisible(false); - setCloseButtonVisible(false); - setMessageType(Information); - setText(i18n("External editor was started.")); - setWordWrap(true); + return currentData().toInt(); } -ExternalEditorWarning::~ExternalEditorWarning() +void UndoSendCombobox::setDelay(int val) { + const int index = findData(val); + setCurrentIndex(index != -1 ? index : 0); } diff --git a/src/undosend/undosendcreatejob.h b/src/undosend/undosendcreatejob.h new file mode 100644 --- /dev/null +++ b/src/undosend/undosendcreatejob.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2019-2020 Laurent Montel + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef UNDOSENDCREATEJOB_H +#define UNDOSENDCREATEJOB_H + +#include +#include "kmail_private_export.h" +class KNotification; +class QTimer; +class KMAILTESTS_TESTS_EXPORT UndoSendCreateJob : public QObject +{ + Q_OBJECT +public: + explicit UndoSendCreateJob(QObject *parent = nullptr); + ~UndoSendCreateJob(); + Q_REQUIRED_RESULT bool canStart() const; + Q_REQUIRED_RESULT bool start(); + + Q_REQUIRED_RESULT QString subject() const; + void setSubject(const QString &subject); + + Q_REQUIRED_RESULT int delay() const; + void setDelay(int delay); + + Q_REQUIRED_RESULT qint64 akonadiIndex() const; + void setAkonadiIndex(qint64 akonadiIndex); + +private: + void slotActivateNotificationAction(unsigned int index); + void slotNotificationClosed(); + void undoSendEmail(); + void slotTimeOut(); + QString mSubject; + KNotification *mNotification = nullptr; + QTimer *mTimer = nullptr; + qint64 mAkonadiIndex = -1; + int mDelay = -1; +}; + +#endif // UNDOSENDCREATEJOB_H diff --git a/src/undosend/undosendcreatejob.cpp b/src/undosend/undosendcreatejob.cpp new file mode 100644 --- /dev/null +++ b/src/undosend/undosendcreatejob.cpp @@ -0,0 +1,127 @@ +/* + Copyright (C) 2019-2020 Laurent Montel + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "undosendcreatejob.h" +#include "kmail_debug.h" + +#include + +#include +#include +#include + +UndoSendCreateJob::UndoSendCreateJob(QObject *parent) + : QObject(parent) +{ +} + +UndoSendCreateJob::~UndoSendCreateJob() +{ +} + +bool UndoSendCreateJob::canStart() const +{ + if (mAkonadiIndex < 0 || mDelay <= 0) { + return false; + } + return true; +} + +bool UndoSendCreateJob::start() +{ + if (!canStart()) { + qCWarning(KMAIL_LOG) << "Impossible to start undosendcreatejob"; + deleteLater(); + return false; + } + mTimer = new QTimer(this); + connect(mTimer, &QTimer::timeout, this, &UndoSendCreateJob::slotTimeOut); + mTimer->setSingleShot(true); + mTimer->start(mDelay * 1000); + mNotification = new KNotification(QStringLiteral("undosend"), nullptr, + KNotification::Persistent); + mNotification->setText(mSubject); + mNotification->setActions(QStringList() << i18n("Undo send")); + + connect(mNotification, QOverload::of(&KNotification::activated), this, &UndoSendCreateJob::slotActivateNotificationAction); + connect(mNotification, &KNotification::closed, this, &UndoSendCreateJob::slotNotificationClosed); + mNotification->sendEvent(); + + return true; +} + +void UndoSendCreateJob::slotTimeOut() +{ + mNotification->close(); + deleteLater(); +} + +void UndoSendCreateJob::slotNotificationClosed() +{ + mTimer->stop(); + deleteLater(); +} + +void UndoSendCreateJob::slotActivateNotificationAction(unsigned int index) +{ + //Index == 0 => is the default action. We don't have it. + switch (index) { + case 1: + undoSendEmail(); + return; + } + qCWarning(KMAIL_LOG) << " SpecialNotifierJob::slotActivateNotificationAction unknown index " << index; +} + +void UndoSendCreateJob::undoSendEmail() +{ + mTimer->stop(); + auto job = new MessageComposer::SendLaterRemoveJob(mAkonadiIndex, this); + job->start(); +} + +QString UndoSendCreateJob::subject() const +{ + return mSubject; +} + +void UndoSendCreateJob::setSubject(const QString &subject) +{ + mSubject = subject; +} + +int UndoSendCreateJob::delay() const +{ + return mDelay; +} + +void UndoSendCreateJob::setDelay(int delay) +{ + mDelay = delay; +} + +qint64 UndoSendCreateJob::akonadiIndex() const +{ + return mAkonadiIndex; +} + +void UndoSendCreateJob::setAkonadiIndex(qint64 akonadiIndex) +{ + mAkonadiIndex = akonadiIndex; +} diff --git a/agents/archivemailagent/autotests/archivemailwidgettest.h b/src/undosend/undosendmanager.h copy from agents/archivemailagent/autotests/archivemailwidgettest.h copy to src/undosend/undosendmanager.h --- a/agents/archivemailagent/autotests/archivemailwidgettest.h +++ b/src/undosend/undosendmanager.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,20 +17,20 @@ Boston, MA 02110-1301, USA. */ -#ifndef ARCHIVEMAILWIDGETTEST_H -#define ARCHIVEMAILWIDGETTEST_H +#ifndef UNDOSENDMANAGER_H +#define UNDOSENDMANAGER_H #include -class ArchiveMailWidgetTest : public QObject +class UndoSendManager : public QObject { Q_OBJECT public: - explicit ArchiveMailWidgetTest(QObject *parent = nullptr); - ~ArchiveMailWidgetTest(); + explicit UndoSendManager(QObject *parent = nullptr); + ~UndoSendManager(); + static UndoSendManager *self(); -private Q_SLOTS: - void shouldHaveDefaultValue(); + void addItem(qint64 index, const QString &subject, int delay); }; -#endif // ARCHIVEMAILWIDGETTEST_H +#endif // UNDOSENDMANAGER_H diff --git a/agents/mailfilteragent/autotests/configurewidgettest.cpp b/src/undosend/undosendmanager.cpp rename from agents/mailfilteragent/autotests/configurewidgettest.cpp rename to src/undosend/undosendmanager.cpp --- a/agents/mailfilteragent/autotests/configurewidgettest.cpp +++ b/src/undosend/undosendmanager.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2019-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -16,16 +16,33 @@ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "configurewidgettest.h" -#include -ConfigureWidgetTest::ConfigureWidgetTest(QObject *parent) +#include "undosendmanager.h" +#include "undosendcreatejob.h" +#include "kmail_debug.h" + +UndoSendManager::UndoSendManager(QObject *parent) : QObject(parent) { } -ConfigureWidgetTest::~ConfigureWidgetTest() +UndoSendManager::~UndoSendManager() +{ +} + +UndoSendManager *UndoSendManager::self() { + static UndoSendManager s_self; + return &s_self; } -QTEST_MAIN(ConfigureWidgetTest) +void UndoSendManager::addItem(qint64 index, const QString &subject, int delay) +{ + UndoSendCreateJob *job = new UndoSendCreateJob(this); + job->setAkonadiIndex(index); + job->setSubject(subject); + job->setDelay(delay); + if (!job->start()) { + qCWarning(KMAIL_LOG) << " Impossible to create job"; + } +} diff --git a/src/undostack.h b/src/undostack.h --- a/src/undostack.h +++ b/src/undostack.h @@ -53,16 +53,16 @@ ~UndoStack(); void clear(); - int size() const; - int newUndoAction(const Akonadi::Collection &srcFolder, const Akonadi::Collection &destFolder); + Q_REQUIRED_RESULT int size() const; + Q_REQUIRED_RESULT int newUndoAction(const Akonadi::Collection &srcFolder, const Akonadi::Collection &destFolder); void addMsgToAction(int undoId, const Akonadi::Item &item); - bool isEmpty() const; + Q_REQUIRED_RESULT bool isEmpty() const; void undo(); void pushSingleAction(const Akonadi::Item &item, const Akonadi::Collection &, const Akonadi::Collection &destFolder); void folderDestroyed(const Akonadi::Collection &folder); - QString undoInfo() const; + Q_REQUIRED_RESULT QString undoInfo() const; Q_SIGNALS: void undoStackChanged(); diff --git a/src/undostack.cpp b/src/undostack.cpp --- a/src/undostack.cpp +++ b/src/undostack.cpp @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include "kmail_debug.h" diff --git a/src/unityservicemanager.h b/src/unityservicemanager.h --- a/src/unityservicemanager.h +++ b/src/unityservicemanager.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2018-2019 Montel Laurent + Copyright (C) 2018-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -35,20 +35,20 @@ ~UnityServiceManager(); void updateSystemTray(); - bool haveSystemTrayApplet() const; + Q_REQUIRED_RESULT bool haveSystemTrayApplet() const; - bool canQueryClose(); + Q_REQUIRED_RESULT bool canQueryClose(); void toggleSystemTray(QWidget *parent); void initListOfCollection(); - bool excludeFolder(const Akonadi::Collection &collection) const; - bool ignoreNewMailInFolder(const Akonadi::Collection &collection); + Q_REQUIRED_RESULT bool excludeFolder(const Akonadi::Collection &collection) const; + Q_REQUIRED_RESULT bool ignoreNewMailInFolder(const Akonadi::Collection &collection); void updateCount(); private: Q_DISABLE_COPY(UnityServiceManager) void unreadMail(const QAbstractItemModel *model, const QModelIndex &parentIndex = {}); void slotCollectionStatisticsChanged(Akonadi::Collection::Id id, const Akonadi::CollectionStatistics &); void initUnity(); - bool hasUnreadMail() const; + Q_REQUIRED_RESULT bool hasUnreadMail() const; QDBusServiceWatcher *mUnityServiceWatcher = nullptr; KMail::KMSystemTray *mSystemTray = nullptr; int mCount = 0; diff --git a/src/unityservicemanager.cpp b/src/unityservicemanager.cpp --- a/src/unityservicemanager.cpp +++ b/src/unityservicemanager.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2018-2019 Montel Laurent + Copyright (C) 2018-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -38,7 +38,7 @@ #include #include #include -#include +#include using namespace KMail; @@ -97,7 +97,7 @@ } } } - if (model->rowCount(index) > 0) { + if (model->hasChildren(index)) { unreadMail(model, index); } } diff --git a/agents/archivemailagent/autotests/archivemailinfotest.h b/src/userfeedback/accountinfosource.h copy from agents/archivemailagent/autotests/archivemailinfotest.h copy to src/userfeedback/accountinfosource.h --- a/agents/archivemailagent/autotests/archivemailinfotest.h +++ b/src/userfeedback/accountinfosource.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,22 +17,20 @@ Boston, MA 02110-1301, USA. */ -#ifndef ARCHIVEMAILINFOTEST_H -#define ARCHIVEMAILINFOTEST_H +#ifndef ACCOUNTINFOSOURCE_H +#define ACCOUNTINFOSOURCE_H +#include +#include "kmail_private_export.h" -#include - -class ArchiveMailInfoTest : public QObject +class KMAILTESTS_TESTS_EXPORT AccountInfoSource : public KUserFeedback::AbstractDataSource { - Q_OBJECT public: - explicit ArchiveMailInfoTest(QObject *parent = nullptr); - ~ArchiveMailInfoTest(); + AccountInfoSource(); + + Q_REQUIRED_RESULT QString name() const override; + Q_REQUIRED_RESULT QString description() const override; -private Q_SLOTS: - void shouldHaveDefaultValue(); - void shouldCopyArchiveInfo(); - void shouldRestoreFromSettings(); + Q_REQUIRED_RESULT QVariant data() override; }; -#endif // ARCHIVEMAILINFOTEST_H +#endif // ACCOUNTINFOSOURCE_H diff --git a/src/userfeedback/accountinfosource.cpp b/src/userfeedback/accountinfosource.cpp new file mode 100644 --- /dev/null +++ b/src/userfeedback/accountinfosource.cpp @@ -0,0 +1,105 @@ +/* + Copyright (C) 2020 Laurent Montel + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "accountinfosource.h" +#include +#include +#include +#include +#include +#include + +AccountInfoSource::AccountInfoSource() + : KUserFeedback::AbstractDataSource(QStringLiteral("accounts"), KUserFeedback::Provider::DetailedSystemInformation) +{ +} + +QString AccountInfoSource::name() const +{ + return i18n("Account information"); +} + +QString AccountInfoSource::description() const +{ + return i18n("Account configured in KMail (receiver and sender)."); +} + +QVariant AccountInfoSource::data() +{ + const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances(); + int numberOfImap = 0; + int numberOfPop3 = 0; + int numberOfKolab = 0; + int numberOfEws = 0; + int numberOfMaildir = 0; + for (const Akonadi::AgentInstance &type : lst) { + const QString identifier = type.identifier(); + if (identifier.startsWith(QLatin1String("akonadi_pop3_resource"))) { + numberOfPop3++; + } else if (identifier.startsWith(QLatin1String("akonadi_imap_resource"))) { + numberOfImap++; + } else if (identifier.startsWith(QLatin1String("akonadi_kolab_resource"))) { + numberOfKolab++; + } else if (identifier.startsWith(QLatin1String("akonadi_ews_resource"))) { + numberOfEws++; + } else if (identifier.startsWith(QLatin1String("akonadi_maildir_resource"))) { + numberOfMaildir++; + } + //TODO add more + } + QVariantList l; + if (numberOfImap > 0) { + QVariantMap m; + m.insert(QStringLiteral("name"), QStringLiteral("imap")); + m.insert(QStringLiteral("number"), numberOfImap); + l.push_back(m); + } + if (numberOfPop3 > 0) { + QVariantMap m; + m.insert(QStringLiteral("name"), QStringLiteral("pop3")); + m.insert(QStringLiteral("number"), numberOfPop3); + l.push_back(m); + } + if (numberOfKolab > 0) { + QVariantMap m; + m.insert(QStringLiteral("name"), QStringLiteral("kolab")); + m.insert(QStringLiteral("number"), numberOfKolab); + l.push_back(m); + } + if (numberOfEws > 0) { + QVariantMap m; + m.insert(QStringLiteral("name"), QStringLiteral("ews")); + m.insert(QStringLiteral("number"), numberOfEws); + l.push_back(m); + } + if (numberOfMaildir > 0) { + QVariantMap m; + m.insert(QStringLiteral("name"), QStringLiteral("maildir")); + m.insert(QStringLiteral("number"), numberOfMaildir); + l.push_back(m); + } + + //Mail Transport + QVariantMap m; + m.insert(QStringLiteral("name"), QStringLiteral("sender")); + m.insert(QStringLiteral("number"), MailTransport::TransportManager::self()->transports().count()); + l.push_back(m); + + return l; +} diff --git a/src/editor/warningwidgets/autotests/externaleditorwarningtest.h b/src/userfeedback/kmailuserfeedbackprovider.h copy from src/editor/warningwidgets/autotests/externaleditorwarningtest.h copy to src/userfeedback/kmailuserfeedbackprovider.h --- a/src/editor/warningwidgets/autotests/externaleditorwarningtest.h +++ b/src/userfeedback/kmailuserfeedbackprovider.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2019 Montel Laurent + Copyright (C) 2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,19 +17,18 @@ Boston, MA 02110-1301, USA. */ -#ifndef EXTERNALEDITORWARNINGTEST_H -#define EXTERNALEDITORWARNINGTEST_H +#ifndef KMAILUSERFEEDBACKPROVIDER_H +#define KMAILUSERFEEDBACKPROVIDER_H -#include +#include +#include "kmail_export.h" -class ExternalEditorWarningTest : public QObject +class KMAIL_EXPORT KMailUserFeedbackProvider : public KUserFeedback::Provider { Q_OBJECT public: - explicit ExternalEditorWarningTest(QObject *parent = nullptr); - ~ExternalEditorWarningTest() = default; -private Q_SLOTS: - void shouldHaveDefaultValue(); + explicit KMailUserFeedbackProvider(QObject *parent = nullptr); + ~KMailUserFeedbackProvider(); }; -#endif // EXTERNALEDITORWARNINGTEST_H +#endif // KMAILUSERFEEDBACKPROVIDER_H diff --git a/src/userfeedback/kmailuserfeedbackprovider.cpp b/src/userfeedback/kmailuserfeedbackprovider.cpp new file mode 100644 --- /dev/null +++ b/src/userfeedback/kmailuserfeedbackprovider.cpp @@ -0,0 +1,56 @@ +/* + Copyright (C) 2020 Laurent Montel + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kmailuserfeedbackprovider.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "userfeedback/accountinfosource.h" +#include "userfeedback/plugininfosource.h" + +KMailUserFeedbackProvider::KMailUserFeedbackProvider(QObject *parent) + : KUserFeedback::Provider(parent) +{ + setProductIdentifier(QStringLiteral("org.kde.kmail")); + setFeedbackServer(QUrl(QStringLiteral("https://telemetry.kde.org/"))); + setSubmissionInterval(7); + setApplicationStartsUntilEncouragement(5); + setEncouragementDelay(30); + + addDataSource(new KUserFeedback::ApplicationVersionSource); + addDataSource(new KUserFeedback::PlatformInfoSource); + addDataSource(new KUserFeedback::ScreenInfoSource); + addDataSource(new KUserFeedback::QtVersionSource); + + addDataSource(new KUserFeedback::StartCountSource); + addDataSource(new KUserFeedback::UsageTimeSource); + + addDataSource(new KUserFeedback::LocaleInfoSource); + addDataSource(new AccountInfoSource); + //addDataSource(new PluginInfoSource); +} + +KMailUserFeedbackProvider::~KMailUserFeedbackProvider() +{ +} diff --git a/src/folderarchive/folderarchiveutil.h b/src/userfeedback/plugininfosource.h copy from src/folderarchive/folderarchiveutil.h copy to src/userfeedback/plugininfosource.h --- a/src/folderarchive/folderarchiveutil.h +++ b/src/userfeedback/plugininfosource.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -16,16 +16,21 @@ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef FOLDERARCHIVEUTIL_H -#define FOLDERARCHIVEUTIL_H - -#include -namespace FolderArchive { -namespace FolderArchiveUtil { -QString groupConfigPattern(); -bool resourceSupportArchiving(const QString &resource); -QString configFileName(); -} -} - -#endif // FOLDERARCHIVEUTIL_H + +#ifndef PLUGININFOSOURCE_H +#define PLUGININFOSOURCE_H +#include +#include "kmail_private_export.h" + +class KMAILTESTS_TESTS_EXPORT PluginInfoSource : public KUserFeedback::AbstractDataSource +{ +public: + PluginInfoSource(); + + Q_REQUIRED_RESULT QString name() const override; + Q_REQUIRED_RESULT QString description() const override; + + Q_REQUIRED_RESULT QVariant data() override; +}; + +#endif // PLUGININFOSOURCE_H diff --git a/src/editor/warningwidgets/externaleditorwarning.cpp b/src/userfeedback/plugininfosource.cpp copy from src/editor/warningwidgets/externaleditorwarning.cpp copy to src/userfeedback/plugininfosource.cpp --- a/src/editor/warningwidgets/externaleditorwarning.cpp +++ b/src/userfeedback/plugininfosource.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -17,20 +17,28 @@ Boston, MA 02110-1301, USA. */ -#include "externaleditorwarning.h" - +#include "plugininfosource.h" +#include +#include #include -ExternalEditorWarning::ExternalEditorWarning(QWidget *parent) - : KMessageWidget(parent) +PluginInfoSource::PluginInfoSource() + : KUserFeedback::AbstractDataSource(QStringLiteral("plugins"), KUserFeedback::Provider::DetailedSystemInformation) +{ +} + +QString PluginInfoSource::name() const +{ + return i18n("Plugins Information"); +} + +QString PluginInfoSource::description() const { - setVisible(false); - setCloseButtonVisible(false); - setMessageType(Information); - setText(i18n("External editor was started.")); - setWordWrap(true); + return i18n("Plugins used in KMail."); } -ExternalEditorWarning::~ExternalEditorWarning() +QVariant PluginInfoSource::data() { + //TODO add list of plugins. + return {}; } diff --git a/src/util.h b/src/util.h --- a/src/util.h +++ b/src/util.h @@ -64,15 +64,15 @@ * Handles a clicked URL, but only in case the viewer didn't handle it. * Currently only support mailto. */ -bool handleClickedURL(const QUrl &url, const QSharedPointer &folder = QSharedPointer(), const Akonadi::Collection &collection = Akonadi::Collection()); +Q_REQUIRED_RESULT bool handleClickedURL(const QUrl &url, const QSharedPointer &folder = QSharedPointer(), const Akonadi::Collection &collection = Akonadi::Collection()); -bool mailingListsHandleURL(const QList &lst, const QSharedPointer &folder, const Akonadi::Collection &collection); +Q_REQUIRED_RESULT bool mailingListsHandleURL(const QList &lst, const QSharedPointer &folder, const Akonadi::Collection &collection); -bool mailingListPost(const QSharedPointer &fd, const Akonadi::Collection &col); -bool mailingListSubscribe(const QSharedPointer &fd, const Akonadi::Collection &col); -bool mailingListUnsubscribe(const QSharedPointer &fd, const Akonadi::Collection &col); -bool mailingListArchives(const QSharedPointer &fd, const Akonadi::Collection &col); -bool mailingListHelp(const QSharedPointer &fd, const Akonadi::Collection &col); +Q_REQUIRED_RESULT bool mailingListPost(const QSharedPointer &fd, const Akonadi::Collection &col); +Q_REQUIRED_RESULT bool mailingListSubscribe(const QSharedPointer &fd, const Akonadi::Collection &col); +Q_REQUIRED_RESULT bool mailingListUnsubscribe(const QSharedPointer &fd, const Akonadi::Collection &col); +Q_REQUIRED_RESULT bool mailingListArchives(const QSharedPointer &fd, const Akonadi::Collection &col); +Q_REQUIRED_RESULT bool mailingListHelp(const QSharedPointer &fd, const Akonadi::Collection &col); void lastEncryptAndSignState(bool &lastEncrypt, bool &lastSign, const KMime::Message::Ptr &msg); diff --git a/src/util.cpp b/src/util.cpp --- a/src/util.cpp +++ b/src/util.cpp @@ -39,12 +39,12 @@ #include "kmkernel.h" #include -#include "MessageComposer/MessageHelper" +#include #include "job/handleclickedurljob.h" #include -#include -#include +#include +#include #include "kmail_debug.h" #include @@ -182,7 +182,7 @@ { if (action) { action->setText(isInTrashFolder ? i18nc("@action Hard delete, bypassing trash", "&Delete") : i18n("&Move to Trash")); - action->setIcon(isInTrashFolder ? QIcon::fromTheme(QStringLiteral("edit-delete")) : QIcon::fromTheme(QStringLiteral("edit-delete-shred"))); + action->setIcon(isInTrashFolder ? QIcon::fromTheme(QStringLiteral("edit-delete-shred")) : QIcon::fromTheme(QStringLiteral("edit-delete"))); //Use same text as in Text property. Change it in kf5 action->setToolTip(isInTrashFolder ? i18nc("@action Hard delete, bypassing trash", "Delete") : i18n("Move to Trash")); } diff --git a/src/widgets/collectionpane.h b/src/widgets/collectionpane.h --- a/src/widgets/collectionpane.h +++ b/src/widgets/collectionpane.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2010-2019 Montel Laurent + Copyright (C) 2010-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -20,7 +20,7 @@ #ifndef COLLECTIONPANE_H #define COLLECTIONPANE_H -#include +#include #include class CollectionPane : public MessageList::Pane @@ -43,7 +43,7 @@ */ explicit CollectionStorageModel(QAbstractItemModel *model, QItemSelectionModel *selectionModel, QObject *parent = nullptr); ~CollectionStorageModel(); - bool isOutBoundFolder(const Akonadi::Collection &c) const override; + Q_REQUIRED_RESULT bool isOutBoundFolder(const Akonadi::Collection &c) const override; }; #endif /* COLLECTIONPANE_H */ diff --git a/src/widgets/collectionpane.cpp b/src/widgets/collectionpane.cpp --- a/src/widgets/collectionpane.cpp +++ b/src/widgets/collectionpane.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010-2019 Montel Laurent + Copyright (C) 2010-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -19,7 +19,7 @@ #include "collectionpane.h" #include "kmkernel.h" -#include "mailcommon/mailkernel.h" +#include #include #include diff --git a/src/widgets/displaymessageformatactionmenu.h b/src/widgets/displaymessageformatactionmenu.h --- a/src/widgets/displaymessageformatactionmenu.h +++ b/src/widgets/displaymessageformatactionmenu.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -21,16 +21,16 @@ #define DisplayMessageFormatActionMenu_H #include -#include "messageviewer/viewer.h" +#include class DisplayMessageFormatActionMenu : public KActionMenu { Q_OBJECT public: explicit DisplayMessageFormatActionMenu(QObject *parent = nullptr); ~DisplayMessageFormatActionMenu(); - MessageViewer::Viewer::DisplayFormatMessage displayMessageFormat() const; + Q_REQUIRED_RESULT MessageViewer::Viewer::DisplayFormatMessage displayMessageFormat() const; void setDisplayMessageFormat(MessageViewer::Viewer::DisplayFormatMessage displayMessageFormat); Q_SIGNALS: diff --git a/src/widgets/displaymessageformatactionmenu.cpp b/src/widgets/displaymessageformatactionmenu.cpp --- a/src/widgets/displaymessageformatactionmenu.cpp +++ b/src/widgets/displaymessageformatactionmenu.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2019 Montel Laurent + Copyright (C) 2014-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/widgets/kactionmenuaccount.h b/src/widgets/kactionmenuaccount.h --- a/src/widgets/kactionmenuaccount.h +++ b/src/widgets/kactionmenuaccount.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/widgets/kactionmenuaccount.cpp b/src/widgets/kactionmenuaccount.cpp --- a/src/widgets/kactionmenuaccount.cpp +++ b/src/widgets/kactionmenuaccount.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -20,7 +20,7 @@ #include "kactionmenuaccount.h" #include #include -#include "MailCommon/MailUtil" +#include #include "kmail_debug.h" #include diff --git a/src/widgets/kactionmenutransport.h b/src/widgets/kactionmenutransport.h --- a/src/widgets/kactionmenutransport.h +++ b/src/widgets/kactionmenutransport.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/widgets/kactionmenutransport.cpp b/src/widgets/kactionmenutransport.cpp --- a/src/widgets/kactionmenutransport.cpp +++ b/src/widgets/kactionmenutransport.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2019 Montel Laurent + Copyright (C) 2015-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -19,7 +19,7 @@ #include "kactionmenutransport.h" #include -#include +#include KActionMenuTransport::KActionMenuTransport(QObject *parent) : KActionMenu(parent) diff --git a/src/widgets/statusbarlabeltoggledstate.cpp b/src/widgets/statusbarlabeltoggledstate.cpp deleted file mode 100644 --- a/src/widgets/statusbarlabeltoggledstate.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright (C) 2014-2019 Montel Laurent - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "statusbarlabeltoggledstate.h" -#include "kmail_debug.h" - -StatusBarLabelToggledState::StatusBarLabelToggledState(QWidget *parent) - : QLabel(parent) -{ - setTextFormat(Qt::PlainText); -} - -StatusBarLabelToggledState::~StatusBarLabelToggledState() -{ -} - -void StatusBarLabelToggledState::setStateString(const QString &toggled, const QString &untoggled) -{ - if (toggled.isEmpty() || untoggled.isEmpty()) { - qCWarning(KMAIL_LOG) << " State string is empty. Need to fix it"; - } - mToggled = toggled; - mUnToggled = untoggled; - updateLabel(); -} - -void StatusBarLabelToggledState::setToggleMode(bool state) -{ - if (mToggleMode != state) { - mToggleMode = state; - Q_EMIT toggleModeChanged(mToggleMode); - updateLabel(); - } -} - -bool StatusBarLabelToggledState::toggleMode() const -{ - return mToggleMode; -} - -void StatusBarLabelToggledState::updateLabel() -{ - if (mToggleMode) { - setText(mToggled); - } else { - setText(mUnToggled); - } -} - -void StatusBarLabelToggledState::mousePressEvent(QMouseEvent *ev) -{ - Q_UNUSED(ev); - setToggleMode(!mToggleMode); -} diff --git a/src/widgets/vacationscriptindicatorwidget.h b/src/widgets/vacationscriptindicatorwidget.h --- a/src/widgets/vacationscriptindicatorwidget.h +++ b/src/widgets/vacationscriptindicatorwidget.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -66,7 +66,7 @@ void updateIndicator(); - bool hasVacationScriptActive() const; + Q_REQUIRED_RESULT bool hasVacationScriptActive() const; Q_SIGNALS: void clicked(const QString &serverName); diff --git a/src/widgets/vacationscriptindicatorwidget.cpp b/src/widgets/vacationscriptindicatorwidget.cpp --- a/src/widgets/vacationscriptindicatorwidget.cpp +++ b/src/widgets/vacationscriptindicatorwidget.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Montel Laurent + Copyright (C) 2013-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/src/widgets/zoomlabelwidget.h b/src/widgets/zoomlabelwidget.h --- a/src/widgets/zoomlabelwidget.h +++ b/src/widgets/zoomlabelwidget.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2018-2019 Laurent Montel + Copyright (C) 2018-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/src/widgets/zoomlabelwidget.cpp b/src/widgets/zoomlabelwidget.cpp --- a/src/widgets/zoomlabelwidget.cpp +++ b/src/widgets/zoomlabelwidget.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2018-2019 Laurent Montel + Copyright (C) 2018-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public