At this stage it is already possible to compile the application, 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 top level 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 top level 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 main Qt Designer file

Open the file detacherview_base.ui in Qt Designer and remove the example label.
Remove the widget's main layout by clicking on the now empty widget and use the Break Layout menu entry in the Form menu.

Now, from left to right, place two Tree Views and one List Widget side-by-side.
Select all three boxes by holding SHIFT and clicking each box with the left mouse button.
Use Layout Horizontally in a Splitter in the Form menu and then create a main layout by clicking on their parent widget and using Layout Vertically in the Form menu.

A preview (Form -> Preview) should now look like this:

Finally, change the object names for the three widgets by right clicking it and choosing Change objectName. The left widget should be named folderView, the middle one messageView and the right one attachmentList.

In order to make it build again, edit the file detacherview.cpp and remove the code from the settingsChanged method.
The application should now build again and be able to run.

Note

A lot of other code of this generated files is not necessary either, feel free to do more cleanup yourself.

Promoting Views

The KDE client library for Akonadi has a couple of convenience classes which make our life as application developers more pleasant.
Two of these classes are specialized view widgets, one for displaying collections and one for displaying items.

In order to use these widgets instead of ones from Qt we need to use a Qt Designer feature called "promoting".
Right click the left widget and choose Promote to. Then fill the form like shown in the next screenshot.

Click add and promote. Repeat the same for the middle widget, this time using Akonadi::ItemView as the class name and akonadi/itemview.h for the header file.

This change also requires a change in the CMakeLists.txt file in the top level directory and in the one from the source directory.

In the file from the top level directory add the following line
find_package (KdepimLibs REQUIRED)

Initialization

Since the application will depend on Akonadi running, we can ensure this by starting it if it is not.
This is handled by the Akonadi::Control class.

In detacher.h we add another slot called delayedInit() which will perform this initialization.
A slot so we can delay its executing using a single shot timer, a technique called "Delayed Initialization", i.e. letting the application create and show its GUI as fast as possible and do any probably time consuming initialization after that.

private slots:

void fileNew();
void optionsPreferences();
void delayedInit();

In detacher.cpp we need two new include directives:

include <QtCore/QTimer>

include <akonadi/control.h>

and the slot's implementation
void Detacher::delayedInit()
{

if ( !Akonadi::Control::start( this ) ) {
qApp->exit( -1 );
return;
}

}

If the application fails to start Akonadi, it simply quits. A real application should probably tell the user about that though.

Since we want the slot to be executed delayed, add the following line at the end of the class' constructor

QTimer::singleShot( 0, this, SLOT( delayedInit() ) );

Lets add a new public method to the view class. In detacherview.h add

void createModels();

and for now with an empty body in detacherview.cpp (we will get to the implementation shortly)
void DetacherView::createModels()
{
}

and call it from Detacher::delayedInit() after the Akonadi start succeeded

void Detacher::delayedInit()
{

if ( !Akonadi::Control::start( this ) ) {
qApp->exit( -1 );
return;
}

m_view->createModels();

}

Connecting Views to Akonadi

The actual data connection between our views and Akonadi is conveniently handled by specialized models which are also provided by the KDE client library for Akonadi.

Actually, the data type the application will be working on, MIME messages, has an even further specialized model in a type specific sub library.

The first line creates a CollectionModel which will get all "folders" from Akonadi and keep this data updated as long as the application is running.

However, since this includes collections for other data types as well, we need to filter for the data type we are interested in, MIME messages or in terms of MIME type message/rfc822.
This kind of filtering is conveniently supplied in the form of a proxy model called CollectionFilterProxyModel.

Setting the models on the respective view almost completes the setup process, the only thing left is to connect the CollectionView to the MessageModel so it changes its data depending on which folder gets selected.

At this stage the application is already capable of showing all your mail folders and headers of all your e-mails!

Getting at the Attachments

This task can be split into two steps:

Getting the message from Akonadi

Getting the attachments from the message

Getting the message from Akonadi

While we could have instructed the MessageModel to get all data for each of its entries, the proper way is to retrieve it only for the items that get selected.
Moreover we want to do this asynchronously because we don't want to block the application even is a message is really huge.

The KDE client library for Akonadi offers this kind of functionality through a job-based API, in this case ItemFetchJob.

Using this is quite simple. First we add a new include and a class forward declaration for detacherview.h

Exercise: Instead of using a QListView and simple strings, a model working on the single item would make the application a lot cleaner.

Detaching an Attachment

This task can again be split into sub tasks:

Saving the selected attachment into a file

Removing the selected attachment from the message

Saving Attachment into File

First we need a new slot in the private slots section of detacherview.h

void detachAttachment();

To implement the first sub task, saving the selected attachment into a file, the following new includes are needed in detacherview.cpp

include <kaction.h>

include <kfiledialog.h>

include <kstandardaction.h>

In the class' constructor create and connect an action and make it available as the attachment list widget's context menu:
KAction *detachAction = KStandardAction::cut( this, SLOT( detachAttachment() ), this );
detachAction->setText( i18nc( "@action:button remove an attachment from an email",