diff --git a/CMakeLists.txt b/CMakeLists.txt index 33121e4..da55b5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,105 +1,99 @@ cmake_minimum_required(VERSION 3.0) set(PIM_VERSION "5.6.42") project(calendarsupport VERSION ${PIM_VERSION}) set(KF5_VERSION "5.38.0") find_package(ECM ${KF5_VERSION} CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) set(LIBRARY_NAMELINK) include(GenerateExportHeader) include(ECMSetupVersion) include(ECMGenerateHeaders) include(ECMGeneratePriFile) include(CMakePackageConfigHelpers) include(ECMSetupVersion) include(FeatureSummary) include(KDEInstallDirs) include(KDECMakeSettings) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(ECMQtDeclareLoggingCategory) include(ECMAddTests) include(ECMCoverageOption) set(CALENDARSUPPORT_LIB_VERSION ${PIM_VERSION}) set(AKONADI_MIMELIB_VERSION "5.6.40") set(KDEPIM_LIB_VERSION "5.6.40") set(QT_REQUIRED_VERSION "5.8.0") set(KMIME_LIB_VERSION "5.6.40") set(CALENDARUTILS_LIB_VERSION "5.6.43") set(KCALENDARCORE_LIB_VERSION "5.6.40") set(IDENTITYMANAGEMENT_LIB_VERSION "5.6.40") set(KHOLIDAYS_LIB_VERSION "5.6.40") set(AKONADICALENDAR_LIB_VERSION "5.6.40") set(PIMCOMMON_LIB_VERSION "5.6.40") set(AKONADI_VERSION "5.6.40") set(KIMAP_LIB_VERSION "5.6.40") find_package(KF5Akonadi ${AKONADI_VERSION} CONFIG REQUIRED) find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED Widgets Test UiTools PrintSupport) find_package(KF5I18n ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5IconThemes ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5GuiAddons ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5KIO ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5Mime ${KMIME_LIB_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiMime ${AKONADI_MIMELIB_VERSION} CONFIG REQUIRED) find_package(KF5Codecs ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5CalendarUtils ${CALENDARUTILS_LIB_VERSION} CONFIG REQUIRED) find_package(KF5CalendarCore ${KCALENDARCORE_LIB_VERSION} CONFIG REQUIRED) find_package(KF5IdentityManagement ${IDENTITYMANAGEMENT_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Holidays ${KHOLIDAYS_LIB_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiCalendar ${AKONADICALENDAR_LIB_VERSION} CONFIG REQUIRED) find_package(KF5PimCommon ${PIMCOMMON_LIB_VERSION} CONFIG REQUIRED) find_package(KF5KdepimDBusInterfaces ${KDEPIM_LIB_VERSION} CONFIG REQUIRED) find_package(KF5IMAP ${KIMAP_LIB_VERSION} CONFIG REQUIRED) -find_package(Boost MODULE) -set_package_properties(Boost PROPERTIES - TYPE REQUIRED - URL "http://www.boost.org" -) - ecm_setup_version(PROJECT VARIABLE_PREFIX CALENDARSUPPORT VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/calendarsupport_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5CalendarSupportConfigVersion.cmake" SOVERSION 5 ) ########### Targets ########### add_definitions("-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII") add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT) #add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000) add_definitions(-DQT_NO_URL_CAST_FROM_STRING) ########### CMake Config Files ########### set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5CalendarSupport") configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KF5CalendarSupportConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5CalendarSupportConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5CalendarSupportConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5CalendarSupportConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT KF5CalendarSupportTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5CalendarSupportTargets.cmake NAMESPACE KF5::) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/calendarsupport_version.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel ) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) add_subdirectory(src) install( FILES calendarsupport.categories calendarsupport.renamecategories DESTINATION ${KDE_INSTALL_CONFDIR} ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 12b48d2..e7941b7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,189 +1,189 @@ add_definitions(-DQT_NO_CAST_FROM_ASCII) add_definitions(-DQT_NO_CAST_TO_ASCII) add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT) add_definitions(-DTRANSLATION_DOMAIN=\"calendarsupport\") ########### next target ############### set(calendarsupport_LIB_SRCS archivedialog.cpp attachmenthandler.cpp calendarsingleton.cpp calendarutils.cpp categoryconfig.cpp categoryhierarchyreader.cpp cellitem.cpp collectionselection.cpp eventarchiver.cpp identitymanager.cpp incidenceattachmentmodel.cpp kcalmodel.cpp kcalprefs.cpp messagewidget.cpp utils.cpp tagcache.cpp plugin.cpp printing/calprintpluginbase.cpp printing/calprintdefaultplugins.cpp printing/calprinter.cpp printing/journalprint.cpp printing/yearprint.cpp next/incidenceviewer.cpp freebusymodel/freeperiodmodel.cpp freebusymodel/freebusyitem.cpp freebusymodel/freebusyitemmodel.cpp freebusymodel/freebusycalendar.cpp ) ki18n_wrap_ui(calendarsupport_LIB_SRCS printing/calprintdayconfig_base.ui printing/calprintincidenceconfig_base.ui printing/calprintjournalconfig_base.ui printing/calprintmonthconfig_base.ui printing/calprinttodoconfig_base.ui printing/calprintweekconfig_base.ui printing/calprintyearconfig_base.ui ) ecm_qt_declare_logging_category(calendarsupport_LIB_SRCS HEADER calendarsupport_debug.h IDENTIFIER CALENDARSUPPORT_LOG CATEGORY_NAME org.kde.pim.calendarsupport) kconfig_add_kcfg_files(calendarsupport_LIB_SRCS kcalprefs_base.kcfgc) add_library(KF5CalendarSupport ${calendarsupport_LIB_SRCS}) generate_export_header(KF5CalendarSupport BASE_NAME calendarsupport) add_library(KF5::CalendarSupport ALIAS KF5CalendarSupport) target_include_directories(KF5CalendarSupport INTERFACE "$") -target_include_directories(KF5CalendarSupport PUBLIC "$") +target_include_directories(KF5CalendarSupport PUBLIC "$") target_link_libraries( KF5CalendarSupport PUBLIC KF5::Mime KF5::IdentityManagement KF5::AkonadiCalendar Qt5::PrintSupport PRIVATE KF5::I18n KF5::Completion KF5::KIOWidgets KF5::IconThemes KF5::GuiAddons KF5::AkonadiWidgets KF5::Holidays KF5::Codecs KF5::AkonadiCore KF5::CalendarCore KF5::CalendarUtils KF5::KdepimDBusInterfaces KF5::PimCommon ) set_target_properties(KF5CalendarSupport PROPERTIES VERSION ${CALENDARSUPPORT_VERSION_STRING} SOVERSION ${CALENDARSUPPORT_SOVERSION} EXPORT_NAME CalendarSupport ) install(TARGETS KF5CalendarSupport EXPORT KF5CalendarSupportTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} ${LIBRARY_NAMELINK} ) ecm_generate_headers(CalendarSupport_CamelCase_HEADERS HEADER_NAMES Utils CategoryConfig CellItem CollectionSelection KCalPrefs IdentityManager EventArchiver Plugin CategoryHierarchyReader CalendarSingleton MessageWidget ArchiveDialog REQUIRED_HEADERS CalendarSupport_HEADERS PREFIX CalendarSupport ) ecm_generate_headers(CalendarSupport_CamelCaseprinter_HEADERS HEADER_NAMES PrintPlugin CalPrinter CalPrintDefaultPlugins CalPrintPluginBase REQUIRED_HEADERS CalendarSupport_printer_HEADERS PREFIX CalendarSupport RELATIVE printing ) ecm_generate_headers(CalendarSupport_CamelCasenext_HEADERS HEADER_NAMES IncidenceViewer REQUIRED_HEADERS CalendarSupport_next_HEADERS PREFIX CalendarSupport RELATIVE next ) ecm_generate_headers(CalendarSupport_CamelCasefreebusy_HEADERS HEADER_NAMES FreeBusyItem FreeBusyItemModel FreeBusyCalendar FreePeriodModel REQUIRED_HEADERS CalendarSupport_freebusy_HEADERS PREFIX CalendarSupport RELATIVE freebusymodel ) ecm_generate_pri_file(BASE_NAME CalendarSupport LIB_NAME KF5CalendarSupport DEPS "Mime IdentityManagement AkonadiCalendar" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/CalendarSupport ) install(FILES ${CalendarSupport_CamelCase_HEADERS} ${CalendarSupport_CamelCaseprinter_HEADERS} ${CalendarSupport_CamelCasenext_HEADERS} ${CalendarSupport_CamelCasefreebusy_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/CalendarSupport COMPONENT Devel ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/calendarsupport_export.h ${CMAKE_CURRENT_BINARY_DIR}/ui_calprintincidenceconfig_base.h ${CMAKE_CURRENT_BINARY_DIR}/ui_calprintdayconfig_base.h ${CMAKE_CURRENT_BINARY_DIR}/ui_calprintweekconfig_base.h ${CMAKE_CURRENT_BINARY_DIR}/ui_calprintmonthconfig_base.h ${CMAKE_CURRENT_BINARY_DIR}/ui_calprinttodoconfig_base.h ${CMAKE_CURRENT_BINARY_DIR}/kcalprefs_base.h ${CalendarSupport_HEADERS} ${CalendarSupport_printer_HEADERS} ${CalendarSupport_next_HEADERS} ${CalendarSupport_freebusy_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/calendarsupport COMPONENT Devel ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) install(FILES calendarplugin.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR}) if(BUILD_TESTING) add_subdirectory(freebusymodel/autotests) endif() diff --git a/src/utils.cpp b/src/utils.cpp index 61e974e..9fb2647 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,806 +1,807 @@ /* Copyright (c) 2009, 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Frank Osterfeld Author: Andras Mantia 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; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include "utils.h" #include "kcalprefs.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include "calendarsupport_debug.h" using namespace CalendarSupport; using namespace KHolidays; using namespace KCalCore; KCalCore::Incidence::Ptr CalendarSupport::incidence(const Akonadi::Item &item) { //relying on exception for performance reasons try { return item.payload(); } catch (Akonadi::PayloadException) { return KCalCore::Incidence::Ptr(); } } KCalCore::Event::Ptr CalendarSupport::event(const Akonadi::Item &item) { //relying on exception for performance reasons try { KCalCore::Incidence::Ptr incidence = item.payload(); if (hasEvent(incidence)) { return item.payload(); } } catch (Akonadi::PayloadException) { return KCalCore::Event::Ptr(); } return KCalCore::Event::Ptr(); } KCalCore::Event::Ptr CalendarSupport::event(const KCalCore::Incidence::Ptr &incidence) { if (hasEvent(incidence)) { return incidence.staticCast(); } return KCalCore::Event::Ptr(); } KCalCore::Incidence::List CalendarSupport::incidencesFromItems(const Akonadi::Item::List &items) { KCalCore::Incidence::List incidences; for (const Akonadi::Item &item : items) { if (const KCalCore::Incidence::Ptr e = CalendarSupport::incidence(item)) { incidences.push_back(e); } } return incidences; } KCalCore::Todo::Ptr CalendarSupport::todo(const Akonadi::Item &item) { try { KCalCore::Incidence::Ptr incidence = item.payload(); if (hasTodo(incidence)) { return item.payload(); } } catch (Akonadi::PayloadException) { return KCalCore::Todo::Ptr(); } return KCalCore::Todo::Ptr(); } KCalCore::Todo::Ptr CalendarSupport::todo(const KCalCore::Incidence::Ptr &incidence) { if (hasTodo(incidence)) { return incidence.staticCast(); } return KCalCore::Todo::Ptr(); } KCalCore::Journal::Ptr CalendarSupport::journal(const Akonadi::Item &item) { try { KCalCore::Incidence::Ptr incidence = item.payload(); if (hasJournal(incidence)) { return item.payload(); } } catch (Akonadi::PayloadException) { return KCalCore::Journal::Ptr(); } return KCalCore::Journal::Ptr(); } KCalCore::Journal::Ptr CalendarSupport::journal(const KCalCore::Incidence::Ptr &incidence) { if (hasJournal(incidence)) { return incidence.staticCast(); } return KCalCore::Journal::Ptr(); } bool CalendarSupport::hasIncidence(const Akonadi::Item &item) { return item.hasPayload(); } bool CalendarSupport::hasEvent(const Akonadi::Item &item) { return item.hasPayload(); } bool CalendarSupport::hasEvent(const KCalCore::Incidence::Ptr &incidence) { return incidence && incidence->type() == KCalCore::Incidence::TypeEvent; } bool CalendarSupport::hasTodo(const Akonadi::Item &item) { return item.hasPayload(); } bool CalendarSupport::hasTodo(const KCalCore::Incidence::Ptr &incidence) { return incidence && incidence->type() == KCalCore::Incidence::TypeTodo; } bool CalendarSupport::hasJournal(const Akonadi::Item &item) { return item.hasPayload(); } bool CalendarSupport::hasJournal(const KCalCore::Incidence::Ptr &incidence) { return incidence && incidence->type() == KCalCore::Incidence::TypeJournal; } QMimeData *CalendarSupport::createMimeData(const Akonadi::Item::List &items) { if (items.isEmpty()) { return nullptr; } KCalCore::MemoryCalendar::Ptr cal(new KCalCore::MemoryCalendar(QTimeZone::systemTimeZone())); QList urls; int incidencesFound = 0; for (const Akonadi::Item &item : items) { const KCalCore::Incidence::Ptr incidence(CalendarSupport::incidence(item)); if (!incidence) { continue; } ++incidencesFound; urls.push_back(item.url()); KCalCore::Incidence::Ptr i(incidence->clone()); cal->addIncidence(i); } if (incidencesFound == 0) { return nullptr; } std::unique_ptr mimeData(new QMimeData); mimeData->setUrls(urls); KCalUtils::ICalDrag::populateMimeData(mimeData.get(), cal); return mimeData.release(); } QMimeData *CalendarSupport::createMimeData(const Akonadi::Item &item) { return createMimeData(Akonadi::Item::List() << item); } #ifndef QT_NO_DRAGANDDROP QDrag *CalendarSupport::createDrag(const Akonadi::Item &item, QWidget *parent) { return createDrag(Akonadi::Item::List() << item, parent); } #endif static QByteArray findMostCommonType(const Akonadi::Item::List &items) { QByteArray prev; if (items.isEmpty()) { return "Incidence"; } for (const Akonadi::Item &item : items) { if (!CalendarSupport::hasIncidence(item)) { continue; } const QByteArray type = CalendarSupport::incidence(item)->typeStr(); if (!prev.isEmpty() && type != prev) { return "Incidence"; } prev = type; } return prev; } #ifndef QT_NO_DRAGANDDROP QDrag *CalendarSupport::createDrag(const Akonadi::Item::List &items, QWidget *parent) { std::unique_ptr drag(new QDrag(parent)); drag->setMimeData(CalendarSupport::createMimeData(items)); const QByteArray common = findMostCommonType(items); if (common == "Event") { drag->setPixmap(BarIcon(QStringLiteral("view-calendar-day"))); } else if (common == "Todo") { drag->setPixmap(BarIcon(QStringLiteral("view-calendar-tasks"))); } return drag.release(); } #endif static bool itemMatches(const Akonadi::Item &item, const KCalCore::CalFilter *filter) { assert(filter); KCalCore::Incidence::Ptr inc = CalendarSupport::incidence(item); if (!inc) { return false; } return filter->filterIncidence(inc); } Akonadi::Item::List CalendarSupport::applyCalFilter(const Akonadi::Item::List &items_, const KCalCore::CalFilter *filter) { Q_ASSERT(filter); Akonadi::Item::List items(items_); - items.erase(std::remove_if(items.begin(), items.end(), - !bind(itemMatches, _1, filter)), items.end()); + items.erase(std::remove_if(items.begin(), items.end(), [filter](const Akonadi::Item &item) { + return !itemMatches(item, filter); + }), items.end()); return items; } bool CalendarSupport::isValidIncidenceItemUrl(const QUrl &url, const QStringList &supportedMimeTypes) { if (!url.isValid()) { return false; } if (url.scheme() != QLatin1String("akonadi")) { return false; } return supportedMimeTypes.contains(QUrlQuery(url).queryItemValue(QStringLiteral("type"))); } bool CalendarSupport::isValidIncidenceItemUrl(const QUrl &url) { return isValidIncidenceItemUrl(url, QStringList() << KCalCore::Event::eventMimeType() << KCalCore::Todo::todoMimeType() << KCalCore::Journal::journalMimeType() << KCalCore::FreeBusy::freeBusyMimeType()); } static bool containsValidIncidenceItemUrl(const QList &urls) { return - std::find_if(urls.begin(), urls.end(), - bind(CalendarSupport::isValidIncidenceItemUrl, _1)) != urls.constEnd(); + std::find_if(urls.begin(), urls.end(), [](const QUrl &url) { + return CalendarSupport::isValidIncidenceItemUrl(url); + }) != urls.constEnd(); } bool CalendarSupport::canDecode(const QMimeData *md) { if (md) { return containsValidIncidenceItemUrl(md->urls()) || KCalUtils::ICalDrag::canDecode(md) || KCalUtils::VCalDrag::canDecode(md); } else { return false; } } QList CalendarSupport::incidenceItemUrls(const QMimeData *mimeData) { QList urls; const QList urlsList = mimeData->urls(); for (const QUrl &i : urlsList ) { if (isValidIncidenceItemUrl(i)) { urls.push_back(i); } } return urls; } QList CalendarSupport::todoItemUrls(const QMimeData *mimeData) { QList urls; const QList urlList = mimeData->urls(); for (const QUrl &i : urlList) { if (isValidIncidenceItemUrl(i, QStringList() << KCalCore::Todo::todoMimeType())) { urls.push_back(i); } } return urls; } bool CalendarSupport::mimeDataHasIncidence(const QMimeData *mimeData) { return !incidenceItemUrls(mimeData).isEmpty() || !incidences(mimeData).isEmpty(); } KCalCore::Todo::List CalendarSupport::todos(const QMimeData *mimeData) { KCalCore::Todo::List todos; #ifndef QT_NO_DRAGANDDROP KCalCore::Calendar::Ptr cal(KCalUtils::DndFactory::createDropCalendar(mimeData)); if (cal) { const KCalCore::Todo::List calTodos = cal->todos(); todos.reserve(calTodos.count()); for (const KCalCore::Todo::Ptr &i : calTodos) { todos.push_back(KCalCore::Todo::Ptr(i->clone())); } } #endif return todos; } KCalCore::Incidence::List CalendarSupport::incidences(const QMimeData *mimeData) { KCalCore::Incidence::List incidences; #ifndef QT_NO_DRAGANDDROP KCalCore::Calendar::Ptr cal(KCalUtils::DndFactory::createDropCalendar(mimeData)); if (cal) { const KCalCore::Incidence::List calIncidences = cal->incidences(); incidences.reserve(calIncidences.count()); for (const KCalCore::Incidence::Ptr &i : calIncidences) { incidences.push_back(KCalCore::Incidence::Ptr(i->clone())); } } #endif return incidences; } Akonadi::Collection CalendarSupport::selectCollection(QWidget *parent, int &dialogCode, const QStringList &mimeTypes, const Akonadi::Collection &defCollection) { QPointer dlg(new Akonadi::CollectionDialog(parent)); dlg->setWindowTitle(i18n("Select Calendar")); dlg->setDescription(i18n("Select the calendar where this item will be stored.")); dlg->changeCollectionDialogOptions(Akonadi::CollectionDialog::KeepTreeExpanded); qCDebug(CALENDARSUPPORT_LOG) << "selecting collections with mimeType in " << mimeTypes; dlg->setMimeTypeFilter(mimeTypes); dlg->setAccessRightsFilter(Akonadi::Collection::CanCreateItem); if (defCollection.isValid()) { dlg->setDefaultCollection(defCollection); } Akonadi::Collection collection; // FIXME: don't use exec. dialogCode = dlg->exec(); if (dlg && dialogCode == QDialog::Accepted) { collection = dlg->selectedCollection(); if (!collection.isValid()) { qCWarning(CALENDARSUPPORT_LOG) << "An invalid collection was selected!"; } } delete dlg; return collection; } Akonadi::Item CalendarSupport::itemFromIndex(const QModelIndex &idx) { Akonadi::Item item = idx.data(Akonadi::EntityTreeModel::ItemRole).value(); item.setParentCollection( idx.data(Akonadi::EntityTreeModel::ParentCollectionRole).value()); return item; } Akonadi::Collection::List CalendarSupport::collectionsFromModel(const QAbstractItemModel *model, const QModelIndex &parentIndex, int start, int end) { const int endRow = end >= 0 ? end : model->rowCount(parentIndex) - 1; Akonadi::Collection::List collections; int row = start; QModelIndex i = model->index(row, 0, parentIndex); while (row <= endRow) { const Akonadi::Collection collection = collectionFromIndex(i); if (collection.isValid()) { collections << collection; QModelIndex childIndex = i.child(0, 0); if (childIndex.isValid()) { collections << collectionsFromModel(model, i); } } ++row; i = i.sibling(row, 0); } return collections; } Akonadi::Item::List CalendarSupport::itemsFromModel(const QAbstractItemModel *model, const QModelIndex &parentIndex, int start, int end) { const int endRow = end >= 0 ? end : model->rowCount(parentIndex) - 1; Akonadi::Item::List items; int row = start; QModelIndex i = model->index(row, 0, parentIndex); while (row <= endRow) { const Akonadi::Item item = itemFromIndex(i); if (CalendarSupport::hasIncidence(item)) { items << item; } else { QModelIndex childIndex = i.child(0, 0); if (childIndex.isValid()) { items << itemsFromModel(model, i); } } ++row; i = i.sibling(row, 0); } return items; } Akonadi::Collection CalendarSupport::collectionFromIndex(const QModelIndex &index) { return index.data(Akonadi::EntityTreeModel::CollectionRole).value(); } Akonadi::Collection::Id CalendarSupport::collectionIdFromIndex(const QModelIndex &index) { return index.data(Akonadi::EntityTreeModel::CollectionIdRole).value(); } Akonadi::Collection::List CalendarSupport::collectionsFromIndexes(const QModelIndexList &indexes) { Akonadi::Collection::List l; l.reserve(indexes.count()); for (const QModelIndex &idx : indexes) { l.push_back(collectionFromIndex(idx)); } return l; } QString CalendarSupport::displayName(Akonadi::ETMCalendar *calendar, const Akonadi::Collection &c) { Akonadi::Collection fullCollection; if (calendar && calendar->collection(c.id()).isValid()) { fullCollection = calendar->collection(c.id()); } else { fullCollection = c; } QString cName = fullCollection.name(); const QString resourceName = fullCollection.resource(); // Kolab Groupware if (resourceName.contains(QStringLiteral("kolab"))) { QString typeStr = cName; // contents type: "Calendar", "Tasks", etc QString ownerStr; // folder owner: "fred", "ethel", etc QString nameStr; // folder name: "Public", "Test", etc if (calendar) { Akonadi::Collection p = c.parentCollection(); while (p != Akonadi::Collection::root()) { Akonadi::Collection tCol = calendar->collection(p.id()); const QString tName = tCol.name(); if (tName.startsWith(QStringLiteral("shared.cal"), Qt::CaseInsensitive)) { ownerStr = QStringLiteral("Shared"); nameStr = cName; typeStr = QStringLiteral("Calendar"); break; } else if (tName.startsWith(QStringLiteral("shared.tasks"), Qt::CaseInsensitive) || tName.startsWith(QStringLiteral("shared.todo"), Qt::CaseInsensitive)) { ownerStr = QStringLiteral("Shared"); nameStr = cName; typeStr = QStringLiteral("Tasks"); break; } else if (tName.startsWith(QStringLiteral("shared.journal"), Qt::CaseInsensitive)) { ownerStr = QStringLiteral("Shared"); nameStr = cName; typeStr = QStringLiteral("Journal"); break; } else if (tName.startsWith(QStringLiteral("shared.notes"), Qt::CaseInsensitive)) { ownerStr = QStringLiteral("Shared"); nameStr = cName; typeStr = QStringLiteral("Notes"); break; } else if (tName != i18n("Calendar") && tName != i18n("Tasks") && tName != i18n("Journal") && tName != i18n("Notes")) { ownerStr = tName; break; } else { nameStr = typeStr; typeStr = tName; } p = p.parentCollection(); } } if (!ownerStr.isEmpty()) { if (!ownerStr.compare(QLatin1String("INBOX"), Qt::CaseInsensitive)) { return i18nc("%1 is folder contents", "My Kolab %1", typeStr); } else if (!ownerStr.compare(QLatin1String("SHARED"), Qt::CaseInsensitive) || !ownerStr.compare(QLatin1String("CALENDAR"), Qt::CaseInsensitive) || !ownerStr.compare(QLatin1String("RESOURCES"), Qt::CaseInsensitive)) { return i18nc("%1 is folder name, %2 is folder contents", "Shared Kolab %1 %2", nameStr, typeStr); } else { if (nameStr.isEmpty()) { return i18nc("%1 is folder owner name, %2 is folder contents", "%1's Kolab %2", ownerStr, typeStr); } else { return i18nc("%1 is folder owner name, %2 is folder name, %3 is folder contents", "%1's %2 Kolab %3", ownerStr, nameStr, typeStr); } } } else { return i18nc("%1 is folder contents", "Kolab %1", typeStr); } } //end kolab section // Dav Groupware if (resourceName.contains(QStringLiteral("davgroupware"))) { const QString resourceDisplayName = Akonadi::AgentManager::self()->instance(resourceName).name(); return i18nc("%1 is the folder name", "%1 in %2", fullCollection.displayName(), resourceDisplayName); } //end caldav section // Google if (resourceName.contains(QStringLiteral("google"))) { QString ownerStr; // folder owner: "user@gmail.com" if (calendar) { Akonadi::Collection p = c.parentCollection(); ownerStr = calendar->collection(p.id()).displayName(); } const QString nameStr = c.displayName(); // folder name: can be anything QString typeStr; const QString mimeStr = c.contentMimeTypes().join(QLatin1Char(',')); if (mimeStr.contains(QStringLiteral(".event"))) { typeStr = i18n("Calendar"); } else if (mimeStr.contains(QStringLiteral(".todo"))) { typeStr = i18n("Tasks"); } else if (mimeStr.contains(QStringLiteral(".journal"))) { typeStr = i18n("Journal"); } else if (mimeStr.contains(QStringLiteral(".note"))) { typeStr = i18n("Notes"); } else { typeStr = mimeStr; } if (!ownerStr.isEmpty()) { const int atChar = ownerStr.lastIndexOf(QLatin1Char('@')); if (atChar >= 0) ownerStr.truncate(atChar); if (nameStr.isEmpty()) { return i18nc("%1 is folder owner name, %2 is folder contents", "%1's Google %2", ownerStr, typeStr); } else { return i18nc("%1 is folder owner name, %2 is folder name", "%1's %2", ownerStr, nameStr); } } else { return i18nc("%1 is folder contents", "Google %1", typeStr); } } //end google section // Not groupware so the collection is "mine" const QString dName = fullCollection.displayName(); if (!dName.isEmpty()) { return fullCollection.name().startsWith(QStringLiteral("akonadi_")) ? i18n("My %1", dName) : dName; } else if (!fullCollection.name().isEmpty()) { return fullCollection.name(); } else { return i18nc("unknown resource", "Unknown"); } } QString CalendarSupport::subMimeTypeForIncidence(const KCalCore::Incidence::Ptr &incidence) { return incidence->mimeType(); } QList CalendarSupport::workDays(const QDate &startDate, const QDate &endDate) { QList result; const int mask(~(KCalPrefs::instance()->mWorkWeekMask)); const int numDays = startDate.daysTo(endDate) + 1; for (int i = 0; i < numDays; ++i) { const QDate date = startDate.addDays(i); if (!(mask & (1 << (date.dayOfWeek() - 1)))) { result.append(date); } } if (KCalPrefs::instance()->mExcludeHolidays) { // NOTE: KOGlobals, where this method comes from, used to hold a pointer to // a KHolidays object. I'm not sure about how expensive it is, just // creating one here. const HolidayRegion holidays(KCalPrefs::instance()->mHolidays); const Holiday::List list = holidays.holidays(startDate, endDate); const int listCount(list.count()); for (int i = 0; i < listCount; ++i) { const Holiday &h = list.at(i); if (h.dayType() == Holiday::NonWorkday) { result.removeAll(h.observedStartDate()); } } } return result; } QStringList CalendarSupport::holiday(const QDate &date) { QStringList hdays; const HolidayRegion holidays(KCalPrefs::instance()->mHolidays); const Holiday::List list = holidays.holidays(date); const int listCount = list.count(); hdays.reserve(listCount); for (int i = 0; i < listCount; ++i) { hdays.append(list.at(i).name()); } return hdays; } void CalendarSupport::saveAttachments(const Akonadi::Item &item, QWidget *parentWidget) { Incidence::Ptr incidence = CalendarSupport::incidence(item); if (!incidence) { KMessageBox::sorry( parentWidget, i18n("No item selected.")); return; } Attachment::List attachments = incidence->attachments(); if (attachments.empty()) { return; } QString targetFile, targetDir; if (attachments.count() > 1) { // get the dir targetDir = QFileDialog::getExistingDirectory(parentWidget, i18n("Save Attachments To")); if (targetDir.isEmpty()) { return; } // we may not get a slash-terminated url out of KFileDialog if (!targetDir.endsWith(QLatin1Char('/'))) { targetDir.append(QLatin1Char('/')); } } else { // only one item, get the desired filename QString fileName = attachments.first()->label(); if (fileName.isEmpty()) { fileName = i18nc("filename for an unnamed attachment", "attachment.1"); } targetFile = QFileDialog::getSaveFileName(parentWidget, i18n("Save Attachment"), fileName); if (targetFile.isEmpty()) { return; } targetDir = QFileInfo(targetFile).absolutePath() + QLatin1Char('/'); } for (const Attachment::Ptr &attachment : qAsConst(attachments)) { targetFile = targetDir + attachment->label(); QUrl sourceUrl; if (attachment->isUri()) { sourceUrl = QUrl(attachment->uri()); } else { sourceUrl = QUrl::fromLocalFile(incidence->writeAttachmentToTempFile(attachment)); } // save the attachment url auto job = KIO::file_copy(sourceUrl, QUrl::fromLocalFile(targetFile)); if (!job->exec() && job->error()) { KMessageBox::error(parentWidget, job->errorString()); } } } QStringList CalendarSupport::categories(const KCalCore::Incidence::List &incidences) { QStringList cats, thisCats; // @TODO: For now just iterate over all incidences. In the future, // the list of categories should be built when reading the file. for (const KCalCore::Incidence::Ptr &incidence : incidences) { thisCats = incidence->categories(); const QStringList::ConstIterator send(thisCats.constEnd()); for (QStringList::ConstIterator si = thisCats.constBegin(); si != send; ++si) { if (!cats.contains(*si)) { cats.append(*si); } } } return cats; } bool CalendarSupport::mergeCalendar(const QString &srcFilename, const KCalCore::Calendar::Ptr &destCalendar) { if (srcFilename.isEmpty()) { qCCritical(CALENDARSUPPORT_LOG) << "Empty filename."; return false; } if (!QFile::exists(srcFilename)) { qCCritical(CALENDARSUPPORT_LOG) << "File'" << srcFilename << "' doesn't exist."; } bool loadedSuccesfully = true; // merge in a file destCalendar->startBatchAdding(); KCalCore::FileStorage storage(destCalendar); storage.setFileName(srcFilename); loadedSuccesfully = storage.load(); destCalendar->endBatchAdding(); return loadedSuccesfully; }