plugins/versit/backuphandler/backupvcardhandler.cpp
changeset 5 603d3f8b6302
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 "backupvcardhandler.h"
       
    47 #include "qcontact.h"
       
    48 #include "qcontactdetail.h"
       
    49 #include "qversitdocument.h"
       
    50 #include "qversitproperty.h"
       
    51 
       
    52 QTM_USE_NAMESPACE
       
    53 
       
    54 /*
       
    55  * This is a map from Versit group names to the details that were generated from properties with the
       
    56  * said groups.  Multiple details can be associated with a single group.
       
    57  */
       
    58 class DetailGroupMap
       
    59 {
       
    60 public:
       
    61     QList<QContactDetail> detailsInGroup(const QString& groupName) const;
       
    62     void insert(const QString& groupName, const QContactDetail& detail);
       
    63     void update(const QContactDetail& detail);
       
    64     void clear();
       
    65 
       
    66 private:
       
    67     QHash<int, QString> mDetailGroupName; // detailid -> group name
       
    68     QHash<int, QContactDetail> mDetailById; // detailid -> detail
       
    69 };
       
    70 
       
    71 /* See QVersitContactImporter::createBackupHandler() */
       
    72 class BackupVCardHandler : public QVersitContactHandler
       
    73 {
       
    74 public:
       
    75     BackupVCardHandler();
       
    76     void propertyProcessed(const QVersitDocument& document,
       
    77                            const QVersitProperty& property,
       
    78                            const QContact& contact,
       
    79                            bool* alreadyProcessed,
       
    80                            QList<QContactDetail>* updatedDetails);
       
    81     void documentProcessed(const QVersitDocument& document,
       
    82                            QContact* contact);
       
    83     void detailProcessed(const QContact& contact,
       
    84                          const QContactDetail& detail,
       
    85                          const QVersitDocument& document,
       
    86                          QSet<QString>* processedFields,
       
    87                          QList<QVersitProperty>* toBeRemoved,
       
    88                          QList<QVersitProperty>* toBeAdded);
       
    89     void contactProcessed(const QContact& contact,
       
    90                           QVersitDocument* document);
       
    91 
       
    92 private:
       
    93     static QVariant deserializeValue(const QVersitProperty& property);
       
    94     static void serializeValue(QVersitProperty* property, const QVariant& value);
       
    95     DetailGroupMap mDetailGroupMap; // remembers which details came from which groups
       
    96     int mDetailNumber;
       
    97 };
       
    98 
       
    99 Q_DEFINE_LATIN1_CONSTANT(PropertyName, "X-NOKIA-QCONTACTFIELD");
       
   100 Q_DEFINE_LATIN1_CONSTANT(DetailDefinitionParameter, "DETAIL");
       
   101 Q_DEFINE_LATIN1_CONSTANT(FieldParameter, "FIELD");
       
   102 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameter, "DATATYPE");
       
   103 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterVariant, "VARIANT");
       
   104 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterDate, "DATE");
       
   105 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterDateTime, "DATETIME");
       
   106 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterTime, "TIME");
       
   107 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterBool, "BOOL");
       
   108 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterInt, "INT");
       
   109 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterUInt, "UINT");
       
   110 Q_DEFINE_LATIN1_CONSTANT(DatatypeParameterUrl, "URL");
       
   111 Q_DEFINE_LATIN1_CONSTANT(GroupPrefix, "G");
       
   112 
       
   113 QSet<QString> BackupVCardHandlerFactory::profiles() const
       
   114 {
       
   115     QSet<QString> retval;
       
   116     retval.insert(QVersitContactHandlerFactory::ProfileBackup);
       
   117     return retval;
       
   118 }
       
   119 
       
   120 QString BackupVCardHandlerFactory::name() const
       
   121 {
       
   122     return QLatin1String("com.nokia.qt.mobility.versit.backuphandler");
       
   123 }
       
   124 
       
   125 int BackupVCardHandlerFactory::index() const
       
   126 {
       
   127     // Prefer to run this plugin last.
       
   128     return -1;
       
   129 }
       
   130 
       
   131 QVersitContactHandler* BackupVCardHandlerFactory::createHandler() const
       
   132 {
       
   133     return new BackupVCardHandler();
       
   134 }
       
   135 
       
   136 Q_EXPORT_PLUGIN2(qtversit_backuphandler, BackupVCardHandlerFactory);
       
   137 
       
   138 /*
       
   139  * Returns a list of details generated from a Versit group.
       
   140  */
       
   141 QList<QContactDetail> DetailGroupMap::detailsInGroup(const QString& groupName) const
       
   142 {
       
   143     QList<int> detailIds = mDetailGroupName.keys(groupName);
       
   144     QList<QContactDetail> details;
       
   145     foreach (int detailId, detailIds) {
       
   146         details << mDetailById[detailId];
       
   147     }
       
   148     return details;
       
   149 }
       
   150 
       
   151 /*
       
   152  * Inserts the association between \a detail and \a groupName to the map.
       
   153  * The detail must have a key (ie. have already been saved in a contact) and the group name must not
       
   154  * be the empty string.
       
   155  */
       
   156 void DetailGroupMap::insert(const QString& groupName, const QContactDetail& detail)
       
   157 {
       
   158     Q_ASSERT(!groupName.isEmpty());
       
   159     mDetailGroupName[detail.key()] = groupName;
       
   160     mDetailById[detail.key()] = detail;
       
   161 }
       
   162 
       
   163 /*
       
   164  * Replaces the detail currently in the map with \a detail.
       
   165  * The detail must have a key (ie. have already been saved in a contact).
       
   166  */
       
   167 void DetailGroupMap::update(const QContactDetail& detail)
       
   168 {
       
   169     Q_ASSERT(detail.key());
       
   170     mDetailById[detail.key()] = detail;
       
   171 }
       
   172 
       
   173 /*!
       
   174  * Removes details and groups from the map.
       
   175  */
       
   176 void DetailGroupMap::clear()
       
   177 {
       
   178     mDetailGroupName.clear();
       
   179     mDetailById.clear();
       
   180 }
       
   181 
       
   182 
       
   183 BackupVCardHandler::BackupVCardHandler()
       
   184     : mDetailNumber(0)
       
   185 {
       
   186 }
       
   187 
       
   188 void BackupVCardHandler::propertyProcessed(
       
   189         const QVersitDocument& document,
       
   190         const QVersitProperty& property,
       
   191         const QContact& contact,
       
   192         bool* alreadyProcessed,
       
   193         QList<QContactDetail>* updatedDetails)
       
   194 {
       
   195     Q_UNUSED(document)
       
   196     Q_UNUSED(contact)
       
   197     QString group;
       
   198     if (!property.groups().isEmpty())
       
   199         group = property.groups().first();
       
   200     if (!*alreadyProcessed) {
       
   201         if (property.name() != PropertyName)
       
   202             return;
       
   203         if (property.groups().size() != 1)
       
   204             return;
       
   205         QMultiHash<QString,QString> parameters = property.parameters();
       
   206         QString definitionName = parameters.value(DetailDefinitionParameter);
       
   207         QString fieldName = parameters.value(FieldParameter);
       
   208 
       
   209         // Find a detail previously seen with the same definitionName, which was generated from
       
   210         // a property from the same group
       
   211         QContactDetail detail(definitionName);
       
   212         foreach (const QContactDetail& previousDetail, mDetailGroupMap.detailsInGroup(group)) {
       
   213             if (previousDetail.definitionName() == definitionName) {
       
   214                 detail = previousDetail;
       
   215             }
       
   216         }
       
   217         // If not found, it's a new empty detail with the definitionName set.
       
   218 
       
   219         detail.setValue(fieldName, deserializeValue(property));
       
   220 
       
   221         // Replace the equivalent detail in updatedDetails with the new one
       
   222         QMutableListIterator<QContactDetail> it(*updatedDetails);
       
   223         while (it.hasNext()) {
       
   224             if (it.next().key() == detail.key()) {
       
   225                 it.remove();
       
   226                 break;
       
   227             }
       
   228         }
       
   229         updatedDetails->append(detail);
       
   230         *alreadyProcessed = true;
       
   231     }
       
   232     if (!group.isEmpty()) {
       
   233         // Keep track of which details were generated from which Versit groups
       
   234         foreach (const QContactDetail& detail, *updatedDetails) {
       
   235             mDetailGroupMap.insert(group, detail);
       
   236         }
       
   237     }
       
   238 }
       
   239 
       
   240 QVariant BackupVCardHandler::deserializeValue(const QVersitProperty& property)
       
   241 {
       
   242     // Import the field
       
   243     if (property.parameters().contains(DatatypeParameter, DatatypeParameterVariant)) {
       
   244         // The value was stored as a QVariant serialized in a QByteArray
       
   245         QDataStream stream(property.variantValue().toByteArray());
       
   246         QVariant value;
       
   247         stream >> value;
       
   248         return value;
       
   249     } else if (property.parameters().contains(DatatypeParameter, DatatypeParameterDate)) {
       
   250         // The value was a QDate serialized as a string
       
   251         return QDate::fromString(property.value(), Qt::ISODate);
       
   252     } else if (property.parameters().contains(DatatypeParameter, DatatypeParameterTime)) {
       
   253         // The value was a QTime serialized as a string
       
   254         return QTime::fromString(property.value(), Qt::ISODate);
       
   255     } else if (property.parameters().contains(DatatypeParameter, DatatypeParameterDateTime)) {
       
   256         // The value was a QDateTime serialized as a string
       
   257         return QDateTime::fromString(property.value(), Qt::ISODate);
       
   258     } else if (property.parameters().contains(DatatypeParameter, DatatypeParameterBool)) {
       
   259         // The value was a bool serialized as a string
       
   260         return property.value().toInt() != 0;
       
   261     } else if (property.parameters().contains(DatatypeParameter, DatatypeParameterInt)) {
       
   262         // The value was an int serialized as a string
       
   263         return property.value().toInt();
       
   264     } else if (property.parameters().contains(DatatypeParameter, DatatypeParameterUInt)) {
       
   265         // The value was a uint serialized as a string
       
   266         return property.value().toUInt();
       
   267     } else if (property.parameters().contains(DatatypeParameter, DatatypeParameterUrl)) {
       
   268         // The value was a QUrl serialized as a string
       
   269         return QUrl(property.value());
       
   270     } else {
       
   271         // The value was stored as a QString or QByteArray
       
   272         return property.variantValue();
       
   273     }
       
   274 }
       
   275 
       
   276 void BackupVCardHandler::documentProcessed(
       
   277         const QVersitDocument& document,
       
   278         QContact* contact)
       
   279 {
       
   280     Q_UNUSED(document)
       
   281     Q_UNUSED(contact)
       
   282     mDetailGroupMap.clear();
       
   283 }
       
   284 
       
   285 void BackupVCardHandler::detailProcessed(
       
   286         const QContact& contact,
       
   287         const QContactDetail& detail,
       
   288         const QVersitDocument& document,
       
   289         QSet<QString>* processedFields,
       
   290         QList<QVersitProperty>* toBeRemoved,
       
   291         QList<QVersitProperty>* toBeAdded)
       
   292 {
       
   293     Q_UNUSED(contact)
       
   294     Q_UNUSED(document)
       
   295     Q_UNUSED(toBeRemoved)
       
   296     if (detail.accessConstraints().testFlag(QContactDetail::ReadOnly))
       
   297         return;
       
   298     QVariantMap fields = detail.variantValues();
       
   299     // fields from the same detail have the same group so the importer can collate them
       
   300     QString detailGroup = GroupPrefix + QString::number(mDetailNumber++);
       
   301     int toBeAddedCount = toBeAdded->count();
       
   302     bool propertiesSynthesized = false;
       
   303     for (QVariantMap::const_iterator it = fields.constBegin(); it != fields.constEnd(); it++) {
       
   304         if (!processedFields->contains(it.key()) && !it.value().toString().isEmpty()) {
       
   305             // Generate a property for the unknown field
       
   306             QVersitProperty property;
       
   307             property.setGroups(QStringList(detailGroup));
       
   308             property.setName(PropertyName);
       
   309             property.insertParameter(DetailDefinitionParameter, detail.definitionName());
       
   310             property.insertParameter(FieldParameter, it.key());
       
   311 
       
   312             serializeValue(&property, it.value());
       
   313 
       
   314             toBeAdded->append(property);
       
   315             propertiesSynthesized = true;
       
   316             processedFields->insert(it.key());
       
   317         }
       
   318     }
       
   319     if (propertiesSynthesized) {
       
   320         // We need to group the already-generated properties with the newly synthesized ones
       
   321         for (int i = 0; i < toBeAddedCount; i++) {
       
   322             QVersitProperty& property = (*toBeAdded)[i];
       
   323             property.setGroups(property.groups() << detailGroup);
       
   324         }
       
   325     }
       
   326 }
       
   327 
       
   328 void BackupVCardHandler::serializeValue(QVersitProperty* property, const QVariant& value)
       
   329 {
       
   330     // serialize the value
       
   331     if (value.type() == QVariant::String
       
   332         || value.type() == QVariant::ByteArray) {
       
   333         // store QStrings and QByteArrays as-is
       
   334         property->setValue(value);
       
   335     } else if (value.type() == QVariant::Date) {
       
   336         // Store a QDate as a string
       
   337         QString valueString(value.toDate().toString(Qt::ISODate));
       
   338         property->insertParameter(DatatypeParameter, DatatypeParameterDate);
       
   339         property->setValue(valueString);
       
   340     } else if (value.type() == QVariant::Time) {
       
   341         // Store a QTime as a string
       
   342         QString valueString(value.toTime().toString(Qt::ISODate));
       
   343         property->insertParameter(DatatypeParameter, DatatypeParameterTime);
       
   344         property->setValue(valueString);
       
   345     } else if (value.type() == QVariant::DateTime) {
       
   346         // Store a QDateTime as a string
       
   347         QString valueString(value.toDateTime().toString(Qt::ISODate));
       
   348         property->insertParameter(DatatypeParameter, DatatypeParameterDateTime);
       
   349         property->setValue(valueString);
       
   350     } else if (value.type() == QVariant::Bool) {
       
   351         // Store an int as a string
       
   352         QString valueString(QString::number(value.toBool() ? 1 : 0));
       
   353         property->insertParameter(DatatypeParameter, DatatypeParameterBool);
       
   354         property->setValue(valueString);
       
   355     } else if (value.type() == QVariant::Int) {
       
   356         // Store an int as a string
       
   357         QString valueString(QString::number(value.toInt()));
       
   358         property->insertParameter(DatatypeParameter, DatatypeParameterInt);
       
   359         property->setValue(valueString);
       
   360     } else if (value.type() == QVariant::UInt) {
       
   361         // Store a uint as a string
       
   362         QString valueString(QString::number(value.toUInt()));
       
   363         property->insertParameter(DatatypeParameter, DatatypeParameterUInt);
       
   364         property->setValue(valueString);
       
   365     } else if (value.type() == QVariant::Url) {
       
   366         // Store a QUrl as a string
       
   367         QString valueString(value.toUrl().toString());
       
   368         property->insertParameter(DatatypeParameter, DatatypeParameterUrl);
       
   369         property->setValue(valueString);
       
   370     } else {
       
   371         // Store other types by serializing the QVariant in a QByteArray
       
   372         QByteArray valueBytes;
       
   373         QDataStream stream(&valueBytes, QIODevice::WriteOnly);
       
   374         stream << value;
       
   375         property->insertParameter(DatatypeParameter, DatatypeParameterVariant);
       
   376         property->setValue(valueBytes);
       
   377     }
       
   378 }
       
   379 
       
   380 void BackupVCardHandler::contactProcessed(
       
   381         const QContact& contact,
       
   382         QVersitDocument* document)
       
   383 {
       
   384     Q_UNUSED(contact)
       
   385     Q_UNUSED(document)
       
   386     mDetailNumber = 0;
       
   387 }