KCalendarCore

compat.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the kcalcore library.
3 
4  SPDX-FileCopyrightText: 2002 Cornelius Schumacher <[email protected]>
5  SPDX-FileCopyrightText: 2003-2004 Reinhold Kainhofer <[email protected]>
6  SPDX-FileCopyrightText: 2012 Christian Mollekopf <[email protected]>
7 
8  SPDX-License-Identifier: LGPL-2.0-or-later
9 */
10 /**
11  @file
12  This file is part of the API for handling calendar data and defines
13  classes for managing compatibility between different calendar formats.
14 
15  @brief
16  Classes that provide compatibility to older or "broken" calendar formats.
17 
18  @author Cornelius Schumacher <[email protected]>
19  @author Reinhold Kainhofer <[email protected]>
20 */
21 
22 #include "compat_p.h"
23 #include "incidence.h"
24 
25 #include "kcalendarcore_debug.h"
26 
27 #include <QDate>
28 #include <QRegularExpression>
29 #include <QString>
30 
31 using namespace KCalendarCore;
32 
33 Compat *CompatFactory::createCompat(const QString &productId, const QString &implementationVersion)
34 {
35  Compat *compat = nullptr;
36 
37  int korg = productId.indexOf(QLatin1String("KOrganizer"));
38  int outl9 = productId.indexOf(QLatin1String("Outlook 9.0"));
39 
40  if (korg >= 0) {
41  int versionStart = productId.indexOf(QLatin1Char(' '), korg);
42  if (versionStart >= 0) {
43  int versionStop = productId.indexOf(QRegularExpression(QStringLiteral("[ /]")), versionStart + 1);
44  if (versionStop >= 0) {
45  QString version = productId.mid(versionStart + 1, versionStop - versionStart - 1);
46 
47  int versionNum = version.section(QLatin1Char('.'), 0, 0).toInt() * 10000 + version.section(QLatin1Char('.'), 1, 1).toInt() * 100
48  + version.section(QLatin1Char('.'), 2, 2).toInt();
49  int releaseStop = productId.indexOf(QLatin1Char('/'), versionStop);
50  QString release;
51  if (releaseStop > versionStop) {
52  release = productId.mid(versionStop + 1, releaseStop - versionStop - 1);
53  }
54  if (versionNum < 30100) {
55  compat = new CompatPre31;
56  } else if (versionNum < 30200) {
57  compat = new CompatPre32;
58  } else if (versionNum == 30200 && release == QLatin1String("pre")) {
59  qCDebug(KCALCORE_LOG) << "Generating compat for KOrganizer 3.2 pre";
60  compat = new Compat32PrereleaseVersions;
61  } else if (versionNum < 30400) {
62  compat = new CompatPre34;
63  } else if (versionNum < 30500) {
64  compat = new CompatPre35;
65  }
66  }
67  }
68  } else if (outl9 >= 0) {
69  qCDebug(KCALCORE_LOG) << "Generating compat for Outlook < 2000 (Outlook 9.0)";
70  compat = new CompatOutlook9;
71  }
72  if (!compat) {
73  compat = new Compat;
74  }
75  // Older implementations lacked the implementation version,
76  // so apply this fix if it is a file from kontact and the version is missing.
77  if (implementationVersion.isEmpty()
78  && (productId.contains(QLatin1String("libkcal")) || productId.contains(QLatin1String("KOrganizer")) || productId.contains(QLatin1String("KAlarm")))) {
79  compat = new CompatPre410(compat);
80  }
81 
82  return compat;
83 }
84 
85 Compat::Compat()
86  : d(nullptr)
87 {
88 }
89 
90 Compat::~Compat()
91 {
92 }
93 
94 void Compat::fixEmptySummary(const Incidence::Ptr &incidence)
95 {
96  // some stupid vCal exporters ignore the standard and use Description
97  // instead of Summary for the default field. Correct for this: Copy the
98  // first line of the description to the summary (if summary is just one
99  // line, move it)
100  if (incidence->summary().isEmpty() && !(incidence->description().isEmpty())) {
101  QString oldDescription = incidence->description().trimmed();
102  QString newSummary(oldDescription);
103  newSummary.remove(QRegularExpression(QStringLiteral("\n.*")));
104  incidence->setSummary(newSummary);
105  if (oldDescription == newSummary) {
106  incidence->setDescription(QLatin1String(""));
107  }
108  }
109 }
110 
111 void Compat::fixAlarms(const Incidence::Ptr &incidence)
112 {
113  Q_UNUSED(incidence);
114 }
115 
116 void Compat::fixFloatingEnd(QDate &date)
117 {
118  Q_UNUSED(date);
119 }
120 
121 void Compat::fixRecurrence(const Incidence::Ptr &incidence)
122 {
123  Q_UNUSED(incidence);
124  // Prevent use of compatibility mode during subsequent changes by the application
125  // incidence->recurrence()->setCompatVersion();
126 }
127 
128 int Compat::fixPriority(int priority)
129 {
130  return priority;
131 }
132 
133 bool Compat::useTimeZoneShift() const
134 {
135  return true;
136 }
137 
138 void Compat::setCreatedToDtStamp(const Incidence::Ptr &incidence, const QDateTime &dtstamp)
139 {
140  Q_UNUSED(incidence);
141  Q_UNUSED(dtstamp);
142 }
143 
144 class Q_DECL_HIDDEN CompatDecorator::Private
145 {
146 public:
147  Compat *compat;
148 };
149 
150 CompatDecorator::CompatDecorator(Compat *compat)
151  : d(new CompatDecorator::Private)
152 {
153  d->compat = compat;
154 }
155 
156 CompatDecorator::~CompatDecorator()
157 {
158  delete d->compat;
159  delete d;
160 }
161 
162 void CompatDecorator::fixEmptySummary(const Incidence::Ptr &incidence)
163 {
164  d->compat->fixEmptySummary(incidence);
165 }
166 
167 void CompatDecorator::fixAlarms(const Incidence::Ptr &incidence)
168 {
169  d->compat->fixAlarms(incidence);
170 }
171 
172 void CompatDecorator::fixFloatingEnd(QDate &date)
173 {
174  d->compat->fixFloatingEnd(date);
175 }
176 
177 void CompatDecorator::fixRecurrence(const Incidence::Ptr &incidence)
178 {
179  d->compat->fixRecurrence(incidence);
180 }
181 
182 int CompatDecorator::fixPriority(int priority)
183 {
184  return d->compat->fixPriority(priority);
185 }
186 
187 bool CompatDecorator::useTimeZoneShift() const
188 {
189  return d->compat->useTimeZoneShift();
190 }
191 
192 void CompatDecorator::setCreatedToDtStamp(const Incidence::Ptr &incidence, const QDateTime &dtstamp)
193 {
194  d->compat->setCreatedToDtStamp(incidence, dtstamp);
195 }
196 
197 CompatPre35::CompatPre35()
198  : d(nullptr)
199 {
200 }
201 
202 CompatPre35::~CompatPre35()
203 {
204 }
205 
206 void CompatPre35::fixRecurrence(const Incidence::Ptr &incidence)
207 {
208  Recurrence *recurrence = incidence->recurrence();
209  if (recurrence) {
210  QDateTime start(incidence->dtStart());
211  // kde < 3.5 only had one rrule, so no need to loop over all RRULEs.
212  RecurrenceRule *r = recurrence->defaultRRule();
213  if (r && !r->dateMatchesRules(start)) {
214  recurrence->addExDateTime(start);
215  }
216  }
217 
218  // Call base class method now that everything else is done
219  Compat::fixRecurrence(incidence);
220 }
221 
222 CompatPre34::CompatPre34()
223  : d(nullptr)
224 {
225 }
226 
227 CompatPre34::~CompatPre34()
228 {
229 }
230 
231 int CompatPre34::fixPriority(int priority)
232 {
233  if (0 < priority && priority < 6) {
234  // adjust 1->1, 2->3, 3->5, 4->7, 5->9
235  return 2 * priority - 1;
236  } else {
237  return priority;
238  }
239 }
240 
241 CompatPre32::CompatPre32()
242  : d(nullptr)
243 {
244 }
245 
246 CompatPre32::~CompatPre32()
247 {
248 }
249 
250 void CompatPre32::fixRecurrence(const Incidence::Ptr &incidence)
251 {
252  Recurrence *recurrence = incidence->recurrence();
253  if (recurrence->recurs() && recurrence->duration() > 0) {
254  recurrence->setDuration(recurrence->duration() + incidence->recurrence()->exDates().count());
255  }
256  // Call base class method now that everything else is done
257  CompatPre35::fixRecurrence(incidence);
258 }
259 
260 CompatPre31::CompatPre31()
261  : d(nullptr)
262 {
263 }
264 
265 CompatPre31::~CompatPre31()
266 {
267 }
268 
269 void CompatPre31::fixFloatingEnd(QDate &endDate)
270 {
271  endDate = endDate.addDays(1);
272 }
273 
274 void CompatPre31::fixRecurrence(const Incidence::Ptr &incidence)
275 {
276  CompatPre32::fixRecurrence(incidence);
277 
278  Recurrence *recur = incidence->recurrence();
279  RecurrenceRule *r = nullptr;
280  if (recur) {
281  r = recur->defaultRRule();
282  }
283  if (recur && r) {
284  int duration = r->duration();
285  if (duration > 0) {
286  // Backwards compatibility for KDE < 3.1.
287  // rDuration was set to the number of time periods to recur,
288  // with week start always on a Monday.
289  // Convert this to the number of occurrences.
290  r->setDuration(-1);
291  QDate end(r->startDt().date());
292  bool doNothing = false;
293  // # of periods:
294  int tmp = (duration - 1) * r->frequency();
295  switch (r->recurrenceType()) {
296  case RecurrenceRule::rWeekly: {
297  end = end.addDays(tmp * 7 + 7 - end.dayOfWeek());
298  break;
299  }
300  case RecurrenceRule::rMonthly: {
301  int month = end.month() - 1 + tmp;
302  end.setDate(end.year() + month / 12, month % 12 + 1, 31);
303  break;
304  }
305  case RecurrenceRule::rYearly: {
306  end.setDate(end.year() + tmp, 12, 31);
307  break;
308  }
309  default:
310  doNothing = true;
311  break;
312  }
313  if (!doNothing) {
314  duration = r->durationTo(QDateTime(end, QTime(0, 0, 0), incidence->dtStart().timeZone()));
315  r->setDuration(duration);
316  }
317  }
318 
319  /* addYearlyNum */
320  // Dates were stored as day numbers, with a fiddle to take account of
321  // leap years. Convert the day number to a month.
322  QList<int> days = r->byYearDays();
323  if (!days.isEmpty()) {
324  QList<int> months = r->byMonths();
325  for (int i = 0; i < months.size(); ++i) {
326  int newmonth = QDate(r->startDt().date().year(), 1, 1).addDays(months.at(i) - 1).month();
327  if (!months.contains(newmonth)) {
328  months.append(newmonth);
329  }
330  }
331 
332  r->setByMonths(months);
333  days.clear();
334  r->setByYearDays(days);
335  }
336  }
337 }
338 
339 CompatOutlook9::CompatOutlook9()
340  : d(nullptr)
341 {
342 }
343 
344 CompatOutlook9::~CompatOutlook9()
345 {
346 }
347 
348 void CompatOutlook9::fixAlarms(const Incidence::Ptr &incidence)
349 {
350  if (!incidence) {
351  return;
352  }
353  Alarm::List alarms = incidence->alarms();
354  Alarm::List::Iterator end(alarms.end());
355  for (Alarm::List::Iterator it = alarms.begin(); it != end; ++it) {
356  Alarm::Ptr al = *it;
357  if (al && al->hasStartOffset()) {
358  Duration offsetDuration = al->startOffset();
359  int offs = offsetDuration.asSeconds();
360  if (offs > 0) {
361  offsetDuration = Duration(-offs);
362  }
363  al->setStartOffset(offsetDuration);
364  }
365  }
366 }
367 
368 Compat32PrereleaseVersions::Compat32PrereleaseVersions()
369  : d(nullptr)
370 {
371 }
372 
373 Compat32PrereleaseVersions::~Compat32PrereleaseVersions()
374 {
375 }
376 
377 bool Compat32PrereleaseVersions::useTimeZoneShift() const
378 {
379  return false;
380 }
381 
382 CompatPre410::CompatPre410(Compat *decoratedCompat)
383  : CompatDecorator(decoratedCompat)
384  , d(nullptr)
385 {
386 }
387 
388 CompatPre410::~CompatPre410()
389 {
390 }
391 
392 void CompatPre410::setCreatedToDtStamp(const Incidence::Ptr &incidence, const QDateTime &dtstamp)
393 {
394  if (dtstamp.isValid()) {
395  incidence->setCreated(dtstamp);
396  }
397 }
void clear()
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
Definition: recurrence.cpp:478
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
bool recurs() const
Returns whether the event recurs at all.
Definition: recurrence.cpp:222
typedef Iterator
QVector::iterator begin()
void setDuration(int duration)
Sets the total number of times the event is to occur, including both the first and last...
QDateTime startDt() const
Returns the recurrence start date/time.
const T & at(int i) const const
void setDuration(int duration)
Sets the total number of times the event is to occur, including both the first and last...
Definition: recurrence.cpp:496
uint frequency() const
Returns the recurrence frequency, in terms of the recurrence time period type.
int size() const const
Represents a span of time measured in seconds or days.
Definition: duration.h:43
void append(const T &value)
int toInt(bool *ok, int base) const const
bool isEmpty() const const
bool isEmpty() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool contains(const T &value) const const
bool isValid() const const
const QList< QKeySequence > & end()
This class represents a recurrence rule for a calendar incidence.
Definition: recurrence.h:75
QString mid(int position, int n) const const
QDate date() const const
This file is part of the API for handling calendar data and defines the Incidence class...
int durationTo(const QDateTime &dt) const
Returns the number of recurrences up to and including the date/time specified.
QString section(QChar sep, int start, int end, QString::SectionFlags flags) const const
int asSeconds() const
Returns the length of the duration in seconds.
Definition: duration.cpp:186
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
QDate addDays(qint64 ndays) const const
This class represents a recurrence rule for a calendar incidence.
int year() const const
QVector::iterator end()
Namespace for all KCalendarCore types.
Definition: alarm.h:36
KDB_EXPORT KDbVersionInfo version()
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Wed Apr 21 2021 22:50:49 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.