Incidenceeditor

incidencedefaults.cpp
1/*
2 SPDX-FileCopyrightText: 2010 Bertjan Broeksema <broeksema@kde.org>
3 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include <config-enterprise.h>
9
10#include "alarmpresets.h"
11#include "incidencedefaults.h"
12#include "incidenceeditor_debug.h"
13
14#include <CalendarSupport/KCalPrefs>
15#include <akonadi/calendarsettings.h> //krazy:exclude=camelcase this is a generated file
16
17#include <KContacts/Addressee>
18
19#include <KCalendarCore/Alarm>
20#include <KCalendarCore/Event>
21#include <KCalendarCore/Journal>
22#include <KCalendarCore/Todo>
23
24#include <KEmailAddress>
25
26#include <KIO/StoredTransferJob>
27#include <KLocalizedString>
28
29#include <QFile>
30#include <QUrl>
31
32using namespace CalendarSupport;
33using namespace IncidenceEditorNG;
34using namespace KCalendarCore;
35
36namespace IncidenceEditorNG
37{
38enum { UNSPECIFED_PRIORITY = 0 };
39
40class IncidenceDefaultsPrivate
41{
42public:
43 /// Members
46 QStringList mEmails;
47 QString mGroupWareDomain;
48 KCalendarCore::Incidence::Ptr mRelatedIncidence;
49 QDateTime mStartDt;
50 QDateTime mEndDt;
51 bool mCleanupTemporaryFiles;
52
53 /// Methods
54 [[nodiscard]] KCalendarCore::Person organizerAsPerson() const;
55 [[nodiscard]] KCalendarCore::Attendee organizerAsAttendee(const KCalendarCore::Person &organizer) const;
56
57 void todoDefaults(const KCalendarCore::Todo::Ptr &todo) const;
58 void eventDefaults(const KCalendarCore::Event::Ptr &event) const;
59 void journalDefaults(const KCalendarCore::Journal::Ptr &journal) const;
60};
61}
62
63KCalendarCore::Person IncidenceDefaultsPrivate::organizerAsPerson() const
64{
66
67 KCalendarCore::Person organizer;
68 organizer.setName(i18nc("@label", "no (valid) identities found"));
69 organizer.setEmail(invalidEmail);
70
71 if (mEmails.isEmpty()) {
72 // Don't bother any longer, either someone forget to call setFullEmails, or
73 // the user has no identities configured.
74 return organizer;
75 }
76
77 if (!mGroupWareDomain.isEmpty()) {
78 // Check if we have an identity with an email that ends with the groupware
79 // domain.
80 for (const QString &fullEmail : std::as_const(mEmails)) {
82 QString email;
83 const bool success = KEmailAddress::extractEmailAddressAndName(fullEmail, email, name);
84 if (success && email.endsWith(mGroupWareDomain)) {
85 organizer.setName(name);
86 organizer.setEmail(email);
87 break;
88 }
89 }
90 }
91
92 if (organizer.email() == invalidEmail) {
93 // Either, no groupware was used, or we didn't find a groupware email address.
94 // Now try to
95 for (const QString &fullEmail : std::as_const(mEmails)) {
97 QString email;
98 const bool success = KEmailAddress::extractEmailAddressAndName(fullEmail, email, name);
99 if (success) {
100 organizer.setName(name);
101 organizer.setEmail(email);
102 break;
103 }
104 }
105 }
106
107 return organizer;
108}
109
110KCalendarCore::Attendee IncidenceDefaultsPrivate::organizerAsAttendee(const KCalendarCore::Person &organizer) const
111{
112 KCalendarCore::Attendee organizerAsAttendee;
113 // Really, the appropriate values (even the fall back values) should come from
114 // organizer. (See organizerAsPerson for more details).
115 organizerAsAttendee.setName(organizer.name());
116 organizerAsAttendee.setEmail(organizer.email());
117 // NOTE: Don't set the status to None, this value is not supported by the attendee
118 // editor atm.
119 organizerAsAttendee.setStatus(KCalendarCore::Attendee::Accepted);
121 return organizerAsAttendee;
122}
123
124void IncidenceDefaultsPrivate::eventDefaults(const KCalendarCore::Event::Ptr &event) const
125{
126 QDateTime startDT;
127 if (mStartDt.isValid()) {
128 startDT = mStartDt;
129 } else {
130 startDT = QDateTime::currentDateTime();
131
132 if (KCalPrefs::instance()->startTime().isValid()) {
133 startDT.setTime(KCalPrefs::instance()->startTime().time());
134 }
135 }
136
137 if (startDT.timeSpec() == Qt::LocalTime) {
138 // Ensure the default is not "floating"
140 }
141
142 const QTime defaultDurationTime = KCalPrefs::instance()->defaultDuration().time();
143 const int defaultDuration = (defaultDurationTime.hour() * 3600) + (defaultDurationTime.minute() * 60);
144
145 QDateTime endDT = mEndDt.isValid() ? mEndDt : startDT.addSecs(defaultDuration);
146
147 if (endDT.timeSpec() == Qt::LocalTime) {
148 // Ensure the default is not "floating"
150 }
151
152 event->setDtStart(startDT);
153 event->setDtEnd(endDT);
154 event->setTransparency(KCalendarCore::Event::Opaque);
155
156 if (KCalPrefs::instance()->defaultEventReminders()) {
157 event->addAlarm(AlarmPresets::defaultAlarm(AlarmPresets::BeforeStart));
158 }
159}
160
161void IncidenceDefaultsPrivate::journalDefaults(const KCalendarCore::Journal::Ptr &journal) const
162{
163 QDateTime startDT = mStartDt.isValid() ? mStartDt : QDateTime::currentDateTime();
164 if (startDT.timeSpec() == Qt::LocalTime) {
165 // Ensure the default is not "floating"
167 }
168 journal->setDtStart(startDT);
169 journal->setAllDay(true);
170}
171
172void IncidenceDefaultsPrivate::todoDefaults(const KCalendarCore::Todo::Ptr &todo) const
173{
174 KCalendarCore::Todo::Ptr relatedTodo = mRelatedIncidence.dynamicCast<KCalendarCore::Todo>();
175 if (relatedTodo) {
176 todo->setCategories(relatedTodo->categories());
177 }
178
179 // Now, but not in the "floating" time zone.
181
182 if (mEndDt.isValid()) {
183 if (mEndDt.timeSpec() == Qt::LocalTime) {
184 // Ensure the default is not "floating"
185 todo->setDtDue(mEndDt.toTimeZone(QTimeZone::systemTimeZone()), true);
186 } else {
187 todo->setDtDue(mEndDt, true /* first */);
188 }
189 } else if (relatedTodo && relatedTodo->hasDueDate()) {
190 todo->setDtDue(relatedTodo->dtDue(true), true /** first */);
191 todo->setAllDay(relatedTodo->allDay());
192 } else if (relatedTodo) {
193 todo->setDtDue(QDateTime());
194 } else {
195 todo->setDtDue(systemNow.addDays(1), true /** first */);
196 }
197
198 if (mStartDt.isValid()) {
199 if (mStartDt.timeSpec() == Qt::LocalTime) {
200 // Ensure the default is not "floating"
201 todo->setDtStart(mStartDt.toTimeZone(QTimeZone::systemTimeZone()));
202 } else {
203 todo->setDtStart(mStartDt);
204 }
205 } else if (relatedTodo && !relatedTodo->hasStartDate()) {
206 todo->setDtStart(QDateTime());
207 } else if (relatedTodo && relatedTodo->hasStartDate() && relatedTodo->dtStart() <= todo->dtDue()) {
208 todo->setDtStart(relatedTodo->dtStart());
209 todo->setAllDay(relatedTodo->allDay());
210 } else if (!mEndDt.isValid() || systemNow < mEndDt) {
211 todo->setDtStart(systemNow);
212 } else {
213 todo->setDtStart(mEndDt.addDays(-1));
214 }
215
216 todo->setCompleted(false);
217 todo->setPercentComplete(0);
218
219 // I had a bunch of to-dos and couldn't distinguish between those that had priority '5'
220 // because I wanted, and those that had priority '5' because it was set by default
221 // and I forgot to unset it.
222 // So don't be smart and try to guess a good default priority for the user, just use unspecified.
223 todo->setPriority(UNSPECIFED_PRIORITY);
224
225 if (KCalPrefs::instance()->defaultTodoReminders()) {
226 todo->addAlarm(AlarmPresets::defaultAlarm(AlarmPresets::BeforeEnd));
227 }
228}
229
230/// IncidenceDefaults
231
232IncidenceDefaults::IncidenceDefaults(bool cleanupAttachmentTemporaryFiles)
233 : d_ptr(new IncidenceDefaultsPrivate)
234{
235 d_ptr->mCleanupTemporaryFiles = cleanupAttachmentTemporaryFiles;
236}
237
239 : d_ptr(new IncidenceDefaultsPrivate)
240{
241 *d_ptr = *other.d_ptr;
242}
243
244IncidenceDefaults::~IncidenceDefaults() = default;
245
246IncidenceDefaults &IncidenceDefaults::operator=(const IncidenceDefaults &other)
247{
248 if (&other != this) {
249 *d_ptr = *other.d_ptr;
250 }
251 return *this;
252}
253
255 const QStringList &attachmentMimetypes,
256 const QStringList &attachmentLabels,
257 bool inlineAttachment)
258{
260 d->mAttachments.clear();
261
263 int i = 0;
264 for (it = attachments.constBegin(); it != attachments.constEnd(); ++it, ++i) {
265 if (!(*it).isEmpty()) {
266 QString mimeType;
267 if (attachmentMimetypes.count() > i) {
268 mimeType = attachmentMimetypes[i];
269 }
270
271 KCalendarCore::Attachment attachment;
272 if (inlineAttachment) {
273 auto job = KIO::storedGet(QUrl::fromUserInput(*it));
274 if (job->exec()) {
275 const QByteArray data = job->data();
276 attachment = KCalendarCore::Attachment(data.toBase64(), mimeType);
277
278 if (i < attachmentLabels.count()) {
279 attachment.setLabel(attachmentLabels[i]);
280 }
281 } else {
282 qCCritical(INCIDENCEEDITOR_LOG) << "Error downloading uri " << *it << job->errorString();
283 }
284
285 if (d_ptr->mCleanupTemporaryFiles) {
286 QFile file(*it);
287 if (!file.remove()) {
288 qCCritical(INCIDENCEEDITOR_LOG) << "Uname to remove file " << *it;
289 }
290 }
291 } else {
292 attachment = KCalendarCore::Attachment(*it, mimeType);
293 if (i < attachmentLabels.count()) {
294 attachment.setLabel(attachmentLabels[i]);
295 }
296 }
297
298 if (!attachment.isEmpty()) {
299 if (attachment.label().isEmpty()) {
300 if (attachment.isUri()) {
301 attachment.setLabel(attachment.uri());
302 } else {
303 attachment.setLabel(i18nc("@label attachment contains binary data", "[Binary data]"));
304 }
305 }
306 d->mAttachments << attachment;
307 attachment.setShowInline(inlineAttachment);
308 }
309 }
310 }
311}
312
314{
316 d->mAttendees.clear();
318 for (it = attendees.begin(); it != attendees.end(); ++it) {
319 QString name;
320 QString email;
322 d->mAttendees << KCalendarCore::Attendee(name, email, true, KCalendarCore::Attendee::NeedsAction);
323 }
324}
325
327{
329 d->mEmails = fullEmails;
330}
331
333{
335 d->mGroupWareDomain = domain;
336}
337
339{
341 d->mRelatedIncidence = incidence;
342}
343
345{
347 d->mStartDt = startDT;
348}
349
351{
353 d->mEndDt = endDT;
354}
355
357{
358 Q_D(const IncidenceDefaults);
359
360 // First some general defaults
361 incidence->setSummary(QString(), false);
362 incidence->setLocation(QString(), false);
363 incidence->setCategories(QStringList());
364 incidence->setSecrecy(KCalendarCore::Incidence::SecrecyPublic);
365 incidence->setStatus(KCalendarCore::Incidence::StatusNone);
366 incidence->setAllDay(false);
367 incidence->setCustomStatus(QString());
368 incidence->setResources(QStringList());
369 incidence->setPriority(0);
370
371 if (d->mRelatedIncidence) {
372 incidence->setRelatedTo(d->mRelatedIncidence->uid());
373 }
374
375 incidence->clearAlarms();
376 incidence->clearAttachments();
377 incidence->clearAttendees();
378 incidence->clearComments();
379 incidence->clearContacts();
380 incidence->clearRecurrence();
381
382 const KCalendarCore::Person organizerAsPerson = d->organizerAsPerson();
383#if KDEPIM_ENTERPRISE_BUILD
384 incidence->addAttendee(d->organizerAsAttendee(organizerAsPerson));
385#endif
386 for (const KCalendarCore::Attendee &attendee : std::as_const(d->mAttendees)) {
387 incidence->addAttendee(attendee);
388 }
389 // Ical standard: No attendees -> must not have an organizer!
390 if (incidence->attendeeCount()) {
391 incidence->setOrganizer(organizerAsPerson);
392 }
393
394 for (const KCalendarCore::Attachment &attachment : std::as_const(d->mAttachments)) {
395 incidence->addAttachment(attachment);
396 }
397
398 switch (incidence->type()) {
400 d->eventDefaults(incidence.dynamicCast<KCalendarCore::Event>());
401 break;
403 d->todoDefaults(incidence.dynamicCast<KCalendarCore::Todo>());
404 break;
406 d->journalDefaults(incidence.dynamicCast<KCalendarCore::Journal>());
407 break;
408 default:
409 qCDebug(INCIDENCEEDITOR_LOG) << "Unsupported incidence type, keeping current values. Type: " << static_cast<int>(incidence->type());
410 }
411}
412
413/** static */
415{
416 IncidenceDefaults defaults(cleanupAttachmentTempFiles);
417
418 // Set the full emails manually here, to avoid that we get dependencies on
419 // KCalPrefs all over the place.
420 defaults.setFullEmails(CalendarSupport::KCalPrefs::instance()->fullEmails());
421
422 // NOTE: At some point this should be generalized. That is, we now use the
423 // freebusy url as a hack, but this assumes that the user has only one
424 // groupware account. Which doesn't have to be the case necessarily.
425 // This method should somehow depend on the calendar selected to which
426 // the incidence is added.
427 if (CalendarSupport::KCalPrefs::instance()->useGroupwareCommunication()) {
428 defaults.setGroupWareDomain(QUrl(Akonadi::CalendarSettings::self()->freeBusyRetrieveUrl()).host());
429 }
430 return defaults;
431}
432
433/** static */
435{
436 static const QString invalidEmail(i18nc("@label invalid email address marker", "invalid@email.address"));
437 return invalidEmail;
438}
The IncidenceDefaults class.
void setAttendees(const QStringList &attendees)
Sets the attendees that are added by default to incidences.
void setFullEmails(const QStringList &fullEmails)
Sets the list of identities to be used for the user.
static IncidenceDefaults minimalIncidenceDefaults(bool cleanupAttachmentTempFiles=false)
Returns minimal incidence defaults: e-mails and groupware domain.
void setGroupWareDomain(const QString &domain)
This is used to do a smarter guess about which identity to use for the organizer.
void setStartDateTime(const QDateTime &startDT)
Set the start date/time to use for passed incidences.
IncidenceDefaults(bool cleanupAttachmentTEmporaryFiles=false)
IncidenceDefaults.
void setEndDateTime(const QDateTime &endDT)
Set the end date/time to use for passed incidences.
void setDefaults(const KCalendarCore::Incidence::Ptr &incidence) const
Sets the default values for.
void setAttachments(const QStringList &attachments, const QStringList &attachmentMimetypes=QStringList(), const QStringList &attachmentLabels=QStringList(), bool inlineAttachment=false)
Sets the attachments that are added by default to incidences.
void setRelatedIncidence(const KCalendarCore::Incidence::Ptr &incidence)
Sets the incidence related to the incidence for which to set the defaults.
void setShowInline(bool showinline)
void setLabel(const QString &label)
void setStatus(PartStat status)
void setName(const QString &name)
void setRole(Role role)
void setEmail(const QString &email)
QString email() const
QString name() const
void setEmail(const QString &email)
void setName(const QString &name)
static void parseEmailAddress(const QString &rawEmail, QString &fullName, QString &email)
KCODECS_EXPORT bool extractEmailAddressAndName(const QString &aStr, QString &mail, QString &name)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Journal::Ptr journal(const Akonadi::Item &item)
AKONADI_CALENDAR_EXPORT KCalendarCore::Todo::Ptr todo(const Akonadi::Item &item)
QString name(GameStandardAction id)
KIOCORE_EXPORT StoredTransferJob * storedGet(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
bool isValid(QStringView ifopt)
char * data()
QByteArray toBase64(Base64Options options) const const
QDateTime addDays(qint64 ndays) const const
QDateTime addSecs(qint64 s) const const
QDateTime currentDateTime()
bool isValid() const const
void setTime(QTime time)
void setTimeZone(const QTimeZone &toZone)
Qt::TimeSpec timeSpec() const const
QDateTime toTimeZone(const QTimeZone &timeZone) const const
bool remove()
typedef ConstIterator
iterator begin()
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
iterator end()
bool isEmpty() const const
QSharedPointer< X > dynamicCast() const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
LocalTime
int hour() const const
int minute() const const
QTimeZone systemTimeZone()
QUrl fromUserInput(const QString &userInput, const QString &workingDirectory, UserInputResolutionOptions options)
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:52:44 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.