KCalendarCore

sorting.cpp
1 /*
2  This file is part of the kcalcore library.
3 
4  SPDX-FileCopyrightText: 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
5  SPDX-FileContributor: Alvaro Manera <[email protected]>
6 
7  SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9 #include "sorting.h"
10 
11 // PENDING(kdab) Review
12 // The QString::compare() need to be replace by a DUI string comparisons.
13 // See http://qt.gitorious.org/maemo-6-ui-framework/libdui
14 // If not compiled in "meego-mode" should we be using locale compares?
15 
16 using namespace KCalendarCore;
17 
18 /**
19  * How one QDateTime compares with another.
20  *
21  * If any all-day events are involved, comparison of QDateTime values
22  * requires them to be considered as representing time periods. An all-day
23  * instance represents a time period from 00:00:00 to 23:59:59.999 on a given
24  * date, while a date/time instance can be considered to represent a time
25  * period whose start and end times are the same. They may therefore be
26  * earlier or later, or may overlap or be contained one within the other.
27  *
28  * Values may be OR'ed with each other in any combination of 'consecutive'
29  * intervals to represent different types of relationship.
30  *
31  * In the descriptions of the values below,
32  * - s1 = start time of first instance
33  * - e1 = end time of first instance
34  * - s2 = start time of second instance
35  * - e2 = end time of second instance.
36  */
37 enum DateTimeComparison {
38  Before = 0x01, /**< The first QDateTime is strictly earlier than the second,
39  * i.e. e1 < s2.
40  */
41  AtStart = 0x02, /**< The first QDateTime starts at the same time as the second,
42  * and ends before the end of the second,
43  * i.e. s1 = s2, e1 < e2.
44  */
45  Inside = 0x04, /**< The first QDateTime starts after the start of the second,
46  * and ends before the end of the second,
47  * i.e. s1 > s2, e1 < e2.
48  */
49  AtEnd = 0x08, /**< The first QDateTime starts after the start of the second,
50  * and ends at the same time as the second,
51  * i.e. s1 > s2, e1 = e2.
52  */
53  After = 0x10, /**< The first QDateTime is strictly later than the second,
54  * i.e. s1 > e2.
55  */
56  Equal = AtStart | Inside | AtEnd,
57  /**< Simultaneous, i.e. s1 = s2 && e1 = e2.
58  */
59  Outside = Before | AtStart | Inside | AtEnd | After,
60  /**< The first QDateTime starts before the start of the other,
61  * and ends after the end of the other,
62  * i.e. s1 < s2, e1 > e2.
63  */
64  StartsAt = AtStart | Inside | AtEnd | After,
65  /**< The first QDateTime starts at the same time as the other,
66  * and ends after the end of the other,
67  * i.e. s1 = s2, e1 > e2.
68  */
69  EndsAt = Before | AtStart | Inside | AtEnd,
70  /**< The first QDateTime starts before the start of the other,
71  * and ends at the same time as the other,
72  * i.e. s1 < s2, e1 = e2.
73  */
74 };
75 
76 /**
77  * Compare two QDateTime instances to determine whether they are
78  * simultaneous, earlier or later.
79 
80  * The comparison takes time zones into account: if the two instances have
81  * different time zones, they are first converted to UTC before comparing.
82  *
83  * If both instances are not all-day values, the first instance is considered to
84  * be either simultaneous, earlier or later, and does not overlap.
85  *
86  * If one instance is all-day and the other is a not all-day, the first instance
87  * is either strictly earlier, strictly later, or overlaps.
88  *
89  * If both instance are all-day, they are considered simultaneous if both
90  * their start of day and end of day times are simultaneous with each
91  * other. (Both start and end of day times need to be considered in case a
92  * daylight savings change occurs during that day.) Otherwise, the first instance
93  * can be strictly earlier, earlier but overlapping, later but overlapping,
94  * or strictly later.
95  *
96  * Note that if either instance is a local time (Qt::TimeSpec of Qt::LocalTime),
97  * the result cannot be guaranteed to be correct, since by definition they
98  * contain no information about time zones or daylight savings changes.
99  *
100  * @return DateTimeComparison indicating the relationship of dt1 to dt2
101  * @see operator==(), operator!=(), operator<(), operator<=(), operator>=(), operator>()
102  */
103 
104 DateTimeComparison compare(const QDateTime &dt1, bool isAllDay1, const QDateTime &dt2, bool isAllDay2)
105 {
106  QDateTime start1;
107  QDateTime start2;
108  // FIXME When secondOccurrence is available in QDateTime
109  // const bool conv = (!d->equalSpec(*other.d) || d->secondOccurrence() != other.d->secondOccurrence());
110  const bool conv = dt1.timeSpec() != dt2.timeSpec() || (dt1.timeSpec() == Qt::OffsetFromUTC && dt1.offsetFromUtc() != dt2.offsetFromUtc())
111  || (dt1.timeSpec() == Qt::TimeZone && dt1.timeZone() != dt2.timeZone());
112  if (conv) {
113  // Different time specs or one is a time which occurs twice,
114  // so convert to UTC before comparing
115  start1 = dt1.toUTC();
116  start2 = dt2.toUTC();
117  } else {
118  // Same time specs, so no need to convert to UTC
119  start1 = dt1;
120  start2 = dt2;
121  }
122  if (isAllDay1 || isAllDay2) {
123  // At least one of the instances is date-only, so we need to compare
124  // time periods rather than just times.
125  QDateTime end1;
126  QDateTime end2;
127  if (conv) {
128  if (isAllDay1) {
129  QDateTime dt(dt1);
130  dt.setTime(QTime(23, 59, 59, 999));
131  end1 = dt.toUTC();
132  } else {
133  end1 = start1;
134  }
135  if (isAllDay2) {
136  QDateTime dt(dt2);
137  dt.setTime(QTime(23, 59, 59, 999));
138  end2 = dt.toUTC();
139  } else {
140  end2 = start2;
141  }
142  } else {
143  if (isAllDay1) {
144  end1 = QDateTime(dt1.date(), QTime(23, 59, 59, 999), Qt::LocalTime);
145  } else {
146  end1 = dt1;
147  }
148  if (isAllDay2) {
149  end2 = QDateTime(dt2.date(), QTime(23, 59, 59, 999), Qt::LocalTime);
150  } else {
151  end2 = dt2;
152  }
153  }
154 
155  if (start1 == start2) {
156  return !isAllDay1 ? AtStart
157  : (end1 == end2) ? Equal
158  : (end1 < end2) ? static_cast<DateTimeComparison>(AtStart | Inside)
159  : static_cast<DateTimeComparison>(AtStart | Inside | AtEnd | After);
160  }
161 
162  if (start1 < start2) {
163  return (end1 < start2) ? Before
164  : (end1 == end2) ? static_cast<DateTimeComparison>(Before | AtStart | Inside | AtEnd)
165  : (end1 == start2) ? static_cast<DateTimeComparison>(Before | AtStart)
166  : (end1 < end2) ? static_cast<DateTimeComparison>(Before | AtStart | Inside)
167  : Outside;
168  } else {
169  return (start1 > end2) ? After
170  : (start1 == end2) ? (end1 == end2 ? AtEnd : static_cast<DateTimeComparison>(AtEnd | After))
171  : (end1 == end2) ? static_cast<DateTimeComparison>(Inside | AtEnd)
172  : (end1 < end2) ? Inside
173  : static_cast<DateTimeComparison>(Inside | AtEnd | After);
174  }
175  }
176  return (start1 == start2) ? Equal : (start1 < start2) ? Before : After;
177 }
178 
179 bool KCalendarCore::Events::startDateLessThan(const Event::Ptr &e1, const Event::Ptr &e2)
180 {
181  DateTimeComparison res = compare(e1->dtStart(), e1->allDay(), e2->dtStart(), e2->allDay());
182  if (res == Equal) {
183  return Events::summaryLessThan(e1, e2);
184  } else {
185  return (res & Before || res & AtStart);
186  }
187 }
188 
189 bool KCalendarCore::Events::startDateMoreThan(const Event::Ptr &e1, const Event::Ptr &e2)
190 {
191  DateTimeComparison res = compare(e1->dtStart(), e1->allDay(), e2->dtStart(), e2->allDay());
192  if (res == Equal) {
193  return Events::summaryMoreThan(e1, e2);
194  } else {
195  return (res & After || res & AtEnd);
196  }
197 }
198 
199 bool KCalendarCore::Events::summaryLessThan(const Event::Ptr &e1, const Event::Ptr &e2)
200 {
201  return QString::compare(e1->summary(), e2->summary(), Qt::CaseInsensitive) < 0;
202 }
203 
204 bool KCalendarCore::Events::summaryMoreThan(const Event::Ptr &e1, const Event::Ptr &e2)
205 {
206  return QString::compare(e1->summary(), e2->summary(), Qt::CaseInsensitive) > 0;
207 }
208 
209 bool KCalendarCore::Events::endDateLessThan(const Event::Ptr &e1, const Event::Ptr &e2)
210 {
211  DateTimeComparison res = compare(e1->dtEnd(), e1->allDay(), e2->dtEnd(), e2->allDay());
212  if (res == Equal) {
213  return Events::summaryLessThan(e1, e2);
214  } else {
215  return (res & Before || res & AtStart);
216  }
217 }
218 
219 bool KCalendarCore::Events::endDateMoreThan(const Event::Ptr &e1, const Event::Ptr &e2)
220 {
221  DateTimeComparison res = compare(e1->dtEnd(), e1->allDay(), e2->dtEnd(), e2->allDay());
222  if (res == Equal) {
223  return Events::summaryMoreThan(e1, e2);
224  } else {
225  return (res & After || res & AtEnd);
226  }
227 }
228 
229 bool KCalendarCore::Journals::dateLessThan(const Journal::Ptr &j1, const Journal::Ptr &j2)
230 {
231  DateTimeComparison res = compare(j1->dtStart(), j1->allDay(), j2->dtStart(), j2->allDay());
232  return (res & Before || res & AtStart);
233 }
234 
235 bool KCalendarCore::Journals::dateMoreThan(const Journal::Ptr &j1, const Journal::Ptr &j2)
236 {
237  DateTimeComparison res = compare(j1->dtStart(), j1->allDay(), j2->dtStart(), j2->allDay());
238  return (res & After || res & AtEnd);
239 }
240 
241 bool KCalendarCore::Journals::summaryLessThan(const Journal::Ptr &j1, const Journal::Ptr &j2)
242 {
243  return QString::compare(j1->summary(), j2->summary(), Qt::CaseInsensitive) < 0;
244 }
245 
246 bool KCalendarCore::Journals::summaryMoreThan(const Journal::Ptr &j1, const Journal::Ptr &j2)
247 {
248  return QString::compare(j1->summary(), j2->summary(), Qt::CaseInsensitive) > 0;
249 }
250 
251 bool KCalendarCore::Todos::startDateLessThan(const Todo::Ptr &t1, const Todo::Ptr &t2)
252 {
253  DateTimeComparison res = compare(t1->dtStart(), t1->allDay(), t2->dtStart(), t2->allDay());
254  if (res == Equal) {
255  return Todos::summaryLessThan(t1, t2);
256  } else {
257  return (res & Before || res & AtStart);
258  }
259 }
260 
261 bool KCalendarCore::Todos::startDateMoreThan(const Todo::Ptr &t1, const Todo::Ptr &t2)
262 {
263  DateTimeComparison res = compare(t1->dtStart(), t1->allDay(), t2->dtStart(), t2->allDay());
264  if (res == Equal) {
265  return Todos::summaryMoreThan(t1, t2);
266  } else {
267  return (res & After || res & AtEnd);
268  }
269 }
270 
271 bool KCalendarCore::Todos::dueDateLessThan(const Todo::Ptr &t1, const Todo::Ptr &t2)
272 {
273  if (!t1->hasDueDate() ) {
274  return false;
275  }
276  if (!t2->hasDueDate()) {
277  return true;
278  }
279  DateTimeComparison res = compare(t1->dtDue(), t1->allDay(), t2->dtDue(), t2->allDay());
280  if (res == Equal) {
281  return Todos::summaryLessThan(t1, t2);
282  } else {
283  return (res & Before || res & AtStart);
284  }
285 }
286 
287 bool KCalendarCore::Todos::dueDateMoreThan(const Todo::Ptr &t1, const Todo::Ptr &t2)
288 {
289  if (!t2->hasDueDate()) {
290  return false;
291  }
292  if (!t1->hasDueDate()) {
293  return true;
294  }
295  DateTimeComparison res = compare(t1->dtDue(), t1->allDay(), t2->dtDue(), t2->allDay());
296  if (res == Equal) {
297  return Todos::summaryMoreThan(t1, t2);
298  } else {
299  return (res & After || res & AtEnd);
300  }
301 }
302 
303 bool KCalendarCore::Todos::priorityLessThan(const Todo::Ptr &t1, const Todo::Ptr &t2)
304 {
305  if (t1->priority() < t2->priority()) {
306  return true;
307  } else if (t1->priority() == t2->priority()) {
308  return Todos::summaryLessThan(t1, t2);
309  } else {
310  return false;
311  }
312 }
313 
314 bool KCalendarCore::Todos::priorityMoreThan(const Todo::Ptr &t1, const Todo::Ptr &t2)
315 {
316  if (t1->priority() > t2->priority()) {
317  return true;
318  } else if (t1->priority() == t2->priority()) {
319  return Todos::summaryMoreThan(t1, t2);
320  } else {
321  return false;
322  }
323 }
324 
325 bool KCalendarCore::Todos::percentLessThan(const Todo::Ptr &t1, const Todo::Ptr &t2)
326 {
327  if (t1->percentComplete() < t2->percentComplete()) {
328  return true;
329  } else if (t1->percentComplete() == t2->percentComplete()) {
330  return Todos::summaryLessThan(t1, t2);
331  } else {
332  return false;
333  }
334 }
335 
336 bool KCalendarCore::Todos::percentMoreThan(const Todo::Ptr &t1, const Todo::Ptr &t2)
337 {
338  if (t1->percentComplete() > t2->percentComplete()) {
339  return true;
340  } else if (t1->percentComplete() == t2->percentComplete()) {
341  return Todos::summaryMoreThan(t1, t2);
342  } else {
343  return false;
344  }
345 }
346 
347 bool KCalendarCore::Todos::summaryLessThan(const Todo::Ptr &t1, const Todo::Ptr &t2)
348 {
349  return QString::compare(t1->summary(), t2->summary(), Qt::CaseInsensitive) < 0;
350 }
351 
352 bool KCalendarCore::Todos::summaryMoreThan(const Todo::Ptr &t1, const Todo::Ptr &t2)
353 {
354  return QString::compare(t1->summary(), t2->summary(), Qt::CaseInsensitive) > 0;
355 }
356 
357 bool KCalendarCore::Todos::createdLessThan(const Todo::Ptr &t1, const Todo::Ptr &t2)
358 {
359  DateTimeComparison res = compare(t1->created(), t1->allDay(), t2->created(), t2->allDay());
360  if (res == Equal) {
361  return Todos::summaryLessThan(t1, t2);
362  } else {
363  return (res & Before || res & AtStart);
364  }
365 }
366 
367 bool KCalendarCore::Todos::createdMoreThan(const Todo::Ptr &t1, const Todo::Ptr &t2)
368 {
369  DateTimeComparison res = compare(t1->created(), t1->allDay(), t2->created(), t2->allDay());
370  if (res == Equal) {
371  return Todos::summaryMoreThan(t1, t2);
372  } else {
373  return (res & After || res & AtEnd);
374  }
375 }
376 
377 bool KCalendarCore::Incidences::dateLessThan(const Incidence::Ptr &i1, const Incidence::Ptr &i2)
378 {
379  DateTimeComparison res = compare(i1->dateTime(Incidence::RoleSort), i1->allDay(), i2->dateTime(Incidence::RoleSort), i2->allDay());
380  if (res == Equal) {
381  return Incidences::summaryLessThan(i1, i2);
382  } else {
383  return (res & Before || res & AtStart);
384  }
385 }
386 
387 bool KCalendarCore::Incidences::dateMoreThan(const Incidence::Ptr &i1, const Incidence::Ptr &i2)
388 {
389  DateTimeComparison res = compare(i1->dateTime(Incidence::RoleSort), i1->allDay(), i2->dateTime(Incidence::RoleSort), i2->allDay());
390  if (res == Equal) {
391  return Incidences::summaryMoreThan(i1, i2);
392  } else {
393  return (res & After || res & AtEnd);
394  }
395 }
396 
397 bool KCalendarCore::Incidences::createdLessThan(const Incidence::Ptr &i1, const Incidence::Ptr &i2)
398 {
399  DateTimeComparison res = compare(i1->created(), i1->allDay(), i2->created(), i2->allDay());
400  if (res == Equal) {
401  return Incidences::summaryLessThan(i1, i2);
402  } else {
403  return (res & Before || res & AtStart);
404  }
405 }
406 
407 bool KCalendarCore::Incidences::createdMoreThan(const Incidence::Ptr &i1, const Incidence::Ptr &i2)
408 {
409  DateTimeComparison res = compare(i1->created(), i1->allDay(), i2->created(), i2->allDay());
410  if (res == Equal) {
411  return Incidences::summaryMoreThan(i1, i2);
412  } else {
413  return (res & After || res & AtEnd);
414  }
415 }
416 
417 bool KCalendarCore::Incidences::summaryLessThan(const Incidence::Ptr &i1, const Incidence::Ptr &i2)
418 {
419  return QString::compare(i1->summary(), i2->summary(), Qt::CaseInsensitive) < 0;
420 }
421 
422 bool KCalendarCore::Incidences::summaryMoreThan(const Incidence::Ptr &i1, const Incidence::Ptr &i2)
423 {
424  return QString::compare(i1->summary(), i2->summary(), Qt::CaseInsensitive) > 0;
425 }
426 
427 bool KCalendarCore::Incidences::categoriesLessThan(const Incidence::Ptr &i1, const Incidence::Ptr &i2)
428 {
429  const auto res = QString::compare(i1->categoriesStr(), i2->categoriesStr(), Qt::CaseSensitive);
430  if (res == 0) {
431  return Incidences::summaryLessThan(i1, i2);
432  } else {
433  return res < 0;
434  }
435 }
436 
437 bool KCalendarCore::Incidences::categoriesMoreThan(const Incidence::Ptr &i1, const Incidence::Ptr &i2)
438 {
439  const auto res = QString::compare(i1->categoriesStr(), i2->categoriesStr(), Qt::CaseSensitive);
440  if (res == 0) {
441  return Incidences::summaryMoreThan(i1, i2);
442  } else {
443  return res > 0;
444  }
445 }
QTimeZone timeZone() const const
CaseInsensitive
OffsetFromUTC
Namespace for all KCalendarCore types.
Definition: alarm.h:36
@ RoleSort
Role for an incidence's date/time used when sorting.
QDateTime toUTC() const const
int offsetFromUtc() const const
Qt::TimeSpec timeSpec() const const
QDate date() const const
int compare(const QString &other, Qt::CaseSensitivity cs) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Oct 1 2023 03:58:00 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.