Warning, /pim/akonadi/docs/client_libraries.md is written in an unsupported language. File is not indexed.

0001 # Akonadi client libraries # {#client_libraries}
0002 
0003 [TOC]
0004 
0005 Akonadi client libraries consist of three libraries that provide tools to access
0006 the Akonadi PIM data server: AkonadiCore, AkonadiWidgets and AkonadiAgentBase.
0007 All processes accessing Akonadi, including those which communicate with a remote
0008 server [agents](@ref agents), are considered clients.
0009 
0010 <!--
0011 Additional information about Akonadi:
0012 
0013 - <a href="https://api.kde.org/kdesupport-api/akonadi-apidocs/">Akonadi Server documentation</a>
0014 - \ref akonadi_history
0015 - <a href="https://community.kde.org/KDE_PIM/Akonadi">Website</a>
0016 - <a href="https://techbase.kde.org/KDE_PIM/Akonadi">Wiki</a>
0017 
0018 Tools for developers:
0019 
0020 - <a href="https://bugs.kde.org/buglist.cgi?query_format=advanced&product=Akonadi&component=libakonadi&bug_status=REPORTED&bug_status=CONFIRMED&bug_status=ASSIGNED&bug_status=REOPENED">Bugtracker</a>
0021 //-->
0022 
0023 # Akonadi Objects # {#objects}
0024 
0025 Akonadi works on two basic object types: collections and items.
0026 
0027 Collections are comparable to folders in a file system and are represented by
0028 the class Akonadi::Collection. Every collection has an associated cache policy
0029 represented by the class Akonadi::CachePolicy which defines what part of its
0030 content is cached for how long. All available ways to work with collections are
0031 listed in the "[Collections](#collections)" section.
0032 
0033 Akonadi items are comparable to files in a file system and are represented by
0034 the class Akonadi::Item. Each item represents a single PIM object such as a mail
0035 or a contact. The actual object it represents is its so-called payload. All
0036 available ways to work with items are listed in the "[Items](#items)"
0037 section.
0038 
0039 Both items and collections are identified by a persistent unique identifier.
0040 Also, they can contain arbitrary attributes (derived from Akonadi::Attribute) to
0041 attach general or application specific meta data to them.
0042 
0043 # Collection retrieval and manipulation # {#collections}
0044 
0045 A collection is represented by the Akonadi::Collection class.
0046 
0047 Classes to retrieve information about collections:
0048 
0049 * Akonadi::CollectionFetchJob
0050 * Akonadi::CollectionStatisticsJob
0051 
0052 Classes to manipulate collections:
0053 
0054 * Akonadi::CollectionCreateJob
0055 * Akonadi::CollectionCopyJob
0056 * Akonadi::CollectionModifyJob
0057 * Akonadi::CollectionDeleteJob
0058 
0059 There is also Akonadi::CollectionModel, which is a self-updating model class which can
0060 be used in combination with Akonadi::CollectionView. Akonadi::CollectionFilterProxyModel
0061 can be used to limit a displayed collection tree to collections supporting a certain
0062 type of PIM items. Akonadi::CollectionPropertiesDialog provides an extensible properties
0063 dialog for collections. Often needed QAction for collection operations are provided by
0064 Akonadi::StandardActionManager.
0065 
0066 # PIM item retrieval and manipulation # {#items}
0067 
0068 PIM items are represented by classes derived from Akonadi::Item.
0069 Items can be retrieved using Akonadi::ItemFetchJob.
0070 
0071 The following classes are provided to manipulate PIM items:
0072 
0073 * Akonadi::ItemCreateJob
0074 * Akonadi::ItemCopyJob
0075 * Akonadi::ItemModifyJob
0076 * Akonadi::ItemDeleteJob
0077 
0078 Akonadi::ItemModel provides a self-updating model class which can be used to display the content
0079 of a collection. Akonadi::ItemView is the base class for a corresponding view. Often needed QAction
0080 for item operations are provided by Akonadi::StandardActionManager.
0081 
0082 # Low-level access to the Akonadi server # {#jobs}
0083 
0084 Accessing the Akonadi server is done using job classes derived from Akonadi::Job. The
0085 communication channel with the server is provided by Akonadi::Session.
0086 
0087 To use server-side transactions, the following jobs are provided:
0088 
0089 * Akonadi::TransactionBeginJob
0090 * Akonadi::TransactionCommitJob
0091 * Akonadi::TransactionRollbackJob
0092 
0093 There also is Akonadi::TransactionSequence which can be used to automatically group
0094 a set of jobs into a single transaction.
0095 
0096 
0097 # Change notifications (Monitor) # {#monitor}
0098 
0099 The Akonadi::Monitor class allows you to monitor specific resources,
0100 collections and PIM items for changes. Akonadi::ChangeRecorder augments this
0101 by providing a way to record and replay change notifications.
0102 
0103 # PIM item serializer # {#serializer}
0104 
0105 The class Akonadi::ItemSerializer is responsible for converting between the stored (binary) representation
0106 of a PIM item and the objects used to handle these items provided by the corresponding libraries (kabc, kcal, etc.).
0107 
0108 Serializer plugins allow you to add support for new kinds of PIM items to Akonadi.
0109 Akonadi::ItemSerializerPlugin can be used as a base class for such a plugin.
0110 
0111 # Agents and Resources # {#resource}
0112 
0113 Agents are independent processes that watch the Akonadi store for changes and react to them if necessary.
0114 Example: The Akonadi Indexing Agent is an agent that watches Akonadi for new emails, calendar events, etc.,
0115 retrieves the new items and indexes them into a special database.
0116 
0117 The class Akonadi::AgentBase is the common base class for all agents. It provides commonly needed
0118 functionality such as change monitoring and recording.
0119 
0120 Resources are a special kind of agents. They are used as the actual backend for whatever data the resource represents.
0121 In this situation the akonadi server acts more like a proxy service. It caches data on behalf of its clients
0122 (client here being the Resource), not permanently storing it. The Akonadi server forwards item retrieval requests to the
0123 corresponding resource, if the item is not in the cache.
0124 Example: The imap resource is responsible for storing and fetching emails from an imap server.
0125 
0126 Akonadi::ResourceBase is the base class for them. It provides the
0127 necessary interfaces to the server as well as many convenience functions to make implementing
0128 a new resource as easy as possible. Note that a collection contains items belonging to a single
0129 resource, although there are plans in the future for 'virtual' collections which will contain
0130 the results of a search query spanning multiple resources.
0131 
0132 A resource can support multiple mimetypes. There are two places where a resource can specify
0133 mimetypes: in its desktop files, and in the content mimetypes field of
0134 collections created by it. The ones in the desktop file are used for
0135 filtering agent types, e.g. in the resource creation dialogs. The collection
0136 content mimetypes specify what you can actually put into a collection, which
0137 is not necessarily the same (e.g. the Kolab resource supports contacts and events, but not
0138 in the same folder).
0139 
0140 
0141 # Integration in your Application # {#integration}
0142 
0143 Akonadi::Control provides ways to ensure that the Akonadi server is running, to monitor its availability
0144 and provide help on server-side errors. A more low-level interface to the Akonadi server is provided
0145 by Akonadi::ServerManager.
0146 
0147 A set of standard actions is provided by Akonadi::StandardActionManager. These provide consistent
0148 look and feel across applications.
0149 
0150 
0151 This library provides classes for KDE applications to communicate with the Akonadi server. The most high-level interface to Akonadi is the Models and Views provided in this library. Ready to use models are provided for use with views to interact with a tree of collections, a list of items in a collection, or a combined tree of Collections and items.
0152 
0153 ## Collections and Items ## {#collections_and_items}
0154 
0155 In the Akonadi concept, Items are individual objects of PIM data, e.g. emails, contacts, events, notes etc. The data in an item is stored in a typed payload. For example, if an Akonadi Item holds a contact, the contact is available as a KABC::Addressee:
0156 
0157 ~~~~~~~~~~~~~{.cpp}
0158 if (item.hasPayload<KABC::Addressee>()) {
0159     KABC::Addressee addr = item.payload<KABC::Addressee>();
0160     // use addr in some way...
0161 }
0162 ~~~~~~~~~~~~~
0163 
0164 Additionally, an Item must have a mimetype which corresponds to the type of payload it holds.
0165 
0166 Collections are simply containers of Items. A Collection has a name and a list of mimetypes that it may contain. A collection may for example contain events if it can contain the mimetype 'text/calendar'. A Collection itself (as opposed to its contents) has a mimetype, which is the same for all Collections. A Collection which can itself contain Collections must be able to contain the Collection mimetype.
0167 
0168 ~~~~~~~~~~~~~{.cpp}
0169 Collection col;
0170 // This collection can contain events and nested collections.
0171 col.setContentMimetypes({ Akonadi::Collection::mimeType(),
0172                           QStringLiteral("text/calendar") });
0173 ~~~~~~~~~~~~~
0174 
0175 This system makes it simple to create PIM applications. For example, to create an application for viewing and editing events, you simply need to tell %Akonadi to retrieve all items matching the mimetype 'text/calendar'.
0176 
0177 ## Convenience Mimetype Accessors ## {#convenience_mimetype_accessors}
0178 
0179 In order to avoid typos, improve readability, and to encapsulate the correct mimetypes for particular pim items, many of the standard classes have an accessor for the kind of mimetype the can handle. For example, you can use KMime::Message::mimeType() for emails, KABC::Addressee::mimeType() for contacts etc. It makes sense to define a similar static function in your own types.
0180 
0181 ~~~~~~~~~~~~~{.cpp}
0182 col.setContentMimetypes({ Akonadi::Collection::mimeType(),
0183                           KABC::Addressee::mimeType(),
0184                           KMime::Message::mimeType() });
0185 ~~~~~~~~~~~~~
0186 
0187 ## Models and Views ## {#models_and_views}
0188 Akonadi models and views are a high level way to interact with the Akonadi server. Most applications will use these classes. See the EntityTreeModel documentation for more information.
0189 
0190 Models provide an interface for viewing, deleting and moving Items and Collections. New Items can also be created by dropping data of the appropriate type on a model. Additionally, the models are updated automatically if another application changes the data or inserts or deletes items etc.
0191 
0192 Akonadi provides several models for particular uses, e.g. the MailModel is used for emails and the ContactsModel is used for showing contacts. Additional specific models can be implemented using EntityTreeModel as a base class.
0193 
0194 A typical use of these would be to create a model and use proxy models to make the view show different parts of the model. For example, show a collection tree in on one side and show items in a selected collection in another view.
0195 
0196 ~~~~~~~~~~~~~{.cpp}
0197 mailModel = new MailModel(session, monitor, this);
0198 
0199 collectionTree = new Akonadi::EntityMimeTypeFilterModel(this);
0200 collectionTree->setSourceModel(mailModel);
0201 // Filter out everything that is not a collection.
0202 collectionTree->addMimeTypeInclusionFilter(Akonadi::Collection::mimeType());
0203 collectionTree->setHeaderSet(Akonadi::EntityTreeModel::CollectionTreeHeaders);
0204 
0205 collectionView = new Akonadi::EntityTreeView(this);
0206 collectionView->setModel(collectionTree);
0207 
0208 itemList = new Akonadi::EntityMimeTypeFilterModel(this);
0209 itemList->setSourceModel(mailModel);
0210 // Filter out collections
0211 itemList->addMimeTypeExclusionFilter(Akonadi::Collection::mimeType());
0212 itemList->setHeaderSet(Akonadi::EntityTreeModel::ItemListHeaders);
0213 
0214 itemView = new Akonadi::EntityTreeView(this);
0215 itemView->setModel(itemList);
0216 ~~~~~~~~~~~~~
0217 
0218 ![An email application using MailModel](/docs/images/mailmodelapp.png "An email application using MailModel")
0219 
0220 The content of the model is determined by the configuration of the Monitor passed into it. The examples below show a use of the EntityTreeModel and some proxy models for a simple hierarchical note collection. As the model is generic, the configuration and proxy models will also work with any other mimetype.
0221 
0222 ~~~~~~~~~~~~~{.cpp}
0223 // Configure what should be shown in the model:
0224 Monitor *monitor = new Akonadi::Monitor(this);
0225 monitor->fetchCollection(true);
0226 monitor->setItemFetchScope(scope);
0227 monitor->setCollectionMonitored(Akonadi::Collection::root());
0228 monitor->setMimeTypeMonitored(MyEntity::mimeType());
0229 
0230 Akonadi::Session *session = new Akonadi::Session(QByteArray("MyEmailApp-") + QByteArray::number(qrand()), this);
0231 monitor->setSession(session);
0232 
0233 Akonadi::EntityTreeModel *entityTree = new Akonadi::EntityTreeModel(monitor, this);
0234 ~~~~~~~~~~~~~
0235 
0236 ![A plain EntityTreeModel in a view](/docs/images/entitytreemodel.png "A plain EntityTreeModel in a view")
0237 
0238 The EntityTreeModel can be further configured for certain behaviours such as fetching of collections and items.
0239 
0240 To create a model of only a collection tree and no items, set that in the model. This is just like CollectionModel:
0241 
0242 ~~~~~~~~~~~~~{.cpp}
0243 entityTree->setItemPopulationStrategy(Akonadi::EntityTreeModel::NoItemPopulation);
0244 ~~~~~~~~~~~~~
0245 
0246 ![A plain EntityTreeModel which does not fetch items.](/docs/images/entitytreemodel-collections.png "A plain EntityTreeModel which does not fetch items.")
0247 
0248 Or, create a model of only items and not child collections. This is just like ItemModel:
0249 
0250 ~~~~~~~~~~~~~{.cpp}
0251 entityTree->setRootCollection(myCollection);
0252 entityTree->setCollectionFetchStrategy(Akonadi::EntityTreeModel::FetchNoCollections);
0253 ~~~~~~~~~~~~~
0254 
0255 Or, to create a model which includes items and first level collections:
0256 
0257 ~~~~~~~~~~~~~{.cpp}
0258 entityTree->setCollectionFetchStrategy(Akonadi::EntityTreeModel::FetchFirstLevelCollections);
0259 ~~~~~~~~~~~~~
0260 
0261 The items in the model can also be inserted lazily for performance reasons. The Collection tree is always built immediately.
0262 
0263 Additionally, a KDescendantsProxyModel may be used to alter how the items in the tree are presented.
0264 
0265 ~~~~~~~~~~~~~{.cpp}
0266 // ... Create an entityTreeModel
0267 KDescendantsProxyModel *descProxy = new KDescendantsProxyModel(this);
0268 descProxy->setSourceModel(entityTree);
0269 view->setModel(descProxy);
0270 ~~~~~~~~~~~~~
0271 
0272 ![A KDescendantsProxyModel wrapping an EntityTreeModel](/docs/images/descendantentitiesproxymodel.png "A KDescendantsProxyModel wrapping an EntityTreeModel")
0273 
0274 KDescendantsProxyModel can also display ancestors of each Entity in the list.
0275 
0276 ~~~~~~~~~~~~~{.cpp}
0277 // ... Create an entityTreeModel
0278 KDescendantsProxyModel *descProxy = new KDescendantsProxyModel(this);
0279 descProxy->setSourceModel(entityTree);
0280 
0281 // #### This is new
0282 descProxy->setDisplayAncestorData(true, QLatin1StringView(" / "));
0283 
0284 view->setModel(descProxy);
0285 ~~~~~~~~~~~~~
0286 
0287 ![A KDescendantsProxyModel with ancestor names.](/docs/images/descendantentitiesproxymodel-withansecnames.png "A KDescendantsProxyModel with ancestor names.")
0288 
0289 This proxy can be combined with a filter to for example remove collections.
0290 
0291 ~~~~~~~~~~~~~{.cpp}
0292 // ... Create an entityTreeModel
0293 KDescendantsProxyModel *descProxy = new KDescendantsProxyModel(this);
0294 descProxy->setSourceModel(entityTree);
0295 
0296 // #### This is new.
0297 Akonadi::EntityMimeTypeFilterModel *filterModel = new Akonadi::EntityMimeTypeFilterModel(this);
0298 filterModel->setSourceModel(descProxy);
0299 filterModel->setExclusionFilter({ Akonadi::Collection::mimeType() });
0300 
0301 view->setModel(filterModel);
0302 ~~~~~~~~~~~~~
0303 
0304 ![An EntityMimeTypeFilterModel wrapping a KDescendantsProxyModel wrapping an EntityTreeModel](/docs/images/descendantentitiesproxymodel-colfilter.png "An EntityMimeTypeFilterModel wrapping a KDescendantsProxyModel wrapping an EntityTreeModel")
0305 
0306 It is also possible to show the root item as part of the selectable model:
0307 
0308 ~~~~~~~~~~~~~{.cpp}
0309 entityTree->setIncludeRootCollection(true);
0310 ~~~~~~~~~~~~~
0311 
0312 ![An EntityTreeModel showing Collection::root](/docs/images/entitytreemodel-showroot.png "An EntityTreeModel showing Collection::root")
0313 
0314 By default the displayed name of the root collection is '[*]', because it doesn't require i18n, and is generic. It can be changed too.
0315 
0316 ~~~~~~~~~~~~~{.cpp}
0317 entityTree->setIncludeRootCollection(true);
0318 entityTree->setRootCollectionDisplayName(i18nc("Name of top level for all collections in the application", "[All]"))
0319 ~~~~~~~~~~~~~
0320 
0321 ![An EntityTreeModel showing Collection::root with an application specific name.](/docs/images/entitytreemodel-showrootwithname.png "An EntityTreeModel showing Collection::root with an application specific name.")
0322 
0323 These can of course be combined to create an application which uses one EntityTreeModel along with several proxies and views.
0324 
0325 ~~~~~~~~~~~~~{.cpp}
0326 // ... create an EntityTreeModel.
0327 Akonadi::EntityMimeTypeFilterModel *collectionTree = new Akonadi::EntityMimeTypeFilterModel(this);
0328 collectionTree->setSourceModel(entityTree);
0329 // Filter to include collections only:
0330 collectionTree->setInclusionFilter({ Akonadi:: Collection::mimeType() });
0331 Akonadi::EntityTreeView *treeView = new Akonadi::EntityTreeView(this);
0332 treeView->setModel(collectionTree);
0333 
0334 Akonadi::EntityMimeTypeFilterModel *itemList = new Akonadi::EntityMimeTypeFilterModel(this);
0335 itemList->setSourceModel(entityTree);
0336 // Filter *out* collections
0337 itemList->setExclusionFilter({ Akonadi::Collection::mimeType() });
0338 Akonadi::EntityTreeView *listView = new Akonadi::EntityTreeView(this);
0339 listView->setModel(itemList);
0340 ~~~~~~~~~~~~~
0341 
0342 ![A single EntityTreeModel with several views and proxies.](/docs/images/treeandlistapp.png "A single EntityTreeModel with several views and proxies.")
0343 
0344 Or to also show items of child collections in the list:
0345 
0346 ~~~~~~~~~~~~~{.cpp}
0347 // ... Create an entityTreeModel
0348 collectionTree = new Akonadi::EntityMimeTypeFilterModel(this);
0349 collectionTree->setSourceModel(entityTree);
0350 
0351 // Include only collections in this proxy model.
0352 collectionTree->addMimeTypeInclusionFilter(Akonadi::Collection::mimeType());
0353 
0354 treeview->setModel(collectionTree);
0355 
0356 descendedList = new KDescendantsProxyModel(this);
0357 descendedList->setSourceModel(entityTree);
0358 
0359 itemList = new Akonadi::EntityMimeTypeFilterModel(this);
0360 itemList->setSourceModel(descendedList);
0361 
0362 // Exclude collections from the list view.
0363 itemList->addMimeTypeExclusionFilter(Akonadi::Collection::mimeType());
0364 
0365 listView = new EntityTreeView(this);
0366 listView->setModel(itemList);
0367 ~~~~~~~~~~~~~
0368 
0369 ![Showing descendants of all Collections in the list](/docs/images/treeandlistappwithdesclist.png "Showing descendants of all Collections in the list")
0370 
0371 Note that it is important in this case to use the DescendantEntitesProxyModel before the EntityMimeTypeFilterModel. Otherwise, by filtering out the collections first, you would also be filtering out their child items.
0372 
0373 A SelectionProxyModel can be used to simplify managing selection in one view through multiple proxy models to a representation in another view. The selectionModel of the initial view is used to create a proxied model which includes only the selected indexes and their children.
0374 
0375 
0376 ~~~~~~~~~~~~~{.cpp}
0377 // ... Create an entityTreeModel
0378 collectionTree = new Akonadi::EntityMimeTypeFilterModel(this);
0379 collectionTree->setSourceModel(entityTree);
0380 
0381 // Include only collections in this proxy model.
0382 collectionTree->addMimeTypeInclusionFilter(Akonadi::Collection::mimeType());
0383 
0384 treeview->setModel(collectionTree);
0385 
0386 // SelectionProxyModel can handle complex selections:
0387 treeview->setSelectionMode(QAbstractItemView::ExtendedSelection);
0388 
0389 SelectionProxyModel *selProxy = new SelectionProxyModel(treeview->selectionModel(), this);
0390 selProxy->setSourceModel(entityTree);
0391 
0392 Akonadi::EntityTreeView *selView = new Akonadi::EntityTreeView(splitter);
0393 selView->setModel(selProxy);
0394 ~~~~~~~~~~~~~
0395 
0396 ![A Selection in one view creating a model for use with another view.](/docs/images/selectionproxymodelsimpleselection.png "A Selection in one view creating a model for use with another view.")
0397 
0398 The SelectionProxyModel can handle complex selections.
0399 
0400 ![Non-contiguous selection creating a new simple model in a second view](/docs/images//selectionproxymodelmultipleselection.png "Non-contiguous selection creating a new simple model in a second view.")
0401 
0402 If an index and one or more of its descendants are selected, only the top-most selected index (including all of its descendants) are included in the proxy model. (Though this is configurable. See below)
0403 
0404 ![Selecting an item and its descendant](/docs/images/selectionproxymodelmultipleselection-withdescendant.png "Selecting an item and its descendant.")
0405 
0406 SelectionProxyModel allows configuration using the methods setStartWithChildTrees, setOmitDescendants, setIncludeAllSelected. See testapp/proxymodeltestapp to try out the 5 valid configurations.
0407 
0408 Obviously, the SelectionProxyModel may be used in a view, or further processed with other proxy models. See the example_contacts application for example which uses a further KDescendantsProxyModel and EntityMimeTypeFilterModel on top of a SelectionProxyModel.
0409 
0410 The SelectionProxyModel orders its items in the same top-to-bottom order as they appear in the source model. Note that this order may be different to the order in the selection model if there is a QSortFilterProxyModel between the selection and the source model.
0411 
0412 ![Ordered items in the SelectionProxyModel](/docs/images/selectionproxymodel-ordered.png "Ordered items in the SelectionProxyModel")
0413 
0414 Details on the actual implementation of lazy population are described on [this page](@ref internals).
0415 
0416 # Jobs and Monitors # {#jobs_and_monitors}
0417 
0418 The lower level way to interact with Akonadi is to use Jobs and Monitors (This is what models use internally). Jobs are used to make changes to akonadi, and in some cases (e.g., a fetch job) emit a signal with data resulting from the job. A Monitor reports changes made to the data stored in Akonadi (e.g., creating, updating, deleting or moving an item or collection ) via signals.
0419 
0420 Typically, an application will configure a monitor to report changes to a particular Collection, mimetype or resource, and then connect to the signals it emits.
0421 
0422 Most applications will use some of the low level api for actions unrelated to a model-tree view, such as creating new items and collections.
0423 
0424 # Tricky details # {#tricky_details}
0425 
0426 ## Change Conflicts ## {#change_conflicts}
0427 It is possible that while an application is editing an item, that item gets updated in akonadi. Akonadi will notify the application that that item has changed via a Monitor signal. It is the responsibility of the application to handle the conflict by for example offering the user a dialog to resolve it. Alternatively, the application could ignore the dataChanged signal for that item, and will get another chance to resolve the conflict when trying to save the result back to akonadi. In that case, the ItemModifyJob will fail and report that the revision number of the item on the server differs from its revision number as reported by the job. Again, it is up to the application to handle this case.
0428 
0429 This is something that every application using akonadi will have to handle.
0430 
0431 ## Using Item::Id or Collection::Id as an identifier ## {#using_id_as_an_identifier}
0432 
0433 Items and Collections have a id() member which is a unique identifier used by akonadi. It can be useful to use the id() as an identifier when storing Collections or Items.
0434 
0435 However, as an item and a collection can have the same id(), if you need to store both Collections and Items together by a simple identifier, conflicts can occur.
0436 
0437 ~~~~~~~~~~~~~{.cpp}
0438 QString getRemoteIdById(Item::Id id)
0439 {
0440     // Note:
0441     // m_items is QHash<Item::Id, Item>
0442     // m_collections is QHash<Collection::Id, Collection>
0443     if (m_items.contains(id)) {
0444         // Oops, we could accidentally match a collection here.
0445         return m_items.value(id).remoteId();
0446     } else if (m_collections.contains(id)) {
0447         return m_collections.value(id).remoteId();
0448     }
0449     return QString();
0450 }
0451 ~~~~~~~~~~~~~
0452 
0453 In this case, it makes more sense to use a normal qint64 as the internal identifier, and use the sign bit to determine if the identifier refers to a Collection or an Item. This is done in the implementation of EntityTreeModel to tell Collections and Items apart.
0454 
0455 ~~~~~~~~~~~~~{.cpp}
0456 qstring getremoteidbyinternalidentifier(qint64 internalidentifier)
0457 {
0458     // note:
0459     // m_items is qhash<item::id, item>
0460     // m_collections is qhash<collection::id, collection>
0461 
0462     // if the id is negative, it refers to an item
0463     // otherwise it refers to a collection.
0464 
0465     if (internalidentifier < 0) {
0466         // reverse the sign of the id before using it.
0467         return m_items.value(-internalidentifier).remoteid();
0468     } else {
0469         return m_collections.value(internalidentifier).remoteid();
0470     }
0471 }
0472 ~~~~~~~~~~~~~
0473 
0474 
0475 ### Unordered Lists ### {#unordered_lists}
0476 Collection and Item both provide a ::List to represent groups of objects. However the objects in the list are usually not ordered in any particular way, even though the API provides methods to work with an ordered list. It makes more sense to think of it as a Set instead of a list in most cases.
0477 
0478 For example, when using an ItemFetchJob to fetch the items in a collection, the items could be in any order when returned from the job. The order that a Monitor emits notices of changes is also indeterminate. By using a Transaction however, it is sometimes possible to retrieve objects in order. Additionally, using s constructor overload in the CollectionFetchJob it is possible to retrieve collections in a particular order.
0479 
0480 ~~~~~~~~~~~~~{.cpp}
0481 Collection::List getCollections(const QList<Collection::Id> &idsToGet)
0482 {
0483     Collection::List getList;
0484     for (Collection::Id id :  idsToGet) {
0485         getList << Collection(id);
0486     }
0487     CollectionFetchJob *job = CollectionFetchJob(getList);
0488     if (job->exec()) {
0489         // job->collections() is in the same order as the ids in idsToGet.
0490     }
0491 }
0492 ~~~~~~~~~~~~~
0493 
0494 # Resources # {#resources}
0495 The KDEPIM module includes resources for handling many types of PIM data, such as imap email, vcard files and vcard directories, ical event files etc. These cover many of the sources for your PIM data, but in the case that you need to use data from another source (for example a website providing a contacts storage service and an api), you simply have to write a new resource.
0496 
0497 https://techbase.kde.org/Development/Tutorials/Akonadi/Resources
0498 
0499 # Serializers # {#serializers}
0500 Serializers provide the functionality of converting raw data, for example from a file, to a strongly typed object of PIM data. For example, the addressee serializer reads data from a file and creates a KABC::Addressee object.
0501 
0502 New serializers can also easily be written if the data you are dealing with is not one of the standard PIM data types.
0503 
0504 # Implementation details # {#implementation_details}
0505 
0506 ## Updating Akonadi Models ## {#updating_models}
0507 
0508 NOTE: The details here are only relevant if you are writing a new view using EntityTreeModel, or writing a new model.
0509 
0510 Because communication with Akonadi happens asynchronously, and the models only hold a cached copy of the data on the akonadi server, some typical behaviours of models are not followed by Akonadi models.
0511 
0512 For example, when setting data on a model via a view, most models synchronously update their internal store and notify akonadi to update its view of the data by returning <tt>true</tt>.
0513 
0514 <!--
0515 TODO: Render this manually
0516 @dot
0517 digraph utmg {
0518     rankdir = LR;
0519     { node [label="",style=invis, height=0, width=0 ];
0520       V_Set_Data; V_Result; V_Data_Changed;
0521       M_Set_Data; M_Result;
0522     }
0523     { node [shape=box, fillcolor=lightyellow, style=filled,fontsize=26];
0524       View [label=":View"]; Model [label=":Model"];
0525     }
0526     { node [style=invis];
0527       View_EOL; Model_EOL;
0528     }
0529     {
0530       V_Set_Data -> M_Set_Data [label="Set Data"];
0531       M_Result -> V_Result [label="Success",arrowhead="vee", style="dashed"];
0532       V_Result -> V_Data_Changed [label="Update View \n[ Success = True ]"];
0533     }
0534 
0535     // Dashed Vertical lines for object lifetimes.
0536     edge [style=dashed, arrowhead=none];
0537     { rank = same; View -> V_Set_Data -> V_Result -> V_Data_Changed -> View_EOL; }
0538     { rank = same; Model -> M_Set_Data -> M_Result -> Model_EOL; }
0539 
0540     // Make sure top nodes are in a straight line.
0541     { View -> Model [style=invis]; }
0542     // And the bottom nodes.
0543     { View_EOL -> Model_EOL [style=invis]; }
0544 }
0545 @enddot
0546 //-->
0547 
0548 Akonadi models only cache data from the Akonadi server. To update data on an Akonadi::Entity stored in a model, the model makes a request to the Akonadi server to update the model data. At that point the data cached internally in the model is not updated, so <tt>false</tt> is always returned from setData. If the request to update data on the Akonadi server is successful, an Akonadi::Monitor notifies the model that the data on that item has changed. The model then updates its internal data store and notifies the view that the data has changed. The details of how the Monitor communicates with akonadi are omitted for clarity.
0549 
0550 <!--
0551 TODO: Render this into PNG
0552 @dot
0553 digraph utmg {
0554     rankdir = LR;
0555     { node [label="",style=invis, height=0, width=0 ];
0556       ETV_Set_Data; ETV_Result; ETV_Data_Changed;
0557       ETM_Set_Data; ETM_Result; ETM_Changed;
0558       M_Dummy_1; M_Changed;
0559       AS_Modify;
0560     }
0561     { node [shape=box, fillcolor=lightyellow, style=filled,fontsize=26];
0562       EntityTreeView [label=":View"]; EntityTreeModel [label=":Model"]; Monitor [label=":Monitor"]; Akonadi_Server [label=":Akonadi"];
0563     }
0564     { node [style=invis];
0565       EntityTreeView_EOL; EntityTreeModel_EOL; Monitor_EOL; Akonadi_Server_EOL;
0566     }
0567     {
0568       { rank = same; ETV_Set_Data -> ETM_Set_Data [label="Set Data"]; }
0569       { rank = same; ETM_Result -> ETV_Result [label="False",arrowhead="vee", style="dashed"]; }
0570       { rank = same; ETM_Result -> M_Dummy_1 [style=invis]; }
0571       { rank = same; ETM_Set_Data -> AS_Modify [arrowhead="vee",taillabel="Modify Item", labeldistance=14.0, labelangle=10]; }
0572       { rank = same; M_Changed -> ETM_Changed [arrowhead="vee",label="Item Changed"]; }
0573       { rank = same; ETM_Changed -> ETV_Data_Changed [arrowhead="vee",label="Update View"]; }
0574     }
0575 
0576     // Dashed Vertical lines for object lifetimes.
0577     edge [style=dashed, arrowhead=none];
0578     { rank = same; EntityTreeView -> ETV_Set_Data -> ETV_Result -> ETV_Data_Changed -> EntityTreeView_EOL; }
0579     { rank = same; EntityTreeModel -> ETM_Set_Data -> ETM_Result -> ETM_Changed -> EntityTreeModel_EOL; }
0580     { rank = same; Monitor -> M_Dummy_1 -> M_Changed -> Monitor_EOL; }
0581     { rank = same; Akonadi_Server -> AS_Modify -> Akonadi_Server_EOL; }
0582 
0583     // Make sure top nodes are in a straight line.
0584     { EntityTreeView -> EntityTreeModel -> Monitor -> Akonadi_Server [style=invis]; }
0585     // And the bottom nodes.
0586     { EntityTreeView_EOL -> EntityTreeModel_EOL -> Monitor_EOL -> Akonadi_Server_EOL [style=invis]; }
0587 }
0588 @enddot
0589 //-->
0590 
0591 Similarly, in drag and drop operations, most models would update an internal data store and return <tt>true</tt> from dropMimeData if the drop is successful.
0592 
0593 <!--
0594 TODO: Render this to PNG
0595 @dot
0596 digraph utmg {
0597     rankdir = LR;
0598     { node [label="",style=invis, height=0, width=0 ];
0599       Left_Phantom; Left_Phantom_DropEvent;
0600       V_DropEvent; V_Result; V_Data_Changed; V_Dummy_1;
0601       M_DropMimeData; M_Result;
0602     }
0603     { node [shape=box, fillcolor=lightyellow, style=filled,fontsize=26];
0604       View [label=":View"]; Model [label=":Model"];
0605     }
0606     { node [style=invis];
0607        Left_Phantom_EOL;
0608        View_EOL; Model_EOL;
0609     }
0610     {
0611       Left_Phantom_DropEvent -> V_DropEvent [label="DropEvent"];
0612       V_DropEvent -> M_DropMimeData [label="DropMimeData"];
0613       M_Result -> V_Result [label="Success",arrowhead="vee", style="dashed"];
0614       V_Result -> V_Data_Changed [label="Update View \n[Success = True]"];
0615     }
0616 
0617     // Dashed Vertical lines for object lifetimes.
0618     edge [style=dashed, arrowhead=none];
0619     { rank = same; View -> V_DropEvent -> V_Result -> V_Dummy_1 -> V_Data_Changed -> View_EOL; }
0620     { rank = same; Model -> M_DropMimeData -> M_Result -> Model_EOL; }
0621 
0622     //Phantom line
0623     { rank= same; Left_Phantom -> Left_Phantom_DropEvent -> Left_Phantom_EOL [style=invis]; }
0624 
0625     // Make sure top nodes are in a straight line.
0626     {  Left_Phantom -> View -> Model [style=invis]; }
0627     // And the bottom nodes.
0628     {  Left_Phantom_EOL ->  View_EOL -> Model_EOL [style=invis]; }
0629 }
0630 @enddot
0631 //--->
0632 
0633 Akonadi models, for the same reason as above, always return false from dropMimeData. At the same time a suitable request is sent to the akonadi server to make the changes resulting from the drop (for example, moving or copying an entity, or adding a new entity to a collection etc). If that request is successful, the Akonadi::Monitor notifies the model that the data is changed and the model updates its internal store and notifies the view that the model data is changed.
0634 
0635 <!--
0636 TODO: Render this to PNG
0637 @dot
0638 digraph utmg {
0639     rankdir = LR;
0640     { node [label="",style=invis, height=0, width=0 ];
0641       Left_Phantom; Left_Phantom_DropEvent;
0642       ETV_DropEvent; ETV_Result; ETV_Data_Changed;
0643       ETM_DropMimeData; ETM_Result; ETM_Changed;
0644       M_Dummy_1; M_Changed;
0645       AS_Modify;
0646     }
0647     { node [shape=box, fillcolor=lightyellow, style=filled,fontsize=26];
0648       EntityTreeView [label=":View"];
0649       EntityTreeModel [label=":Model"];
0650       Monitor [label=":Monitor"];
0651       Akonadi_Server [label=":Akonadi"];
0652     }
0653     { node [style=invis];
0654       Left_Phantom_EOL;
0655       EntityTreeView_EOL; EntityTreeModel_EOL; Monitor_EOL; Akonadi_Server_EOL;
0656     }
0657 
0658     {
0659       { rank = same; Left_Phantom_DropEvent -> ETV_DropEvent [label="DropEvent"]; }
0660       { rank = same; ETV_DropEvent -> ETM_DropMimeData [label="Drop MimeData"]; }
0661       { rank = same; ETM_Result -> ETV_Result [label="False",arrowhead="vee", style="dashed"]; }
0662       { rank = same; ETM_Result -> M_Dummy_1 [style=invis]; }
0663       { rank = same; ETM_DropMimeData -> AS_Modify [arrowhead="vee",taillabel="Action", labeldistance=14.0, labelangle=10]; }
0664       { rank = same; M_Changed -> ETM_Changed [arrowhead="vee",label="Item Changed"]; }
0665       { rank = same; ETM_Changed -> ETV_Data_Changed [arrowhead="vee",label="Update View"]; }
0666     }
0667 
0668     // Dashed Vertical lines for object lifetimes.
0669     edge [style=dashed, arrowhead=none];
0670     { rank = same; EntityTreeView -> ETV_DropEvent -> ETV_Result -> ETV_Data_Changed -> EntityTreeView_EOL; }
0671     { rank = same; EntityTreeModel -> ETM_DropMimeData -> ETM_Result -> ETM_Changed -> EntityTreeModel_EOL; }
0672     { rank = same; Monitor -> M_Dummy_1 -> M_Changed -> Monitor_EOL; }
0673     { rank = same; Akonadi_Server -> AS_Modify -> Akonadi_Server_EOL; }
0674 
0675     //Phantom line
0676     { rank= same; Left_Phantom -> Left_Phantom_DropEvent -> Left_Phantom_EOL [style=invis]; }
0677 
0678     // Make sure top nodes are in a straight line.
0679     { Left_Phantom -> EntityTreeView -> EntityTreeModel -> Monitor -> Akonadi_Server [style=invis]; }
0680     // And the bottom nodes.
0681     { Left_Phantom_EOL -> EntityTreeView_EOL -> EntityTreeModel_EOL -> Monitor_EOL -> Akonadi_Server_EOL [style=invis]; }
0682 }
0683 @enddot
0684 //-->