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 <alvaro.manera@nokia.com>
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
16using 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 */
37enum 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 QTimeZone::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
104DateTimeComparison 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), QTimeZone::LocalTime);
145 } else {
146 end1 = dt1;
147 }
148 if (isAllDay2) {
149 end2 = QDateTime(dt2.date(), QTime(23, 59, 59, 999), QTimeZone::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
179bool 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
189bool 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
199bool 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
204bool 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
209bool 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
219bool 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
229bool 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
235bool 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
241bool 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
246bool 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
251bool 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
261bool 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
271bool 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
287bool 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
303bool 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
314bool 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
325bool 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
336bool 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
347bool 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
352bool 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
357bool 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
367bool 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
377bool 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
387bool 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
397bool 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
407bool 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
417bool 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
422bool 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
427bool 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
437bool 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}
Namespace for all KCalendarCore types.
Definition alarm.h:37
QDate date() const const
int offsetFromUtc() const const
Qt::TimeSpec timeSpec() const const
QTimeZone timeZone() const const
QDateTime toUTC() const const
int compare(QLatin1StringView s1, const QString &s2, Qt::CaseSensitivity cs)
CaseInsensitive
OffsetFromUTC
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:47 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.