1/*
2 This file is part of the Nepomuk KDE project.
3 SPDX-FileCopyrightText: 2010 Sebastian Trueg <trueg@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6*/
7
8#include "timelinetools.h"
9#include "kio_timeline_debug.h"
10
11#include <QRegularExpression>
12#include <QUrlQuery>
13
14namespace
15{
16QDate applyRelativeDateModificators(const QDate& date, const QMap<QString, QString>& modificators)
17{
18 QDate newDate(date);
19 const QString dayKey = QStringLiteral("relDays");
20 const QString weekKey = QStringLiteral("relWeeks");
21 const QString monthKey = QStringLiteral("relMonths");
22 const QString yearKey = QStringLiteral("relYears");
23 bool ok = false;
24
25 if (modificators.contains(key: yearKey)) {
26 int relYears = modificators[yearKey].toInt(ok: &ok);
27 if (ok) {
28 newDate = newDate.addYears(years: relYears);
29 }
30 }
31 if (modificators.contains(key: monthKey)) {
32 int relMonths = modificators[monthKey].toInt(ok: &ok);
33 if (ok) {
34 newDate = newDate.addMonths(months: relMonths);
35 }
36 }
37 if (modificators.contains(key: weekKey)) {
38 int relWeeks = modificators[weekKey].toInt(ok: &ok);
39 if (ok) {
40 newDate = newDate.addDays(days: relWeeks * 7); // we assume weeks have 7 days everywhere. QDate seems to make that assumption too, should be OK.
41 }
42 }
43 if (modificators.contains(key: dayKey)) {
44 int relDays = modificators[dayKey].toInt(ok: &ok);
45 if (ok) {
46 newDate = newDate.addDays(days: relDays);
47 }
48 }
49 return newDate;
50}
51}
52
53QUrl Baloo::canonicalizeTimelineUrl(const QUrl& url) {
54 QUrl newUrl = url;
55 QString path = url.path();
56 if (path.contains(s: QLatin1String("//"))) {
57 QStringList sections = path.split(sep: QLatin1Char('/'), behavior: Qt::SkipEmptyParts);
58 path = QLatin1Char('/') + sections.join(sep: QLatin1Char('/'));
59 newUrl.setPath(path);
60 }
61 if ((path.size() > 1) && path.endsWith(c: QLatin1Char('/'))) {
62 path.chop(n: 1);
63 newUrl.setPath(path);
64 }
65 if (!path.startsWith(c: QLatin1Char('/'))) {
66 path = QLatin1Char('/') + path;
67 newUrl.setPath(path);
68 }
69 return newUrl;
70}
71
72Baloo::TimelineFolderType Baloo::parseTimelineUrl(const QUrl& url, QDate* date, QString* filename)
73{
74 qCDebug(KIO_TIMELINE) << url;
75
76 static const QRegularExpression s_dateRegexp(
77 QRegularExpression::anchoredPattern(QStringLiteral("\\d{4}-\\d{2}(?:-(\\d{2}))?")));
78
79 // reset
80 *date = QDate();
81
82 QString path = url.path();
83 if (path.endsWith(c: QLatin1Char('/'))) {
84 path.chop(n: 1);
85 }
86
87 if (path.isEmpty()) {
88 qCDebug(KIO_TIMELINE) << url << "is root folder";
89 return RootFolder;
90 } else if (path.startsWith(s: QLatin1String("/today"))) {
91 *date = QDate::currentDate();
92 if (filename) {
93 *filename = path.mid(position: 7);
94 }
95 qCDebug(KIO_TIMELINE) << url << "is today folder:" << *date;
96 return DayFolder;
97 } else if (path == QLatin1String("/calendar")) {
98 qCDebug(KIO_TIMELINE) << url << "is calendar folder";
99 return CalendarFolder;
100 } else {
101 QStringList sections = path.split(QStringLiteral("/"), behavior: Qt::SkipEmptyParts);
102 QString dateString;
103 QRegularExpressionMatch match = s_dateRegexp.match(subject: sections.last());
104 if (match.hasMatch()) {
105 dateString = sections.last();
106 } else if (sections.count() > 1
107 && (match = s_dateRegexp.match(subject: sections[sections.count() - 2])).hasMatch()) {
108 dateString = sections[sections.count() - 2];
109 if (filename) {
110 *filename = sections.last();
111 }
112 } else {
113 qCWarning(KIO_TIMELINE) << url << "COULD NOT PARSE";
114 return NoFolder;
115 }
116
117 if (match.captured(nth: 1).isEmpty()) {
118 // no day -> month listing
119 qCDebug(KIO_TIMELINE) << "parsing " << dateString;
120 *date = QDate::fromString(string: dateString, QStringLiteral("yyyy-MM"));
121 qCDebug(KIO_TIMELINE) << url << "is month folder:" << date->month() << date->year();
122 if (date->month() > 0 && date->year() > 0) {
123 return MonthFolder;
124 }
125 } else {
126 qCDebug(KIO_TIMELINE) << "parsing " << dateString;
127 typedef QPair<QString, QString> StringPair;
128 QUrlQuery query(url);
129 const QList<StringPair> queryItems = query.queryItems();
130 QMap<QString, QString> map;
131 for (const StringPair& pair : queryItems) {
132 map.insert(key: pair.first, value: pair.second);
133 }
134
135 *date = applyRelativeDateModificators(date: QDate::fromString(string: dateString, QStringLiteral("yyyy-MM-dd")), modificators: map);
136 // only in day folders we can have filenames
137 qCDebug(KIO_TIMELINE) << url << "is day folder:" << *date;
138 if (date->isValid()) {
139 return DayFolder;
140 }
141 }
142 }
143
144 return NoFolder;
145}
146

source code of baloo/src/kioworkers/timeline/timelinetools.cpp