Akonadi

collectionpathresolver.cpp
1/*
2 SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "collectionpathresolver.h"
8
9#include "collectionfetchjob.h"
10#include "job_p.h"
11
12#include "akonadicore_debug.h"
13
14#include <KLocalizedString>
15
16#include <QStringList>
17
18using namespace Akonadi;
19
20/// @cond PRIVATE
21
22class Akonadi::CollectionPathResolverPrivate : public JobPrivate
23{
24public:
25 explicit CollectionPathResolverPrivate(CollectionPathResolver *parent)
26 : JobPrivate(parent)
27 {
28 }
29
30 void init(const QString &path, const Collection &rootCollection)
31 {
33
34 mPathToId = true;
35 mPath = path;
36 if (mPath.startsWith(q->pathDelimiter())) {
37 mPath = mPath.right(mPath.length() - q->pathDelimiter().length());
38 }
39 if (mPath.endsWith(q->pathDelimiter())) {
40 mPath = mPath.left(mPath.length() - q->pathDelimiter().length());
41 }
42
43 mPathParts = splitPath(mPath);
44 mCurrentNode = rootCollection;
45 }
46
47 void jobResult(KJob *job);
48
49 QStringList splitPath(const QString &path)
50 {
51 if (path.isEmpty()) { // path is normalized, so non-empty means at least one hit
52 return QStringList();
53 }
54
55 QStringList rv;
56 int begin = 0;
57 const int pathSize(path.size());
58 for (int i = 0; i < pathSize; ++i) {
59 if (path[i] == QLatin1Char('/')) {
60 QString pathElement = path.mid(begin, i - begin);
61 pathElement.replace(QLatin1StringView("\\/"), QLatin1StringView("/"));
62 rv.append(pathElement);
63 begin = i + 1;
64 }
65 if (i < path.size() - 2 && path[i] == QLatin1Char('\\') && path[i + 1] == QLatin1Char('/')) {
66 ++i;
67 }
68 }
69 QString pathElement = path.mid(begin);
70 pathElement.replace(QLatin1StringView("\\/"), QLatin1StringView("/"));
71 rv.append(pathElement);
72 return rv;
73 }
74
75 Q_DECLARE_PUBLIC(CollectionPathResolver)
76
77 Collection mCurrentNode;
78 QStringList mPathParts;
79 QString mPath;
80 Collection::Id mColId = -1;
81 bool mPathToId = false;
82};
83
84void CollectionPathResolverPrivate::jobResult(KJob *job)
85{
86 if (job->error()) {
87 return;
88 }
89
91
92 auto list = static_cast<CollectionFetchJob *>(job);
93 CollectionFetchJob *nextJob = nullptr;
94 const Collection::List cols = list->collections();
95 if (cols.isEmpty()) {
96 mColId = -1;
97 q->setError(CollectionPathResolver::Unknown);
98 q->setErrorText(i18n("No such collection."));
99 q->emitResult();
100 return;
101 }
102
103 if (mPathToId) {
104 const QString currentPart = mPathParts.takeFirst();
105 bool found = false;
106 for (const Collection &c : cols) {
107 if (c.name() == currentPart) {
108 mCurrentNode = c;
109 found = true;
110 break;
111 }
112 }
113 if (!found) {
114 qCWarning(AKONADICORE_LOG) << "No such collection" << currentPart << "with parent" << mCurrentNode.id();
115 mColId = -1;
116 q->setError(CollectionPathResolver::Unknown);
117 q->setErrorText(i18n("No such collection."));
118 q->emitResult();
119 return;
120 }
121 if (mPathParts.isEmpty()) {
122 mColId = mCurrentNode.id();
123 q->emitResult();
124 return;
125 }
126 nextJob = new CollectionFetchJob(mCurrentNode, CollectionFetchJob::FirstLevel, q);
127 } else {
128 Collection col = list->collections().at(0);
129 mCurrentNode = col.parentCollection();
130 mPathParts.prepend(col.name());
131 if (mCurrentNode == Collection::root()) {
132 q->emitResult();
133 return;
134 }
135 nextJob = new CollectionFetchJob(mCurrentNode, CollectionFetchJob::Base, q);
136 }
137 q->connect(nextJob, &CollectionFetchJob::result, q, [this](KJob *job) {
138 jobResult(job);
139 });
140}
141
143 : Job(new CollectionPathResolverPrivate(this), parent)
144{
146 d->init(path, Collection::root());
147}
148
149CollectionPathResolver::CollectionPathResolver(const QString &path, const Collection &parentCollection, QObject *parent)
150 : Job(new CollectionPathResolverPrivate(this), parent)
151{
153 d->init(path, parentCollection);
154}
155
157 : Job(new CollectionPathResolverPrivate(this), parent)
158{
160
161 d->mPathToId = false;
162 d->mColId = collection.id();
163 d->mCurrentNode = collection;
164}
165
167{
168}
169
171{
173
174 return d->mColId;
175}
176
178{
180
181 if (d->mPathToId) {
182 return d->mPath;
183 }
184 return d->mPathParts.join(pathDelimiter());
185}
186
188{
189 return QStringLiteral("/");
190}
191
193{
195
196 CollectionFetchJob *job = nullptr;
197 if (d->mPathToId) {
198 if (d->mPath.isEmpty()) {
199 d->mColId = Collection::root().id();
200 emitResult();
201 return;
202 }
203 job = new CollectionFetchJob(d->mCurrentNode, CollectionFetchJob::FirstLevel, this);
204 } else {
205 if (d->mColId == 0) {
206 d->mColId = Collection::root().id();
207 emitResult();
208 return;
209 }
210 job = new CollectionFetchJob(d->mCurrentNode, CollectionFetchJob::Base, this);
211 }
212 connect(job, &CollectionFetchJob::result, this, [d](KJob *job) {
213 d->jobResult(job);
214 });
215}
216
217/// @endcond
218
219#include "moc_collectionpathresolver.cpp"
Job that fetches collections from the Akonadi storage.
@ FirstLevel
Only list direct sub-collections of the base collection.
@ Base
Only fetch the base collection.
Collection::Id collection() const
Returns the collection id.
static QString pathDelimiter()
Returns the path delimiter for collections.
QString path() const
Returns the collection path.
CollectionPathResolver(const QString &path, QObject *parent=nullptr)
Creates a new collection path resolver to convert a path into a id.
~CollectionPathResolver() override
Destroys the collection path resolver.
void doStart() override
This method must be reimplemented in the concrete jobs.
Represents a collection of PIM items.
Definition collection.h:62
qint64 Id
Describes the unique id type.
Definition collection.h:79
static Collection root()
Returns the root collection.
Collection parentCollection() const
Returns the parent collection of this object.
Base class for all actions in the Akonadi storage.
Definition job.h:81
void emitResult()
int error() const
void result(KJob *job)
QString i18n(const char *text, const TYPE &arg...)
Helper integration between Akonadi and Qt.
QString path(const QString &relativePath)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
const QList< QKeySequence > & begin()
QCA_EXPORT void init()
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
bool isEmpty() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool isEmpty() const const
QString left(qsizetype n) const const
QString mid(qsizetype position, qsizetype n) const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QString right(qsizetype n) const const
qsizetype size() const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:38 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.