At this stage it is already possible to compile the resource, so we can already check if our development environment is setup correctly by creating the build directory and having CMake either generate Makefiles or a KDevelop project file.

Generating Makefiles

From within the generated source directory:
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=debugfull ..
and run the build using make as usual.

Generating a KDevelop project file

From within the generated source directory:
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=debugfull -G KDevelop3 ..
and open the generated project with KDevelop and run the build process from there.

Adjusting the resource description file

The capabilities of the resource need to be described in both human understable and machine interpretable form.
This is achieved through a so-called desktop file, similar to those installed by applications.

Since the vcarddirresource.desktop file generated by KAppTemplate contains only example values, we need to edit it:

Name and Comment are strings visible to the user and can be translated. Since our resource will serve contact data, the example valued for Icon and X-Akonadi-MimeTypes fields are conveniently correct.

Resource Configuration

Since the backend of our resource will be a file system directory, we need a way to let the user configure it and a way to persistantly store this configuration.

KDE has a nice framework for this called KConfig XT which enabled us developers to specify our config options as an XML file and have the code for storage and retrieval auto-generated.

The template we are basing our resource on already contains such a file, vcarddirresource.kcfg, and we only have to add a new option for our base directory:
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"

To enable the user to change this properties, we need to create and show a config dialog. Since we are using KConfig XT this is pretty easy, but for the scope of this tutorial we make our lives even more easier and just use a KFileDialog

First we need to add two new include directives at the beginning of our source file vcarddirresource.cpp:

include <kfiledialog.h>

include <klocalizedstring.h>

To show the dialog on the user's request, we need to modify the resource method configure which currently has an empty implementations.
void VCardDirResource::configure( WId windowId )
{

The code creates a top level collection, i.e. its parent collection is Akonadi's root collection, sets the configured path as its remote identifier (so we could eventually map it back to our "backend" location) and uses our resource name as the user visible collection name.

Since our resource will be providing contact data, we need to set the respective MIME type to indicate which kind of data our collection will hold.

Finally the fully set up collection is sent to Akonadi.

Retrieving Items

Retrieving items for a specific collection is similar to listing the files of a specific directory.
Conveniently our backend is a directory, so we can map this directly.

There are several methods to implement item retrieval, e.g. synchronous or asynchronous, all items in one go or in patches, etc.
For the scope of the tutorial we choose the easiest combination, i.e. synchronously provide all items in one go.

Our earlier decision to use the directory's path as the collection's remote identifier conveniently allows us to retrieve the path from the given collection.

We then list all vCard files in that directory and create one Akonadi item for each one, this time using the path plus the file's name as the remote identifier.

Note

This rather primitive implementation assumes that all files with the extension vcf are indeed vCard files and contain only one vCard each.

Finally the whole list of items is sent to Akonadi.

Retrieving Item Data

Continuing our file system analogy, retrieving a specific item's data is similar to reading a specific file's data or its associated meta data.
So we have again the convenience of a direct mapping between Akonadi and backend functionality.

Since our backend items are vCard files, we need to parse them into data structures which we can then use as item payloads.

And additionally we need to edit CMakeLists.txt to make it link the library for the KABC classes:
target_link_libraries(akonadi_vcarddir_resource ${KDE4_AKONADI_LIBS} ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${KDE4_KDECORE_LIBS} ${KDE4_KABC_LIBS})

Again aided by our decision what to use as the item's remote identifier, we can directly use it to open the respective vCard file.
After parsing the data we create a new item object, use the given item to initialize it, set the contact data object as its payload and send it to Akonadi.

Note

Since we need the full vCard data for parsing, we ignore the parts parameter and always retrieve the full payload.

Item Changes

All Akonadi clients, e.g. end user applications, agents, etc., can at any time add items to collections, change item data and remove items from collections. If such a change happens in the collection tree of a resource, the resource should properly make the respective change on its backend.

As usual we get the path of the directory a specific collection maps to from the collection's remote identifier.

Then we check if the newly added item is already equiped with a payload, in our case a KABC::Addressee object.
In either case we ensure that the object has an unique identifier by which we then use as the base name for the vCard file.

Finally we let Akonadi know that we have processed the item change and which remote identifier our backend has assigned to it.

Modifying Items

In our case handling item modifications is almost the same as handling item adding, however more sophisticated resource will most likely do different things depending on the parts parameter.

Removing Items

Since we have a one-to-one mapping of items to files, an item removal is as simple as removing the respective file:

void VCardDirResource::itemRemoved( const Akonadi::Item &item )
{

Q_UNUSED( item );

const QString fileName = item.remoteId();

QFile::remove( fileName );

changeCommitted( item );

}

Backend Changes

Of course changes to collections and items might also happen on the backend and in cases where the backend can send out change notifications, the resource can map these changes directly into its collection tree.

The APIs for that are exactly the same which any other client would use, i.e. Akonadi's job classes.

Tip

Exercise: Use KDirWatch to get notified about file and directory changes and modify the Akonadi storage accordingly.

Testing

This section needs improvements: Please help us to

cleanup confusing sections and
fix sections which contain a todo

Describe basic setup for manual testing. Link to tutorial about using the test suite Igor Trindade Oliveira is working on as a GSoC project.