src/versit/qvcardbackuphandlers_p.cpp
changeset 5 603d3f8b6302
parent 3 e4ebb16b39ea
equal deleted inserted replaced
3:e4ebb16b39ea 5:603d3f8b6302
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QList>
       
    43 #include <QString>
       
    44 #include <QTextStream>
       
    45 #include <QUrl>
       
    46 #include "qvcardbackuphandlers_p.h"
       
    47 #include "qcontact.h"
       
    48 #include "qcontactdetail.h"
       
    49 #include "qversitdocument.h"
       
    50 #include "qversitproperty.h"
       
    51 
       
    52 QTM_USE_NAMESPACE
       
    53 
       
    54 QTM_BEGIN_NAMESPACE
       
    55 
       
    56 Q_DEFINE_LATIN1_CONSTANT(PropertyName, "X-NOKIA-QCONTACTFIELD");
       
    57 Q_DEFINE_LATIN1_CONSTANT(DetailDefinitionParameter, "DETAIL");
       
    58 Q_DEFINE_LATIN1_CONSTANT(FieldParameter, "FIELD");
       
    59 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameter, "DATATYPE");
       
    60 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterVariant, "VARIANT");
       
    61 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterDate, "DATE");
       
    62 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterDateTime, "DATETIME");
       
    63 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterTime, "TIME");
       
    64 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterBool, "BOOL");
       
    65 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterInt, "INT");
       
    66 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterUInt, "UINT");
       
    67 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterUrl, "URL");
       
    68 Q_DEFINE_LATIN1_CONSTANT(GroupPrefix, "G");
       
    69 
       
    70 QTM_END_NAMESPACE
       
    71 
       
    72 /*
       
    73  * Returns a list of details generated from a Versit group.
       
    74  */
       
    75 QList<QContactDetail> DetailGroupMap::detailsInGroup(const QString& groupName) const
       
    76 {
       
    77     QList<int> detailIds = mDetailGroupName.keys(groupName);
       
    78     QList<QContactDetail> details;
       
    79     foreach (int detailId, detailIds) {
       
    80         details << mDetailById[detailId];
       
    81     }
       
    82     return details;
       
    83 }
       
    84 
       
    85 /*
       
    86  * Inserts the association between \a detail and \a groupName to the map.
       
    87  * The detail must have a key (ie. have already been saved in a contact) and the group name must not
       
    88  * be the empty string.
       
    89  */
       
    90 void DetailGroupMap::insert(const QString& groupName, const QContactDetail& detail)
       
    91 {
       
    92     Q_ASSERT(!groupName.isEmpty());
       
    93     mDetailGroupName[detail.key()] = groupName;
       
    94     mDetailById[detail.key()] = detail;
       
    95 }
       
    96 
       
    97 /*
       
    98  * Replaces the detail currently in the map with \a detail.
       
    99  * The detail must have a key (ie. have already been saved in a contact).
       
   100  */
       
   101 void DetailGroupMap::update(const QContactDetail& detail)
       
   102 {
       
   103     Q_ASSERT(detail.key());
       
   104     mDetailById[detail.key()] = detail;
       
   105 }
       
   106 
       
   107 /*!
       
   108  * Removes details and groups from the map.
       
   109  */
       
   110 void DetailGroupMap::clear()
       
   111 {
       
   112     mDetailGroupName.clear();
       
   113     mDetailById.clear();
       
   114 }
       
   115 
       
   116 
       
   117 QVCardImporterBackupHandler::QVCardImporterBackupHandler()
       
   118 {
       
   119 }
       
   120 
       
   121 void QVCardImporterBackupHandler::propertyProcessed(
       
   122         const QVersitDocument& document,
       
   123         const QVersitProperty& property,
       
   124         bool alreadyProcessed,
       
   125         const QContact& contact,
       
   126         QList<QContactDetail>* updatedDetails)
       
   127 {
       
   128     Q_UNUSED(document)
       
   129     Q_UNUSED(contact)
       
   130     QString group;
       
   131     if (!property.groups().isEmpty())
       
   132         group = property.groups().first();
       
   133     if (!alreadyProcessed) {
       
   134         if (property.name() != PropertyName)
       
   135             return;
       
   136         if (property.groups().size() != 1)
       
   137             return;
       
   138         QMultiHash<QString,QString> parameters = property.parameters();
       
   139         QString definitionName = parameters.value(DetailDefinitionParameter);
       
   140         QString fieldName = parameters.value(FieldParameter);
       
   141 
       
   142         // Find a detail previously seen with the same definitionName, which was generated from
       
   143         // a property from the same group
       
   144         QContactDetail detail(definitionName);
       
   145         foreach (const QContactDetail& previousDetail, mDetailGroupMap.detailsInGroup(group)) {
       
   146             if (previousDetail.definitionName() == definitionName) {
       
   147                 detail = previousDetail;
       
   148             }
       
   149         }
       
   150         // If not found, it's a new empty detail with the definitionName set.
       
   151 
       
   152         detail.setValue(fieldName, deserializeValue(property));
       
   153 
       
   154         // Replace the equivalent detail in updatedDetails with the new one
       
   155         QMutableListIterator<QContactDetail> it(*updatedDetails);
       
   156         while (it.hasNext()) {
       
   157             if (it.next().key() == detail.key()) {
       
   158                 it.remove();
       
   159                 break;
       
   160             }
       
   161         }
       
   162         updatedDetails->append(detail);
       
   163     }
       
   164     if (!group.isEmpty()) {
       
   165         // Keep track of which details were generated from which Versit groups
       
   166         foreach (const QContactDetail& detail, *updatedDetails) {
       
   167             mDetailGroupMap.insert(group, detail);
       
   168         }
       
   169     }
       
   170 }
       
   171 
       
   172 QVariant QVCardImporterBackupHandler::deserializeValue(const QVersitProperty& property)
       
   173 {
       
   174     // Import the field
       
   175     if (property.parameters().contains(DatatypeParameter, DatatypeParameterVariant)) {
       
   176         // The value was stored as a QVariant serialized in a QByteArray
       
   177         QDataStream stream(property.variantValue().toByteArray());
       
   178         QVariant value;
       
   179         stream >> value;
       
   180         return value;
       
   181     } else if (property.parameters().contains(DatatypeParameter, DatatypeParameterDate)) {
       
   182         // The value was a QDate serialized as a string
       
   183         return QDate::fromString(property.value(), Qt::ISODate);
       
   184     } else if (property.parameters().contains(DatatypeParameter, DatatypeParameterTime)) {
       
   185         // The value was a QTime serialized as a string
       
   186         return QTime::fromString(property.value(), Qt::ISODate);
       
   187     } else if (property.parameters().contains(DatatypeParameter, DatatypeParameterDateTime)) {
       
   188         // The value was a QDateTime serialized as a string
       
   189         return QDateTime::fromString(property.value(), Qt::ISODate);
       
   190     } else if (property.parameters().contains(DatatypeParameter, DatatypeParameterBool)) {
       
   191         // The value was a bool serialized as a string
       
   192         return property.value().toInt() != 0;
       
   193     } else if (property.parameters().contains(DatatypeParameter, DatatypeParameterInt)) {
       
   194         // The value was an int serialized as a string
       
   195         return property.value().toInt();
       
   196     } else if (property.parameters().contains(DatatypeParameter, DatatypeParameterUInt)) {
       
   197         // The value was a uint serialized as a string
       
   198         return property.value().toUInt();
       
   199     } else if (property.parameters().contains(DatatypeParameter, DatatypeParameterUrl)) {
       
   200         // The value was a QUrl serialized as a string
       
   201         return QUrl(property.value());
       
   202     } else {
       
   203         // The value was stored as a QString or QByteArray
       
   204         return property.variantValue();
       
   205     }
       
   206 }
       
   207 
       
   208 void QVCardImporterBackupHandler::documentProcessed(
       
   209         const QVersitDocument& document,
       
   210         QContact* contact)
       
   211 {
       
   212     Q_UNUSED(document)
       
   213     Q_UNUSED(contact)
       
   214     mDetailGroupMap.clear();
       
   215 }
       
   216 
       
   217 QVCardExporterBackupHandler::QVCardExporterBackupHandler()
       
   218     : mDetailNumber(0)
       
   219 {
       
   220 }
       
   221 
       
   222 void QVCardExporterBackupHandler::detailProcessed(
       
   223         const QContact& contact,
       
   224         const QContactDetail& detail,
       
   225         const QSet<QString>& processedFields,
       
   226         const QVersitDocument& document,
       
   227         QList<QVersitProperty>* toBeRemoved,
       
   228         QList<QVersitProperty>* toBeAdded)
       
   229 {
       
   230     Q_UNUSED(contact)
       
   231     Q_UNUSED(document)
       
   232     Q_UNUSED(toBeRemoved)
       
   233     if (detail.accessConstraints().testFlag(QContactDetail::ReadOnly))
       
   234         return;
       
   235     QVariantMap fields = detail.variantValues();
       
   236     // fields from the same detail have the same group so the importer can collate them
       
   237     QString detailGroup = GroupPrefix + QString::number(mDetailNumber++);
       
   238     int toBeAddedCount = toBeAdded->count();
       
   239     bool propertiesSynthesized = false;
       
   240     for (QVariantMap::const_iterator it = fields.constBegin(); it != fields.constEnd(); it++) {
       
   241         if (!processedFields.contains(it.key()) && !it.value().toString().isEmpty()) {
       
   242             // Generate a property for the unknown field
       
   243             QVersitProperty property;
       
   244             property.setGroups(QStringList(detailGroup));
       
   245             property.setName(PropertyName);
       
   246             property.insertParameter(DetailDefinitionParameter, detail.definitionName());
       
   247             property.insertParameter(FieldParameter, it.key());
       
   248 
       
   249             serializeValue(&property, it.value());
       
   250 
       
   251             toBeAdded->append(property);
       
   252             propertiesSynthesized = true;
       
   253         }
       
   254     }
       
   255     if (propertiesSynthesized) {
       
   256         // We need to group the already-generated properties with the newly synthesized ones
       
   257         for (int i = 0; i < toBeAddedCount; i++) {
       
   258             QVersitProperty& property = (*toBeAdded)[i];
       
   259             property.setGroups(property.groups() << detailGroup);
       
   260         }
       
   261     }
       
   262 }
       
   263 
       
   264 void QVCardExporterBackupHandler::serializeValue(QVersitProperty* property, const QVariant& value)
       
   265 {
       
   266     // serialize the value
       
   267     if (value.type() == QVariant::String
       
   268         || value.type() == QVariant::ByteArray) {
       
   269         // store QStrings and QByteArrays as-is
       
   270         property->setValue(value);
       
   271     } else if (value.type() == QVariant::Date) {
       
   272         // Store a QDate as a string
       
   273         QString valueString(value.toDate().toString(Qt::ISODate));
       
   274         property->insertParameter(DatatypeParameter, DatatypeParameterDate);
       
   275         property->setValue(valueString);
       
   276     } else if (value.type() == QVariant::Time) {
       
   277         // Store a QTime as a string
       
   278         QString valueString(value.toTime().toString(Qt::ISODate));
       
   279         property->insertParameter(DatatypeParameter, DatatypeParameterTime);
       
   280         property->setValue(valueString);
       
   281     } else if (value.type() == QVariant::DateTime) {
       
   282         // Store a QDateTime as a string
       
   283         QString valueString(value.toDateTime().toString(Qt::ISODate));
       
   284         property->insertParameter(DatatypeParameter, DatatypeParameterDateTime);
       
   285         property->setValue(valueString);
       
   286     } else if (value.type() == QVariant::Bool) {
       
   287         // Store an int as a string
       
   288         QString valueString(QString::number(value.toBool() ? 1 : 0));
       
   289         property->insertParameter(DatatypeParameter, DatatypeParameterBool);
       
   290         property->setValue(valueString);
       
   291     } else if (value.type() == QVariant::Int) {
       
   292         // Store an int as a string
       
   293         QString valueString(QString::number(value.toInt()));
       
   294         property->insertParameter(DatatypeParameter, DatatypeParameterInt);
       
   295         property->setValue(valueString);
       
   296     } else if (value.type() == QVariant::UInt) {
       
   297         // Store a uint as a string
       
   298         QString valueString(QString::number(value.toUInt()));
       
   299         property->insertParameter(DatatypeParameter, DatatypeParameterUInt);
       
   300         property->setValue(valueString);
       
   301     } else if (value.type() == QVariant::Url) {
       
   302         // Store a QUrl as a string
       
   303         QString valueString(value.toUrl().toString());
       
   304         property->insertParameter(DatatypeParameter, DatatypeParameterUrl);
       
   305         property->setValue(valueString);
       
   306     } else {
       
   307         // Store other types by serializing the QVariant in a QByteArray
       
   308         QByteArray valueBytes;
       
   309         QDataStream stream(&valueBytes, QIODevice::WriteOnly);
       
   310         stream << value;
       
   311         property->insertParameter(DatatypeParameter, DatatypeParameterVariant);
       
   312         property->setValue(valueBytes);
       
   313     }
       
   314 }
       
   315 
       
   316 void QVCardExporterBackupHandler::contactProcessed(
       
   317         const QContact& contact,
       
   318         QVersitDocument* document)
       
   319 {
       
   320     Q_UNUSED(contact)
       
   321     Q_UNUSED(document)
       
   322     mDetailNumber = 0;
       
   323 }