The QOrganizerItemManager interface provided to clients to allow access to organizer information depends on an implementation of QOrganizerItemManagerEngine existing. This engine provides the methods which are called by the manager. An engine is identified by its URI, which is the name reported to clients through the QOrganizerItemManager::managerUri() function. The URI of a manager is built by combining its name, version and relevant construction parameters.
While clients never interact directly with instances of QOrganizerItemManagerEngine, they may need to be aware of limitations of individual engines, or differences between engines. The API offered through QOrganizerItemManager allows clients to retrieve this information for the engine which provides the functionality exposed through a particular QOrganizerItemManager.
A QOrganizerItemManagerEngine may provide an aggregated view of multiple physical datastores, zero or more of which may be remote datastores. Clients of the API are aware only that the data is managed by a QOrganizerItemManagerEngine with a particular URI. It is possible that multiple different engines will have overlap in the datastores which they aggregate, and in that case the way in which those engines were implemented will determine whether operations are thread-safe or not.
Since the data may physically be stored in a remote datastore, any operations may be dominated by the return-trip-time of communications with the remote datastore. As such, it is recommended that clients use the asynchronous client API to access organizer information from any QOrganizerItemManager.
Each engine may support a different schema. All engines should attempt to support the default schema, described in the default schema documentation, however clients should never assume that any engine does support the default schema fully.
Clients are able to retrieve the schema supported by a particular engine at run-time by calling QOrganizerItemManager::detailDefinitions(). Some engines support different detail definitions (that is, a different schema) for different types of organizer items (events, todos, journals, notes and so forth). Clients can retrieve the organizer item types supported by an engine by calling QOrganizerItemManager::supportedItemTypes().
The Organizer module of the Qt Mobility project includes several backends already, some of which are designed to interface with the default calendar on their particular platform.
The in-memory engine identifies itself as the "memory" engine. It is available on all platforms which are supported by the Qt Mobility project.
The in-memory engine supports the default schema, and provides almost all functionality available through the Qt Mobility Organizer API; however, all data is stored in-memory and is not persisted in any way.
The Symbian engine identifies itself as the "symbian" engine, and is only available on the Symbian S60 3.1, S60 3.2, S60 5.0 and Symbian^3 platforms.
The Symbian engine supports a modified version of the default schema. The schema supported by the Symbian engine depends on which version of the platform is being used.
The Symbian engine allows clients to use both the asynchronous and synchronous interfaces, and persists all saved data to the system calendar.
The Maemo 5 (Fremantle) engine identifies itself as the "maemo5" engine, but is only available on the Maemo 5 (Fremantle) platform which has the correct libraries installed (including calendar-backend).
The Maemo 5 (Fremantle) engine supports a modified version of the default schema, and persists all saved information to the system calendar.
Some developers may wish to provide implementations of QOrganizerItemManagerEngine for use by clients. The engine that they provide may aggregate multiple datastores, or access a remote datastore, or provide some other functionality to clients. An engine is distributed as a Qt Plugin, and will be detected automatically by the plugin loading code in the QOrganizerItemManager, so long as the plugin is located in the correct path ($QT_PLUGINS_DIR/organizer/).
Different engines provide different functionality and support different features. Depending on the feature set of the engine, it will need to implement a particular subset of the API. The default implementation for most functions will set the error to QOrganizerItemManager::NotSupportedError and return the value which indicates that an error has occurred.
All engines must implement the following functions:
Every engine implementation must also come with an implementation of QOrganizerItemManagerEngineFactory for that engine.
Note that you do not need to implement filtering and sorting natively in an engine; the default implementation offers the following static functions to perform filtering and sorting respectively, in memory:
However, engine implementors should be aware that the default implementation is naive and will have greatly reduced performance compared to a native implementation (e.g., SQL queries, if the calendar or personal data exposed by the engine implementation is stored in an SQL database).
Similarly, any QOrganizerItemFetchHint parameter may be ignored by an engine implementation, but if it does so it must return all information available for the item.
All engines must also implement the following functions to implement asynchronous requests:
If the engine does not support asynchronous requests, it should always return false in the last three of those functions, and do nothing in the first. If the engine does support asynchronous requests, it must ensure that all information required to perform the request is saved in the engine within QOrganizerItemManagerEngine::startRequest(), as the client owns the request object and may delete it at any time. In general, engine implementors should be aware of this ownership semantic, and never attempt an unsafe operation on a request pointer.
It is recommended that all engine implementations support asynchronous requests, even if they use a "dummy" implementation which services the request synchronously during startRequest, and then emit the appropriate signals from the request via a zero-millisecond timeout timer.
The rest of the virtual functions are optional, and should be implemented only if the engine supports the operations.
If the engine can be constructed with different parameters, which affects the operation of the engine (for example, a parameter might define which file to read schedule or calendar information from, or it might be an access token to prove that the client has the access rights to read organizer information from the engine, etc), it must report which parameters it was constructed with via the
function.
If the engine supports native filtering of any kind, it must report to clients which filters are supported natively by implementing:
If the engine supports saving or removing organizer item information, as well as retrieval, it must implement:
It may also choose to implement the "single item" functions:
If it does not, the default implementation of those functions will use the batch (plural) versions of those functions to implement the required behavior.
If the engine supports modification of its schema (that is, extension of its definitions at run-time), it must report that it supports the QOrganizerItemManager::MutableDefinitions feature via QOrganizerItemManagerEngine::hasFeature(), and must also implement:
Apart from areas of functionality which may be optionally implemented by the engine or not, the default implementation provides several functions which operate in a naive, in-memory manner. An engine implementation can override this default implementation with its own, if it wishes, in order to obtain performance gains, or to more accurately implement the function.
As previously mentioned it may implement its own sorting or filtering, in functions such as QOrganizerItemManagerEngine::items(). An engine may also implement:
An engine implementation must emit the appropriate signals for the subset of functionality that it supports.
If the engine supports reading or saving items, it must emit the:
signals as appropriate. Alternatively, it can emit the QOrganizerItemManager::dataChanged() signal instead.
There are several other considerations that engine writers must be aware of:
There are several implementations of QOrganizerItemManagerEngine available in the Qt Mobility source code repository. In particular, the "memory" engine provides an implementation of an in-memory, anonymous datastore which supports almost every feature in the API, and therefore is useful for demonstration purposes. Be aware, however, that the implementation of all functionality in the "memory" engine is naive and not performant, and should not be copied in any real engine implementation (e.g., to perform filtering, it reads all items from the (in-memory) database, and checks one by one for matches; a real engine, on the other hand, might perform a database query to return the results directly, rather than performing n-reads).