1/*
2 Copyright (c) 2007 Volker Krause <vkrause@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#include "collectionpathresolver_p.h"
21
22#include "collectionfetchjob.h"
23#include "job_p.h"
24
25#include <klocalizedstring.h>
26
27#include <QtCore/QStringList>
28
29using namespace Akonadi;
30
31//@cond PRIVATE
32
33class Akonadi::CollectionPathResolverPrivate : public JobPrivate
34{
35public:
36 CollectionPathResolverPrivate(CollectionPathResolver *parent)
37 : JobPrivate(parent)
38 , mColId(-1)
39 {
40 }
41
42 void init(const QString &path, const Collection &rootCollection)
43 {
44 Q_Q(CollectionPathResolver);
45
46 mPathToId = true;
47 mPath = path;
48 if (mPath.startsWith(q->pathDelimiter())) {
49 mPath = mPath.right(mPath.length() - q->pathDelimiter().length());
50 }
51 if (mPath.endsWith(q->pathDelimiter())) {
52 mPath = mPath.left(mPath.length() - q->pathDelimiter().length());
53 }
54
55 mPathParts = splitPath(mPath);
56 mCurrentNode = rootCollection;
57 }
58
59 void jobResult(KJob *);
60
61 QStringList splitPath(const QString &path)
62 {
63 if (path.isEmpty()) { // path is normalized, so non-empty means at least one hit
64 return QStringList();
65 }
66
67 QStringList rv;
68 int begin = 0;
69 const int pathSize(path.size());
70 for (int i = 0; i < pathSize; ++i) {
71 if (path[i] == QLatin1Char('/')) {
72 QString pathElement = path.mid(begin, i - begin);
73 pathElement = pathElement.replace(QLatin1String("\\/"), QLatin1String("/"));
74 rv.append(pathElement);
75 begin = i + 1;
76 }
77 if (i < path.size() - 2 && path[i] == QLatin1Char('\\') && path[i + 1] == QLatin1Char('/')) {
78 ++i;
79 }
80 }
81 QString pathElement = path.mid(begin);
82 pathElement = pathElement.replace(QLatin1String("\\/"), QLatin1String("/"));
83 rv.append(pathElement);
84 return rv;
85 }
86
87 Q_DECLARE_PUBLIC(CollectionPathResolver)
88
89 Collection::Id mColId;
90 QString mPath;
91 bool mPathToId;
92 QStringList mPathParts;
93 Collection mCurrentNode;
94};
95
96void CollectionPathResolverPrivate::jobResult(KJob *job)
97{
98 if (job->error()) {
99 return;
100 }
101
102 Q_Q(CollectionPathResolver);
103
104 CollectionFetchJob *list = static_cast<CollectionFetchJob *>(job);
105 CollectionFetchJob *nextJob = 0;
106 const Collection::List cols = list->collections();
107 if (cols.isEmpty()) {
108 mColId = -1;
109 q->setError(CollectionPathResolver::Unknown);
110 q->setErrorText(i18n("No such collection."));
111 q->emitResult();
112 return;
113 }
114
115 if (mPathToId) {
116 const QString currentPart = mPathParts.takeFirst();
117 bool found = false;
118 foreach (const Collection &c, cols) {
119 if (c.name() == currentPart) {
120 mCurrentNode = c;
121 found = true;
122 break;
123 }
124 }
125 if (!found) {
126 kWarning() << "No such collection" << currentPart << "with parent" << mCurrentNode.id();
127 mColId = -1;
128 q->setError(CollectionPathResolver::Unknown);
129 q->setErrorText(i18n("No such collection."));
130 q->emitResult();
131 return;
132 }
133 if (mPathParts.isEmpty()) {
134 mColId = mCurrentNode.id();
135 q->emitResult();
136 return;
137 }
138 nextJob = new CollectionFetchJob(mCurrentNode, CollectionFetchJob::FirstLevel, q);
139 } else {
140 Collection col = list->collections().first();
141 mCurrentNode = col.parentCollection();
142 mPathParts.prepend(col.name());
143 if (mCurrentNode == Collection::root()) {
144 q->emitResult();
145 return;
146 }
147 nextJob = new CollectionFetchJob(mCurrentNode, CollectionFetchJob::Base, q);
148 }
149 q->connect(nextJob, SIGNAL(result(KJob*)), q, SLOT(jobResult(KJob*)));
150}
151
152CollectionPathResolver::CollectionPathResolver(const QString &path, QObject *parent)
153 : Job(new CollectionPathResolverPrivate(this), parent)
154{
155 Q_D(CollectionPathResolver);
156 d->init(path, Collection::root());
157}
158
159CollectionPathResolver::CollectionPathResolver(const QString &path, const Collection &parentCollection, QObject *parent)
160 : Job(new CollectionPathResolverPrivate(this), parent)
161{
162 Q_D(CollectionPathResolver);
163 d->init(path, parentCollection);
164}
165
166CollectionPathResolver::CollectionPathResolver(const Collection &collection, QObject *parent)
167 : Job(new CollectionPathResolverPrivate(this), parent)
168{
169 Q_D(CollectionPathResolver);
170
171 d->mPathToId = false;
172 d->mColId = collection.id();
173 d->mCurrentNode = collection;
174}
175
176CollectionPathResolver::~CollectionPathResolver()
177{
178}
179
180Collection::Id CollectionPathResolver::collection() const
181{
182 Q_D(const CollectionPathResolver);
183
184 return d->mColId;
185}
186
187QString CollectionPathResolver::path() const
188{
189 Q_D(const CollectionPathResolver);
190
191 if (d->mPathToId) {
192 return d->mPath;
193 }
194 return d->mPathParts.join(pathDelimiter());
195}
196
197QString CollectionPathResolver::pathDelimiter()
198{
199 return QLatin1String("/");
200}
201
202void CollectionPathResolver::doStart()
203{
204 Q_D(CollectionPathResolver);
205
206 CollectionFetchJob *job = 0;
207 if (d->mPathToId) {
208 if (d->mPath.isEmpty()) {
209 d->mColId = Collection::root().id();
210 emitResult();
211 return;
212 }
213 job = new CollectionFetchJob(d->mCurrentNode, CollectionFetchJob::FirstLevel, this);
214 } else {
215 if (d->mColId == 0) {
216 d->mColId = Collection::root().id();
217 emitResult();
218 return;
219 }
220 job = new CollectionFetchJob(d->mCurrentNode, CollectionFetchJob::Base, this);
221 }
222 connect(job, SIGNAL(result(KJob*)), SLOT(jobResult(KJob*)));
223}
224
225//@endcond
226
227#include "moc_collectionpathresolver_p.cpp"
228