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 }