Contents
Organizer Synchronous API
Introduction
The Organizer Items Synchronous API enables a client to synchronously fetch, update, or remove item data from an item manager. A synchronous API is of most use to clients who wish to perform simple requests where performance or user interface responsiveness is not critical. Synchronous calls to an item manager will block until they are completed, and therefore should not be performed in the GUI thread if the manager is a frontend to an online service or long-latency datastore. The main advantage of the synchronous API is its simplicity and convenience.
Most operations which may be performed using the synchronous API may also be performed using the asynchronous API. It is recommended for most applications that the asynchronous API be used where possible.
Using The API
The synchronous API offered by the Organizer Items module is available through the QOrganizerItemManager class. It consists of three major sections:
- Error Reporting
- Schema Manipulation
- Organizer Item Manipulation
Error Reporting
When a synchronous operation fails, clients need to be able to retrieve error information associated with that synchronous operation. The QOrganizerItemManager::error() function provides this information to clients.
For some synchronous operations (for example, batch save or remove operations) it is possible that multiple errors may occur during the operation. In those cases, the synchronous function will take a pointer to a map of input index to error, which will be filled by the function as required, and the QOrganizerItemManager::error() function will report the overall operation error.
Error reporting is handled slightly differently in the asynchronous API, in that each instance of an asynchronous request is able to report any overall operation error as well as the finer-grained map of errors, for the operation which it requested.
Organizer Item Manipulation
The most common type of operation that clients will perform involves retrieval or modification of items. The QOrganizerItemManager class offers synchronous API to retrieve, create, update and delete items. The create and update operations are provided through the same interface. Both singular and batch operations are offered by the API.
An item is identified by its QOrganizerItemId. This id consists of two parts: a URI which identifies the item manager which stores the item, and the local id of the item in that manager. Some operations which take a pointer to an item as an argument may modify the item during the operation; updating the item id is a common example.
The QOrganizerItemManager class provides API for accessing the IDs of items which are stored in the manager:
- itemIds(const QList<QOrganizerItemSortOrder>& sortOrders = QList<QOrganizerItemSortOrder>()) const
- itemIds(const QOrganizerItemFilter& filter, const QList<QOrganizerItemSortOrder>& sortOrders = QList<QOrganizerItemSortOrder>()) const
The item id retrieval functionality is also provided via asynchronous API through the QOrganizerItemLocalIdFetchRequest class.
The synchronous, singular item manipulation functions offered by the QOrganizerItemManager class are:
- item(const QOrganizerItemLocalId& itemId, const QOrganizerItemFetchHint& fetchHint = QOrganizerItemFetchHint()) const
- saveOrganizer Item(QOrganizerItem* item)
- removeOrganizer Item(const QOrganizerItemLocalId& itemId)
The (optional) fetch argument to the item accessor function allows clients to tell the plugin which types of information they wish to retrieve. This argument is a hint only, and may be ignored safely by the plugin, or used by the plugin to optimize the performance of the retrieve operation.
The save operation entails a validation step, where the item's details are checked against the supported schema. If the item is valid, it will be saved. Note that if the item already exists in the database (determined by the id of the item) it will be replaced with the item contained in the argument. This means that clients should not save any item which was retrieved with a non-empty fetchHint defined, or data loss may occur.
Any error which occurs during such singular item manipulation functions may be accessed by calling QOrganizerItemManager::error() directly after the original synchronous call.
The synchronous, batch item manipulation functions offered by the QOrganizerItemManager class are:
- items(const QList<QOrganizerItemSortOrder>& sortOrders = QList<QOrganizerItemSortOrder>(), const QOrganizerItemFetchHint& fetchHint = QOrganizerItemFetchHint()) const
- items(const QOrganizerItemFilter& filter, const QList<QOrganizerItemSortOrder>& sortOrders = QList<QOrganizerItemSortOrder>(), const QOrganizerItemFetchHint& fetchHint = QOrganizerItemFetchHint()) const
- saveOrganizer Items(QList<QOrganizerItem>* items, QMap<int, QOrganizerItemManager::Error>* errorMap)
- removeOrganizer Items(QList<QOrganizerItemLocalId>* itemIds, QMap<int, QOrganizerItemManager::Error>* errorMap)
The batch save and remove functions both take an (optional) pointer to a map of errors. If the pointer is non-null, this map will be filled out with any errors which occur. The overall operation error of any batch manipulation operation may be accessed by calling QOrganizerItemManager::error() directly after the original synchronous call.
The item manipulation functionality is also provided via asynchronous API through the QOrganizerItemFetchRequest, QOrganizerItemSaveRequest, and QOrganizerItemRemoveRequest classes.
Schema Manipulation
The schema supported by a plugin is the list of detail definitions which are supported by the plugin. An item which contains a detail of a particular definition which is not supported by the plugin will fail to validate when the user attempts to save it in that manager. The schema also includes any access constraints which may apply to certain details or detail definitions (for example, a particular detail definition might be declared to be unique per-item in a particular manager).
Every plugin will support a slightly different schema, as the schema which can be supported will depend on the semantics and limitations of the underlying storage platform on which the plugin is based. The default schema is described in the Qt Mobility Organizer schema documentation, and plugins should attempt to implement that schema; however no guarantees are given to clients as to the conformance of the schemas supported by various plugins to the default schema.
Some plugins support extensible detail types. This means that third party developers can extend the schema of such plugins at run time (for example, to add a new field to a detail). Some plugins allow third party developers to define new detail types (that is, to add an entirely new detail type to the schema supported by that plugin). Plugins which support these types of operations must report to clients that they support the QOrganizerItemManager::MutableDefinitions feature.
The synchronous API offers several functions to retrieve or modify the schema supported by a plugin:
- detailDefinitions(const QString& itemType = QOrganizerItemType::TypeEvent) const
- detailDefinition(const QString& definitionName, const QString& itemType = QOrganizerItemType::TypeEvent) const
- saveDetailDefinition(const QOrganizerItemDetailDefinition& def, const QString& itemType = QOrganizerItemType::TypeEvent)
- removeDetailDefinition(const QString& definitionName, const QString& itemType = QOrganizerItemType::TypeEvent)
The schema manipulation functionality is also provided via asynchronous API through the QOrganizerItemDetailDefinitionFetchRequest, QOrganizerItemDetailDefinitionSaveRequest and QOrganizerItemDetailDefinitionRemoveRequest classes.
Note that the schema supported by a plugin may vary depending on the type of item to which the schema applies. For example, a particular plugin might support name, address, phone number, email address, and gender details for normal items, but only name, address, and phone number details for a group item.
Examples Of Usage
The synchronous API provides the simplest way to access or modify the item information managed by a particular backend. It has the disadvantage that calls block until completion and is therefore most suitable only for applications which interact with local, high-speed datastores.
Saving a new item to the default manager
The client creates a new non-recurring item, adds some, and saves it to the default store of the default manager.
// a default constructed journal will have it's date/time set to the current date/time.
QOrganizerJournal journal;
journal.setDescription("The conference went well. We all agree that marshmallows are awesome, "\
"but we were unable to reach any agreement as to how we could possibly "\
"increase our intake of marshmallows. Several action points were assigned "\
"to various members of the group; I have been tasked with finding a good "\
"recipe that combines both marshmallows and chocolate, by next Wednesday.");
defaultManager.saveItem(&journal);
We assume the existence of various specialized leaf-classes that allow simple access to details of the item, such as priority, description and display label. These specialized leaf classes may be written by anyone, and simply wrap the functionality provided by QOrganizerItemDetail in order to allow simpler access to fields supported by a particular definition.
Filtering by detail definition and value
The client utilizes a default manager and asks for any items which match a particular search criteria:
// XXX TODO: make this more convenient. // QOrganizerItemLocation::matchLocationName("Meeting Room 8") ? QOrganizerItemDetailFilter locationFilter; locationFilter.setDetailDefinitionName(QOrganizerItemLocation::DefinitionName, QOrganizerItemLocation::FieldLocationName); locationFilter.setValue("Meeting Room 8"); QList<QOrganizerItem> entries = defaultManager.items(locationFilter);
Modifying an existing item and saving the modifications
The client retrieves an item, modifies one of its details, adds a new detail, and then saves the item back to the manager.
journal.addComment("Serves: 8. Ingredients: 500g Milk Chocolate, 500g Marshmallows. Step 1: Put the marshmallows into 8 separate bowls. Step 2: Melt the chocolate. Step 3: Pour the chocolate over the marshmallows in the bowls. Step 4: Put the bowls into the refrigerator for 20 minutes; serve chilled."); if (!defaultManager.saveItem(&journal)) qDebug() << "Unable to save updated journal! Error:" << defaultManager.error();