Qt Extended supports implementing PIM synchronization on the device through functions provided by QPimModel. The functions QPimModel::added(), QPimModel::removed() and QPimModel::modified() are provided as a way of accessing the internal changelog maintained by the PIM Library. This helps determine what data has changed since a previous synchronization action so to minimize the amount of data sent over a network when enacting the next synchronization. The functions QPimModel::startSyncTransaction(), QPimModel::abortSyncTransaction() and QPimModel::commitSyncTransaction() are provided to atomically apply changes for synchronization as well as to increase performance by virtue of the SQL transaction and reduced load on calculating changelog timestamps.
Retrieving relevant changes.
The QPimModel functions added, removed and modified are used to retrieve relevant changes for a sync. While these functions are implemented in QPimModel, it is important to use one of the subclasses, QContactModel, QAppointmentModel, or QTaskModel, in order to specify what PIM data type is to be synced.
The time used with these functions should be specified in UTC. This is because changes to the users timezone, perhaps while traveling, should impact synchronization. Generally the timestamp from the previous synchronization will be used with these functions in order to only deal with the changes between two synchronization actions. To this end these functions treat a null datetime as specifying a slow or full sync. Hence passing a null for added will return all records, and passing a null for modified or removed will return no records. For any single timestamp, a record will appear only in one of the added, removed, or modified results.
It is also important to note that the filtering applied to a model, be it for completed tasks or contacts from a certain data source, also apply to the added, modified and removed functions.
void MyTasksSync::fetchChangesSince(const QDateTime &since)
{
QList<QUniqueId> changes = model->added(since);
foreach(const QUniqueId &id, changes) {
QTask t = model->task(id);
mySendAddedTask(t);
}
changes = model->removed(since);
foreach(const QUniqueId &id, changes) {
mySendRemovedTask(id);
}
changes = model->modified(since);
foreach(const QUniqueId &id, changes) {
QTask t = model->task(id);
mySendModifiedTask(t);
}
}
Tracking any identifier mapping, the last sync time and other synchronization bookkeeping is the responsibility of the protocol implementation. If an implementation of the above behavior is required its likely Desktop Synchronization will be a preferred starting point.
Applying remote changes
The second half of synchronization involves applying changes from the remote device or server to the device. This could be done using the usual functions for modifying PIM records, however to aid both performance and to help keep the synchronization transaction atomic some additional functions are provided.
QPimModel::startSyncTransaction() does two separate things. The first is that it starts an SQL database transaction. This allows all changes from this point onwards to be aborted or rolled back in the case that the synchronization is unsuccessful. The second thing it does is it changes the behavior of the behavior changelog to use the passed timestamp for all records added, removed or modified until the QPimModel::commitSyncTransaction() is called. This means all records modified as part of the sync will have the same, known, timestamp.
Given limits for nested SQL transaction its important to only attempt one data storage types sync transaction at a time.
QTaskModel tasks;
QContactModel contacts;
QDateTime syncTime = QDateTime::currentDateTime();
tasks.startSyncTransaction(syncTime);
contacts.startSyncTransaction(syncTime);
tasks.commitSyncTransaction();
contacts.commitSyncTransaction();
QDateTime syncTime = QDateTime::currentDateTime().toUTC();
tasks.startSyncTransaction(syncTime);
tasks.commitSyncTransaction();
contacts.startSyncTransaction(syncTime);
contacts.commitSyncTransaction();