Commit 7b853df5 authored by Volker Krause's avatar Volker Krause

Client-side support for retrieving the ancestor chains of items.

svn path=/trunk/KDE/kdepimlibs/; revision=1009620
parent dfafacfd
......@@ -88,6 +88,18 @@ void ItemFetchJobPrivate::startFetchJob()
command += " " AKONADI_PARAM_ALLATTRIBUTES;
if ( mFetchScope.cacheOnly() )
command += " " AKONADI_PARAM_CACHEONLY;
if ( mFetchScope.ancestorRetrieval() != ItemFetchScope::None ) {
switch ( mFetchScope.ancestorRetrieval() ) {
case ItemFetchScope::Parent:
command += " ANCESTORS 1";
break;
case ItemFetchScope::All:
command += " ANCESTORS INF";
break;
default:
Q_ASSERT( false );
}
}
//TODO: detect somehow if server supports external payload attribute
command += " " AKONADI_PARAM_EXTERNALPAYLOAD;
......@@ -230,6 +242,8 @@ void ItemFetchJob::doHandleResponse( const QByteArray & tag, const QByteArray &
QDateTime datetime;
ImapParser::parseDateTime( fetchResponse[i + 1], datetime );
item.setModificationTime( datetime );
} else if ( key == "ANCESTORS" ) {
ProtocolHelper::parseAncestors( fetchResponse[i + 1], &item );
} else {
int version = 0;
QByteArray plainKey( key );
......
......@@ -107,3 +107,13 @@ void ItemFetchScope::setCacheOnly(bool cacheOnly)
{
d->mCacheOnly = cacheOnly;
}
ItemFetchScope::AncestorRetrieval ItemFetchScope::ancestorRetrieval() const
{
return d->mAncestorDepth;
}
void ItemFetchScope::setAncestorRetrieval( AncestorRetrieval depth )
{
d->mAncestorDepth = depth;
}
......@@ -67,6 +67,16 @@ class ItemFetchScopePrivate;
class AKONADI_EXPORT ItemFetchScope
{
public:
/**
* Describes the ancestor retrieval depth.
* @since 4.4
*/
enum AncestorRetrieval {
None, ///< No ancestor retrieval at all (the default)
Parent, ///< Only retrieve the immediate parent collection
All ///< Retrieve all ancestors, up to Collection::root()
};
/**
* Creates an empty item fetch scope.
*
......@@ -179,6 +189,22 @@ class AKONADI_EXPORT ItemFetchScope
*/
void setCacheOnly( bool cacheOnly );
/**
* Sets how many levels of ancestor collections should be included in the retrieval.
*
* @param ancestorDepth The desired ancestor retrieval depth.
* @since 4.4
*/
void setAncestorRetrieval( AncestorRetrieval ancestorDepth );
/**
* Returns the ancestor retrieval depth.
*
* @see setAncestorRetrieval()
* @since 4.4
*/
AncestorRetrieval ancestorRetrieval() const;
/**
* Returns @c true if there is nothing to fetch.
*/
......
......@@ -22,6 +22,7 @@
#include <QtCore/QSet>
#include <QtCore/QString>
#include "itemfetchscope.h"
namespace Akonadi {
......@@ -31,8 +32,9 @@ namespace Akonadi {
class ItemFetchScopePrivate : public QSharedData
{
public:
ItemFetchScopePrivate()
: mFullPayload( false ),
ItemFetchScopePrivate() :
mAncestorDepth( ItemFetchScope::None ),
mFullPayload( false ),
mAllAttributes( false ),
mCacheOnly( false )
{
......@@ -43,6 +45,7 @@ class ItemFetchScopePrivate : public QSharedData
{
mPayloadParts = other.mPayloadParts;
mAttributes = other.mAttributes;
mAncestorDepth = other.mAncestorDepth;
mFullPayload = other.mFullPayload;
mAllAttributes = other.mAllAttributes;
mCacheOnly = other.mCacheOnly;
......@@ -51,6 +54,7 @@ class ItemFetchScopePrivate : public QSharedData
public:
QSet<QByteArray> mPayloadParts;
QSet<QByteArray> mAttributes;
ItemFetchScope::AncestorRetrieval mAncestorDepth;
bool mFullPayload;
bool mAllAttributes;
bool mCacheOnly;
......
......@@ -79,6 +79,28 @@ QByteArray ProtocolHelper::cachePolicyToByteArray(const CachePolicy & policy)
return rv;
}
void ProtocolHelper::parseAncestors( const QByteArray &data, Entity *entity, int start )
{
QList<QByteArray> ancestors;
ImapParser::parseParenthesizedList( data, ancestors );
Entity* current = entity;
foreach ( const QByteArray &uidRidPair, ancestors ) {
QList<QByteArray> parentIds;
ImapParser::parseParenthesizedList( uidRidPair, parentIds );
if ( parentIds.size() != 2 )
break;
const Collection::Id uid = parentIds.at( 0 ).toLongLong();
const QString rid = QString::fromUtf8( parentIds.at( 1 ) );
if ( uid == Collection::root().id() ) {
current->setParentCollection( Collection::root() );
break;
}
current->parentCollection().setId( uid );
current->parentCollection().setRemoteId( rid );
current = &current->parentCollection();
}
}
int ProtocolHelper::parseCollection(const QByteArray & data, Collection & collection, int start)
{
int pos = start;
......@@ -140,24 +162,7 @@ int ProtocolHelper::parseCollection(const QByteArray & data, Collection & collec
ProtocolHelper::parseCachePolicy( value, policy );
collection.setCachePolicy( policy );
} else if ( key == "ANCESTORS" ) {
QList<QByteArray> ancestors;
ImapParser::parseParenthesizedList( value, ancestors );
Collection* currentCol = &collection;
foreach ( const QByteArray &uidRidPair, ancestors ) {
QList<QByteArray> parentIds;
ImapParser::parseParenthesizedList( uidRidPair, parentIds );
if ( parentIds.size() != 2 )
break;
const Collection::Id uid = parentIds.at( 0 ).toLongLong();
const QString rid = QString::fromUtf8( parentIds.at( 1 ) );
if ( uid == Collection::root().id() ) {
currentCol->setParentCollection( Collection::root() );
break;
}
currentCol->parentCollection().setId( uid );
currentCol->parentCollection().setRemoteId( rid );
currentCol = &currentCol->parentCollection();
}
parseAncestors( value, &collection );
} else {
Attribute* attr = AttributeFactory::createAttribute( key );
Q_ASSERT( attr );
......
......@@ -58,6 +58,11 @@ class ProtocolHelper
*/
static QByteArray cachePolicyToByteArray( const CachePolicy &policy );
/**
Convert a ancestor chain from its protocol representation into an Entity object.
*/
static void parseAncestors( const QByteArray &data, Entity *entity, int start = 0 );
/**
Parse a collection description.
@param data The input data.
......
......@@ -90,7 +90,7 @@ class SessionPrivate
*/
void writeData( const QByteArray &data );
static int minimumProtocolVersion() { return 18; }
static int minimumProtocolVersion() { return 19; }
Session *mParent;
QByteArray sessionId;
......
......@@ -236,3 +236,22 @@ void ItemFetchTest::testRidFetch()
QCOMPARE( item.remoteId(), QString::fromLatin1( "A" ) );
QCOMPARE( item.mimeType(), QString::fromLatin1( "application/octet-stream" ) );
}
void ItemFetchTest::testAncestorRetrieval()
{
ItemFetchJob *job = new ItemFetchJob( Item( 1 ), this );
job->fetchScope().setAncestorRetrieval( ItemFetchScope::All );
AKVERIFYEXEC( job );
QCOMPARE( job->items().count(), 1 );
const Item item = job->items().first();
QVERIFY( item.isValid() );
QCOMPARE( item.remoteId(), QString::fromLatin1( "A" ) );
QCOMPARE( item.mimeType(), QString::fromLatin1( "application/octet-stream" ) );
const Collection c = item.parentCollection();
QCOMPARE( c.remoteId(), QString( "10" ) );
const Collection c2 = c.parentCollection();
QCOMPARE( c2.remoteId(), QString( "6" ) );
const Collection c3 = c2.parentCollection();
QCOMPARE( c3, Collection::root() );
}
\ No newline at end of file
......@@ -33,6 +33,7 @@ class ItemFetchTest : public QObject
void testMultipartFetch_data();
void testMultipartFetch();
void testRidFetch();
void testAncestorRetrieval();
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment