File indexing completed on 2024-05-12 05:10:42

0001 /*
0002   SPDX-FileCopyrightText: 2009, 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
0003   SPDX-FileContributor: Frank Osterfeld <osterfeld@kde.org>
0004   SPDX-FileContributor: Andras Mantia <andras@kdab.com>
0005   SPDX-FileCopyrightText: 2010-2012 SĂ©rgio Martins <iamsergio@gmail.com>
0006   SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
0007 
0008   SPDX-License-Identifier: LGPL-2.0-or-later
0009 */
0010 
0011 #include "calendarutils.h"
0012 #include "etmcalendar.h"
0013 
0014 #include <Akonadi/AgentManager>
0015 #include <Akonadi/Collection>
0016 #include <Akonadi/EntityTreeModel>
0017 
0018 #include <KCalUtils/ICalDrag>
0019 
0020 #include <KLocalizedString>
0021 
0022 #include <QMimeData>
0023 
0024 using namespace Akonadi;
0025 
0026 KCalendarCore::Incidence::Ptr CalendarUtils::incidence(const Akonadi::Item &item)
0027 {
0028     // With this try-catch block, we get a 2x performance improvement in retrieving the payload
0029     // since we don't call hasPayload()
0030     try {
0031         return item.payload<KCalendarCore::Incidence::Ptr>();
0032     } catch (const Akonadi::PayloadException &) {
0033         return {};
0034     }
0035 }
0036 
0037 KCalendarCore::Event::Ptr CalendarUtils::event(const Akonadi::Item &item)
0038 {
0039     try {
0040         auto incidence = item.payload<KCalendarCore::Incidence::Ptr>();
0041         if (incidence && incidence->type() == KCalendarCore::Incidence::TypeEvent) {
0042             return item.payload<KCalendarCore::Event::Ptr>();
0043         }
0044     } catch (const Akonadi::PayloadException &) {
0045         return {};
0046     }
0047     return {};
0048 }
0049 
0050 KCalendarCore::Todo::Ptr CalendarUtils::todo(const Akonadi::Item &item)
0051 {
0052     try {
0053         auto incidence = item.payload<KCalendarCore::Incidence::Ptr>();
0054         if (incidence && incidence->type() == KCalendarCore::Incidence::TypeTodo) {
0055             return item.payload<KCalendarCore::Todo::Ptr>();
0056         }
0057     } catch (const Akonadi::PayloadException &) {
0058         return {};
0059     }
0060     return {};
0061 }
0062 
0063 KCalendarCore::Journal::Ptr CalendarUtils::journal(const Akonadi::Item &item)
0064 {
0065     try {
0066         auto incidence = item.payload<KCalendarCore::Incidence::Ptr>();
0067         if (incidence && incidence->type() == KCalendarCore::Incidence::TypeJournal) {
0068             return item.payload<KCalendarCore::Journal::Ptr>();
0069         }
0070     } catch (const Akonadi::PayloadException &) {
0071         return {};
0072     }
0073     return {};
0074 }
0075 
0076 static QString displayNameImpl(const Akonadi::EntityTreeModel *model, const Akonadi::Collection &c)
0077 {
0078     Akonadi::Collection fullCollection = c;
0079     if (model) {
0080         if (const auto col = Akonadi::EntityTreeModel::updatedCollection(model, c); col.isValid()) {
0081             fullCollection = col;
0082         }
0083     }
0084 
0085     QString cName = fullCollection.name();
0086     const QString resourceName = fullCollection.resource();
0087 
0088     // Kolab Groupware
0089     if (resourceName.contains(QLatin1StringView("kolab"))) {
0090         QString typeStr = cName; // contents type: "Calendar", "Tasks", etc
0091         QString ownerStr; // folder owner: "fred", "ethel", etc
0092         QString nameStr; // folder name: "Public", "Test", etc
0093         if (model) {
0094             Akonadi::Collection p = c.parentCollection();
0095             while (p != Akonadi::Collection::root()) {
0096                 Akonadi::Collection tCol = Akonadi::EntityTreeModel::updatedCollection(model, Collection{p.id()});
0097                 const QString tName = tCol.name();
0098                 if (tName.startsWith(QLatin1StringView("shared.cal"), Qt::CaseInsensitive)) {
0099                     ownerStr = QStringLiteral("Shared");
0100                     nameStr = cName;
0101                     typeStr = i18n("Calendar");
0102                     break;
0103                 } else if (tName.startsWith(QLatin1StringView("shared.tasks"), Qt::CaseInsensitive)
0104                            || tName.startsWith(QLatin1StringView("shared.todo"), Qt::CaseInsensitive)) {
0105                     ownerStr = QStringLiteral("Shared");
0106                     nameStr = cName;
0107                     typeStr = i18n("Tasks");
0108                     break;
0109                 } else if (tName.startsWith(QLatin1StringView("shared.journal"), Qt::CaseInsensitive)) {
0110                     ownerStr = QStringLiteral("Shared");
0111                     nameStr = cName;
0112                     typeStr = i18n("Journal");
0113                     break;
0114                 } else if (tName.startsWith(QLatin1StringView("shared.notes"), Qt::CaseInsensitive)) {
0115                     ownerStr = QStringLiteral("Shared");
0116                     nameStr = cName;
0117                     typeStr = i18n("Notes");
0118                     break;
0119                 } else if (tName != i18n("Calendar") && tName != i18n("Tasks") && tName != i18n("Journal") && tName != i18n("Notes")) {
0120                     ownerStr = tName;
0121                     break;
0122                 } else {
0123                     nameStr = typeStr;
0124                     typeStr = tName;
0125                 }
0126                 p = p.parentCollection();
0127             }
0128         }
0129 
0130         if (!ownerStr.isEmpty()) {
0131             if (!ownerStr.compare(QLatin1StringView("INBOX"), Qt::CaseInsensitive)) {
0132                 return i18nc("%1 is folder contents", "My Kolab %1", typeStr);
0133             } else if (!ownerStr.compare(QLatin1StringView("SHARED"), Qt::CaseInsensitive)
0134                        || !ownerStr.compare(QLatin1StringView("CALENDAR"), Qt::CaseInsensitive)
0135                        || !ownerStr.compare(QLatin1StringView("RESOURCES"), Qt::CaseInsensitive)) {
0136                 return i18nc("%1 is folder name, %2 is folder contents", "Shared Kolab %1 %2", nameStr, typeStr);
0137             } else {
0138                 if (nameStr.isEmpty()) {
0139                     return i18nc("%1 is folder owner name, %2 is folder contents", "%1's Kolab %2", ownerStr, typeStr);
0140                 } else {
0141                     return i18nc("%1 is folder owner name, %2 is folder name, %3 is folder contents", "%1's %2 Kolab %3", ownerStr, nameStr, typeStr);
0142                 }
0143             }
0144         } else {
0145             return i18nc("%1 is folder contents", "Kolab %1", typeStr);
0146         }
0147     } // end kolab section
0148 
0149     // Dav Groupware
0150     if (resourceName.contains(QLatin1StringView("davgroupware"))) {
0151         const QString resourceDisplayName = Akonadi::AgentManager::self()->instance(resourceName).name();
0152         return i18nc("%1 is the folder name", "%1 in %2", fullCollection.displayName(), resourceDisplayName);
0153     } // end caldav section
0154 
0155     // Google
0156     if (resourceName.contains(QLatin1StringView("google"))) {
0157         QString ownerStr; // folder owner: "user@gmail.com"
0158         if (model) {
0159             Akonadi::Collection p = c.parentCollection();
0160             ownerStr = Akonadi::EntityTreeModel::updatedCollection(model, Collection{p.id()}).displayName();
0161         }
0162 
0163         const QString nameStr = c.displayName(); // folder name: can be anything
0164 
0165         QString typeStr;
0166         const QString mimeStr = c.contentMimeTypes().join(QLatin1Char(','));
0167         if (mimeStr.contains(QLatin1StringView(".event"))) {
0168             typeStr = i18n("Calendar");
0169         } else if (mimeStr.contains(QLatin1StringView(".todo"))) {
0170             typeStr = i18n("Tasks");
0171         } else if (mimeStr.contains(QLatin1StringView(".journal"))) {
0172             typeStr = i18n("Journal");
0173         } else if (mimeStr.contains(QLatin1StringView(".note"))) {
0174             typeStr = i18n("Notes");
0175         } else {
0176             typeStr = mimeStr;
0177         }
0178 
0179         if (!ownerStr.isEmpty()) {
0180             const int atChar = ownerStr.lastIndexOf(QLatin1Char('@'));
0181             if (atChar >= 0) {
0182                 ownerStr.truncate(atChar);
0183             }
0184             if (nameStr.isEmpty()) {
0185                 return i18nc("%1 is folder owner name, %2 is folder contents", "%1's Google %2", ownerStr, typeStr);
0186             } else {
0187                 return i18nc("%1 is folder owner name, %2 is folder name", "%1's %2", ownerStr, nameStr);
0188             }
0189         } else {
0190             return i18nc("%1 is folder contents", "Google %1", typeStr);
0191         }
0192     } // end google section
0193 
0194     // Not groupware so the collection is "mine"
0195     const QString dName = fullCollection.displayName();
0196 
0197     if (!dName.isEmpty()) {
0198         return fullCollection.name().startsWith(QLatin1StringView("akonadi_")) ? i18n("My %1", dName) : dName;
0199     } else if (!fullCollection.name().isEmpty()) {
0200         return fullCollection.name();
0201     } else {
0202         return i18nc("unknown resource", "Unknown");
0203     }
0204 }
0205 
0206 QString CalendarUtils::displayName(Akonadi::ETMCalendar *calendar, const Akonadi::Collection &c)
0207 {
0208     return displayNameImpl(calendar ? calendar->entityTreeModel() : nullptr, c);
0209 }
0210 
0211 QString CalendarUtils::displayName(const Akonadi::EntityTreeModel *model, const Akonadi::Collection &c)
0212 {
0213     return displayNameImpl(model, c);
0214 }
0215 
0216 QString CalendarUtils::displayName(const Akonadi::Collection &c)
0217 {
0218     return displayNameImpl(nullptr, c);
0219 }
0220 
0221 QMimeData *CalendarUtils::createMimeData(const Akonadi::Item::List &items)
0222 {
0223     if (items.isEmpty()) {
0224         return nullptr;
0225     }
0226 
0227     KCalendarCore::MemoryCalendar::Ptr cal(new KCalendarCore::MemoryCalendar(QTimeZone::systemTimeZone()));
0228 
0229     QList<QUrl> urls;
0230     int incidencesFound = 0;
0231     for (const Akonadi::Item &item : items) {
0232         const KCalendarCore::Incidence::Ptr incidence(CalendarUtils::incidence(item));
0233         if (!incidence) {
0234             continue;
0235         }
0236         ++incidencesFound;
0237         urls.push_back(item.url());
0238         KCalendarCore::Incidence::Ptr i(incidence->clone());
0239         cal->addIncidence(i);
0240     }
0241 
0242     if (incidencesFound == 0) {
0243         return nullptr;
0244     }
0245 
0246     auto mimeData = std::make_unique<QMimeData>();
0247     mimeData->setUrls(urls);
0248 
0249     if (KCalUtils::ICalDrag::populateMimeData(mimeData.get(), cal)) {
0250         return mimeData.release();
0251     } else {
0252         return nullptr;
0253     }
0254 }