• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepimlibs API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • sources
  • kde-4.14
  • kdepimlibs
  • akonadi
recursivemover.cpp
1 /*
2  Copyright (c) 2012 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 "recursivemover_p.h"
21 #include "collectionfetchjob.h"
22 #include "itemfetchjob.h"
23 #include "itemfetchscope.h"
24 #include "collectionfetchscope.h"
25 
26 using namespace Akonadi;
27 
28 RecursiveMover::RecursiveMover(AgentBasePrivate *parent)
29  : KCompositeJob(parent)
30  , m_agentBase(parent)
31  , m_currentAction(None)
32  , m_runningJobs(0)
33  , m_pendingReplay(false)
34 {
35 }
36 
37 void RecursiveMover::start()
38 {
39  Q_ASSERT(receivers(SIGNAL(result(KJob*))));
40 
41  CollectionFetchJob *job = new CollectionFetchJob(m_movedCollection, CollectionFetchJob::Recursive, this);
42  connect(job, SIGNAL(finished(KJob*)), SLOT(collectionListResult(KJob*)));
43  addSubjob(job);
44  ++m_runningJobs;
45 }
46 
47 void RecursiveMover::setCollection(const Collection &collection, const Collection &parentCollection)
48 {
49  m_movedCollection = collection;
50  m_collections.insert(collection.id(), m_movedCollection);
51  m_collections.insert(parentCollection.id(), parentCollection);
52 }
53 
54 void RecursiveMover::collectionListResult(KJob *job)
55 {
56  Q_ASSERT(m_pendingCollections.isEmpty());
57  --m_runningJobs;
58 
59  if (job->error()) {
60  return; // error handling is in the base class
61  }
62 
63  // build a parent -> children map for the following topological sorting
64  // while we are iterating anyway, also fill m_collections here
65  CollectionFetchJob *fetchJob = qobject_cast<CollectionFetchJob *>(job);
66  QHash<Collection::Id, Collection::List> colTree;
67  foreach (const Collection &col, fetchJob->collections()) {
68  colTree[col.parentCollection().id()] << col;
69  m_collections.insert(col.id(), col);
70  }
71 
72  // topological sort; BFS traversal of the tree
73  m_pendingCollections.push_back(m_movedCollection);
74  QQueue<Collection> toBeProcessed;
75  toBeProcessed.enqueue(m_movedCollection);
76  while (!toBeProcessed.isEmpty()) {
77  const Collection col = toBeProcessed.dequeue();
78  const Collection::List children = colTree.value(col.id());
79  if (children.isEmpty()) {
80  continue;
81  }
82  m_pendingCollections.append(children);
83  foreach (const Collection &child, children) {
84  toBeProcessed.enqueue(child);
85  }
86  }
87 
88  replayNextCollection();
89 }
90 
91 void RecursiveMover::collectionFetchResult(KJob *job)
92 {
93  Q_ASSERT(m_currentCollection.isValid());
94  --m_runningJobs;
95 
96  if (job->error()) {
97  return; // error handling is in the base class
98  }
99 
100  CollectionFetchJob *fetchJob = qobject_cast<CollectionFetchJob *>(job);
101  if (fetchJob->collections().size() == 1) {
102  m_currentCollection = fetchJob->collections().first();
103  m_currentCollection.setParentCollection(m_collections.value(m_currentCollection.parentCollection().id()));
104  m_collections.insert(m_currentCollection.id(), m_currentCollection);
105  } else {
106  // already deleted, move on
107  }
108 
109  if (!m_runningJobs && m_pendingReplay) {
110  replayNext();
111  }
112 }
113 
114 void RecursiveMover::itemListResult(KJob *job)
115 {
116  --m_runningJobs;
117 
118  if (job->error()) {
119  return; // error handling is in the base class
120  }
121 
122  foreach (const Item &item, qobject_cast<ItemFetchJob *>(job)->items()) {
123  if (item.remoteId().isEmpty()) {
124  m_pendingItems.push_back(item);
125  }
126  }
127 
128  if (!m_runningJobs && m_pendingReplay) {
129  replayNext();
130  }
131 }
132 
133 void RecursiveMover::itemFetchResult(KJob *job)
134 {
135  Q_ASSERT(m_currentAction == None);
136  --m_runningJobs;
137 
138  if (job->error()) {
139  return; // error handling is in the base class
140  }
141 
142  ItemFetchJob *fetchJob = qobject_cast<ItemFetchJob *>(job);
143  if (fetchJob->items().size() == 1) {
144  m_currentAction = AddItem;
145  m_agentBase->itemAdded(fetchJob->items().first(), m_currentCollection);
146  } else {
147  // deleted since we started, skip
148  m_currentItem = Item();
149  replayNextItem();
150  }
151 }
152 
153 void RecursiveMover::replayNextCollection()
154 {
155  if (!m_pendingCollections.isEmpty()) {
156 
157  m_currentCollection = m_pendingCollections.takeFirst();
158  ItemFetchJob *job = new ItemFetchJob(m_currentCollection, this);
159  connect(job, SIGNAL(result(KJob*)), SLOT(itemListResult(KJob*)));
160  addSubjob(job);
161  ++m_runningJobs;
162 
163  if (m_currentCollection.remoteId().isEmpty()) {
164  Q_ASSERT(m_currentAction == None);
165  m_currentAction = AddCollection;
166  m_agentBase->collectionAdded(m_currentCollection, m_collections.value(m_currentCollection.parentCollection().id()));
167  return;
168  } else {
169  //replayNextItem(); - but waiting for the fetch job to finish first
170  m_pendingReplay = true;
171  return;
172  }
173  } else {
174  // nothing left to do
175  emitResult();
176  }
177 }
178 
179 void RecursiveMover::replayNextItem()
180 {
181  Q_ASSERT(m_currentCollection.isValid());
182  if (m_pendingItems.isEmpty()) {
183  replayNextCollection(); // all items processed here
184  return;
185  } else {
186  Q_ASSERT(m_currentAction == None);
187  m_currentItem = m_pendingItems.takeFirst();
188  ItemFetchJob *job = new ItemFetchJob(m_currentItem, this);
189  job->fetchScope().fetchFullPayload();
190  connect(job, SIGNAL(result(KJob*)), SLOT(itemFetchResult(KJob*)));
191  addSubjob(job);
192  ++m_runningJobs;
193  }
194 }
195 
196 void RecursiveMover::changeProcessed()
197 {
198  Q_ASSERT(m_currentAction != None);
199 
200  if (m_currentAction == AddCollection) {
201  Q_ASSERT(m_currentCollection.isValid());
202  CollectionFetchJob *job = new CollectionFetchJob(m_currentCollection, CollectionFetchJob::Base, this);
203  job->fetchScope().setAncestorRetrieval(CollectionFetchScope::All);
204  connect(job, SIGNAL(result(KJob*)), SLOT(collectionFetchResult(KJob*)));
205  addSubjob(job);
206  ++m_runningJobs;
207  }
208 
209  m_currentAction = None;
210 }
211 
212 void RecursiveMover::replayNext()
213 {
214  // wait for runnings jobs to finish before actually doing the replay
215  if (m_runningJobs) {
216  m_pendingReplay = true;
217  return;
218  }
219 
220  m_pendingReplay = false;
221 
222  if (m_currentCollection.isValid()) {
223  replayNextItem();
224  } else {
225  replayNextCollection();
226  }
227 }
228 
229 #include "moc_recursivemover_p.cpp"
Akonadi::CollectionFetchJob::collections
Collection::List collections() const
Returns the list of fetched collection.
Definition: collectionfetchjob.cpp:169
QQueue
QList::push_back
void push_back(const T &value)
QQueue::enqueue
void enqueue(const T &t)
Akonadi::Collection
Represents a collection of PIM items.
Definition: collection.h:75
QQueue::dequeue
T dequeue()
Akonadi::CollectionFetchJob
Job that fetches collections from the Akonadi storage.
Definition: collectionfetchjob.h:53
Akonadi::RecursiveMover::changeProcessed
void changeProcessed()
Call once the last replayed change has been processed.
Definition: recursivemover.cpp:196
Akonadi::Entity::setParentCollection
void setParentCollection(const Collection &parent)
Set the parent collection of this object.
Definition: entity.cpp:194
Akonadi::ItemFetchScope::fetchFullPayload
void fetchFullPayload(bool fetch=true)
Sets whether the full payload shall be fetched.
Definition: itemfetchscope.cpp:70
QList::size
int size() const
Akonadi::AgentBasePrivate
Definition: agentbase_p.h:39
Akonadi::ItemFetchJob::items
Item::List items() const
Returns the fetched items.
Definition: itemfetchjob.cpp:233
Akonadi::CollectionFetchJob::Base
Only fetch the base collection.
Definition: collectionfetchjob.h:62
QList::value
T value(int i) const
Akonadi::ItemFetchJob::fetchScope
ItemFetchScope & fetchScope()
Returns the item fetch scope.
Definition: itemfetchjob.cpp:261
QList::append
void append(const T &value)
Akonadi::Entity::parentCollection
Collection parentCollection() const
Returns the parent collection of this object.
Definition: entity.cpp:185
QHash
Akonadi::Entity::remoteId
QString remoteId() const
Returns the remote id of the entity.
Definition: entity.cpp:82
QList::isEmpty
bool isEmpty() const
QString::isEmpty
bool isEmpty() const
Akonadi::CollectionFetchScope::All
Retrieve all ancestors, up to Collection::root()
Definition: collectionfetchscope.h:77
QList::first
T & first()
QList
Akonadi::Entity::id
Id id() const
Returns the unique identifier of the entity.
Definition: entity.cpp:72
QList::takeFirst
T takeFirst()
Akonadi::RecursiveMover::setCollection
void setCollection(const Akonadi::Collection &collection, const Akonadi::Collection &parentCollection)
Set the collection that is actually moved.
Definition: recursivemover.cpp:47
Akonadi::ItemFetchJob
Job that fetches items from the Akonadi storage.
Definition: itemfetchjob.h:82
Akonadi::Entity::isValid
bool isValid() const
Returns whether the entity is valid.
Definition: entity.cpp:97
Akonadi::RecursiveMover::replayNext
void replayNext()
Trigger the next change replay, will call emitResult() once everything has been replayed.
Definition: recursivemover.cpp:212
Akonadi::CollectionFetchJob::Recursive
List all sub-collections.
Definition: collectionfetchjob.h:64
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:38:03 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs API Reference

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal