Access to the backends is provided by implementations of Qt Contacts manager API. This is achieved by defining generic personal information data abstractions which can sufficiently describe contact data stored on any platform. Due to the cross-platform nature of the API, and the ability for developers to write platform-independent implementations of a QContactManager which may unify one or more platform specific contact backends, it is intended that the semantics and quirks of the underlying datastores on any platform may be entirely opaque from the perspective of Qt-based, cross-platform client applications.
Overview
A contact is the digital representation of a person, group or entity, which is stored in a platform-specific manner. Information pertaining to a single contact may be located across several different datastores, and each datum (or detail) may or may not pertain to a particular context in which that information is valid. A contact may include semantically identical pieces of information that are relevant in different contexts. For example, a contact may have a phone number that is relevant to their "home" context, and another phone number that is relevant to their "work" context. It can be seen that the context of information defines its validity to the user, depending on the context of usage; and as such, the sum of information in a given context can be considered equivalent to a "contextual identity". This allows great flexibility when consolidating data from various sources into a single, cohesive contact.
Each datum (or detail) stored in a contact has defined semantics of usage and storage. The Qt Contacts API allows per-datastore contact detail definitions, allowing a manager to provide clients with this information on demand, and allowing third-party developers to register detail definitions for use by clients. A detail definition includes the fields (and value-types of those fields) which make up the detail, per-contact uniqueness constraints on details of the definition, and access constraints (such as read-only, create-only, etc). Additionally, the fields of a detail definition may also be constrained to be read-only or not.
A detail is a single, cohesive unit of information that is stored in a contact. As explained previously, it is valid for a particular context or set of contexts, and conforms to a particular definition. A detail may have specific metadata associated with it, such as its sub-type, context, and arbitrary, user-defined metadata.
Contacts may participate in relationships with other contacts. The details of any such relationship is stored by the manager which contains the contact. There are several standard relationship types supported by the default schema, and arbitrary relationship types are also allowed. In particular, membership of a contact in a group can be modeled as that group contact participating in a HasMember relationship with the contact.
A manager provides access to zero or more platform-specific datastores. Each datastore may support different capabilities (for example, the ability to store certain datatypes, the ability to natively filter on different details or details of different definitions, the provision of locking mechanisms, the provision of changelog information, etc) which are reported by the manager on request. The manager therefore provides access to detail definitions, contacts, and relationships stored in different datastores, in a platform and datastore independent manner. The engine of a manager may be implemented as a plugin to allow dynamic loading of different engines at run-time.
Using the API
This section provides some examples of common usage of the API.
Synchronous API Usage
The synchronous API provides the simplest way to access or modify the contact 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 contact to the default manager
The client creates a new contact, adds a name and a phone number, and saves it to the default store of the default manager.
We assume the existence of a specialised leaf-class that allows simple access to details of the definition identified by the "PhoneNumber" identifier, and another that allows simple access to details of the definition identified by the "Name" identifier. These specialised leaf classes may be written by anyone, and simply wrap the functionality provided by QContactDetail in order to allow simpler access to fields supported by a particular definition.
void addContact(QContactManager* cm)
{
QContact alice;
/* Set the contact's name */
QContactName aliceName;
aliceName.setFirst("Alice");
aliceName.setLast("Jones");
aliceName.setCustomLabel("Ally Jones");
alice.saveDetail(&aliceName);
/* Add a phone number */
QContactPhoneNumber number;
number.setContexts(QContactDetail::ContextHome);
number.setSubTypes(QContactPhoneNumber::SubTypeMobile);
number.setNumber("12345678");
alice.saveDetail(&number);
alice.setPreferredDetail("DialAction", number);
/* Add a second phone number */
QContactPhoneNumber number2;
number2.setContexts(QContactDetail::ContextWork);
number2.setSubTypes(QContactPhoneNumber::SubTypeLandline);
number2.setNumber("555-4444");
alice.saveDetail(&number2);
/* Save the contact */
cm->saveContact(&alice);
}
Filtering by detail definition and value
The client utilises a default manager and asks for any contacts with a particular phone number. The example assumes that the default manager supports the provided QContactPhoneNumber detail leaf class (which implements the default definition for phone number details).
Installing a plugin that modifies the definition of one type of detail
The client installs a plugin, which requires a new field to be added to details of the "EmailAddress" definition. It loads the definition from the default manager, modifies it (by adding the new field - a label field), and saves it back.
void addPlugin(QContactManager* cm)
{
/* Find the definition that we are modifying */
QMap<QString, QContactDetailDefinition> definitions = cm->detailDefinitions();
QContactDetailDefinition modified = definitions.value(QContactEmailAddress::DefinitionName);
/* Make our modifications: we add a "Label" field to email addresses */
QContactDetailDefinitionField newField;
newField.setDataType(QVariant::String);
QMap<QString, QContactDetailDefinitionField> fields = modified.fields();
fields.insert("Label", newField);
/* Update the definition with the new field included */
modified.setFields(fields);
/* Save the definition back to the manager */
if (cm->saveDetailDefinition(modified))
qDebug() << "Successfully modified the detail definition!";
else
qDebug() << "This backend could not support our modifications!";
}
Modifying an existing contact and saving the modifications
The client retrieves a contact, modifies one of its details, adds a new detail, and then saves the contact back to the manager. Note that it uses the newly added field of the email address definition!
void editView(QContactManager* cm)
{
QList<QContactLocalId> contactIds = cm->contacts();
QContact a = cm->contact(contactIds.first());
qDebug() << "Modifying the details of" << a.displayLabel();
/* Change the first phone number */
QList<QContactDetail> numbers = a.details(QContactPhoneNumber::DefinitionName);
QContactPhoneNumber phone = numbers.value(0);
phone.setNumber("123-4445");
/* Add an email address */
QContactEmailAddress email;
email.setEmailAddress("alice.jones@example");
email.setContexts(QContactDetail::ContextHome);
email.setValue("Label", "Alice's Work Email Address");
/* Save the updated details to the contact. */
a.saveDetail(&phone);
a.saveDetail(&email);
/* Now we must save the updated contact back to the database. */
cm->saveContact(&a);
viewDetails(cm);
}
Asynchronous API Usage
The asynchronous API provides a flexible and powerful method of accessing and modifying the contact information managed by a particular backend in an asynchronous manner. Use of the asynchronous API is slightly more complex than use of the synchronous API, but offers the programmer greater flexibility when requesting information from remote or slow, local datastores.
Requesting Contacts
The client sets up a request for contacts matching a specific criteria from a particular manager.
Results from the request will be displayed to the user as they are received.
void RequestExample::performRequest()
{
// retrieve any contact whose first name is "Alice"
QContactDetailFilter dfil;
dfil.setDetailDefinitionName(QContactName::DefinitionName, QContactName::FieldFirst);
dfil.setValue("Alice");
dfil.setMatchFlags(QContactFilter::MatchExactly);
m_fetchRequest->setFilter(dfil);
connect(m_fetchRequest, SIGNAL(progress(QContactFetchRequest*,bool)), this, SLOT(printContacts(QContactFetchRequest*,bool)));
if (!m_fetchRequest->start()) {
qDebug() << "Unable to request contacts!";
QCoreApplication::exit(0);
} else {
qDebug() << "Requested contacts; awaiting results...";
}
}
void RequestExample::printContacts(QContactFetchRequest* request, bool appendOnly)
{
QList<QContact> results = request->contacts();
if (appendOnly) {
// we know that the results are still in the same order; just display the new results.
for (m_previousLastIndex += 1; m_previousLastIndex < results.size(); m_previousLastIndex++) {
qDebug() << "Found another Alice:" << results.at(m_previousLastIndex).displayLabel();
}
} else {
// the order of results has changed; display them all.
for (m_previousLastIndex = 0; m_previousLastIndex < results.size(); m_previousLastIndex++) {
qDebug() << "Found another Alice:" << results.at(m_previousLastIndex).displayLabel();
}
}
// once we've finished retrieving results, stop processing events.
if (request->status() == QContactAbstractRequest::Finished || request->status() == QContactAbstractRequest::Cancelled) {
QCoreApplication::exit(0);
}
}
Other Asynchronous Operations
All other asynchronous operations are performed in a similar manner to the previous example. A request of the desired type (which is derived from QContactAbstractRequest) is created, certain criteria are set which determine the result of the request, and the progress signal of the request is connected to a slot which deals with the result. The request can then be started.
Any operation that 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.
Manager Settings And Configuration
Users of the contacts API can define which backend they wish to access if a manager for that backend is available. The list of available managers can be queried programmatically at run-time, and the capabilities of different managers can be ascertained by inspecting a QContactManager instance. Furthermore, some managers can be constructed with parameters which affect the operation of the backend.
Loading the manager for a specific backend
In this example, the client loads a manager for a specific backend. While this could be found and retrieved using a more advanced plugin framework (such as the Qt Service Framework), this code assumes that the client has prior knowledge of the backend in question.
void loadManager()
{
QContactManager* cm = new QContactManager("KABC");
QList<QContactLocalId> contactIds = cm->contacts();
if (!contactIds.isEmpty()) {
QContact a = cm->contact(contactIds.first());
qDebug() << "This manager contains" << a.displayLabel();
} else {
qDebug() << "This manager contains no contacts";
}
delete cm;
}
Loading a manager with specific parameters
The client loads a manager with specific parameters defined. The parameters which are available are backend specific, and so the client had to know that the "Settings" parameter was valid for the particular backend, and what argument it took. In this example, the client tells the backend to load detail definitions saved in a particular settings file.
Access to a single, complete detail about a contact
"Contact Details" Leaf Classes
Several subclasses of QContactDetail are provided as part of the Qt Mobility Project Contacts API. They are general in design but are intended to fulfil specific use-cases. Please note that certain backends may choose not to support one or more of these subclasses as they appear here; they may offer their own which provide similar functionality.
Each of these subclasses provide access to information stored in fields which are listed in the schema.
Asynchronous Requests
Clients may use either the synchronous or asynchronous API to access functionality provided by a manager backend. The asynchronous API is offered through subclasses of the QContactAbstractRequest class:
Allows a client to asynchronously request that certain contacts be saved to a contacts store
Contact Selection
Clients may select a contact by specifying a unique contact id, or by supplying a QContactFilter which matches the contact or contacts they wish to select. The various derivatives of QContactFilter allow for fine-grained and flexible selection of contacts according to various criteria:
A client can also request that the results of such a selection be sorted, by passing a QContactSortOrder (or list of sort orders) to the manager.
Actions
Clients can perform actions on contacts which support them. Actions are things like "Send Email" or "Dial", and can be provided from various sources including Qt Plugins or the Qt Mobility Service Framework. Every action implementation is uniquely identified by a combination of its name, the name of the vendor which provided the implementation, and the version of the implementation according to the vendor. These pieces of data may be encapsulated in a QContactActionDescriptor which can be used to retrieve an instance of the implementation from a QContactActionFactory.
When an instance of a QContactAction is created, the caller takes ownership of the instance, and must delete it after use.
Different backends have different capabilities and offer different functionality. In order to allow clients to query the provided functionality at runtime, every backend must be capable of reporting their functionality and implementation version. They are reported to clients through various functions provided by the QContactManager class.
Synchronization and Serialization
The contacts API is used by another Qt Mobility module: the Versit* module. It allows serialization of a QContact into a vCard document, and vice versa.
[*] Versit is a trademark of the Internet Mail Consortium.
Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia.
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter
ou par MP !