qtmobility/src/versit/qversitcontactimporter_p.cpp
changeset 4 90517678cc4f
parent 1 2b40d63a9c3d
child 8 71781823f776
--- a/qtmobility/src/versit/qversitcontactimporter_p.cpp	Fri Apr 16 15:51:22 2010 +0300
+++ b/qtmobility/src/versit/qversitcontactimporter_p.cpp	Mon May 03 13:18:40 2010 +0300
@@ -45,6 +45,7 @@
 #include "qversitproperty.h"
 #include "qmobilityglobal.h"
 
+#include <qcontactmanagerengine.h>
 #include <qcontact.h>
 #include <qcontactdetail.h>
 #include <qcontactname.h>
@@ -65,6 +66,8 @@
 #include <qcontactonlineaccount.h>
 #include <qcontactfamily.h>
 #include <qcontactdisplaylabel.h>
+#include <qcontactthumbnail.h>
+#include <qcontactringtone.h>
 
 #include <QHash>
 #include <QFile>
@@ -122,24 +125,35 @@
 /*!
  * Generates a QContact from \a versitDocument.
  */
-QContact QVersitContactImporterPrivate::importContact(
-     const QVersitDocument& document, int contactIndex)
+bool QVersitContactImporterPrivate::importContact(
+        const QVersitDocument& document, int contactIndex, QContact* contact,
+        QVersitContactImporter::Error* error)
 {
-    QContact contact;
+    if (document.type() != QVersitDocument::VCard21Type
+        && document.type() != QVersitDocument::VCard30Type) {
+        *error = QVersitContactImporter::InvalidDocumentError;
+        return false;
+    }
     const QList<QVersitProperty> properties = document.properties();
+    if (properties.size() == 0) {
+        *error = QVersitContactImporter::EmptyDocumentError;
+        return false;
+    }
+
     // First, do the properties with PREF set so they appear first in the contact details
     foreach (const QVersitProperty& property, properties) {
         if (property.parameters().contains(QLatin1String("TYPE"), QLatin1String("PREF")))
-            importProperty(document, property, contactIndex, &contact);
+            importProperty(document, property, contactIndex, contact);
     }
     // ... then, do the rest of the properties.
     foreach (const QVersitProperty& property, properties) {
         if (!property.parameters().contains(QLatin1String("TYPE"), QLatin1String("PREF")))
-            importProperty(document, property, contactIndex, &contact);
+            importProperty(document, property, contactIndex, contact);
     }
 
-    contact.setType(QContactType::TypeContact);
-    return contact;
+    contact->setType(QContactType::TypeContact);
+    QContactManagerEngine::setContactDisplayLabel(contact, QVersitContactImporterPrivate::synthesizedDisplayLabel(*contact));
+    return true;
 }
 
 void QVersitContactImporterPrivate::importProperty(
@@ -166,8 +180,10 @@
         success = createOrganization(property, contact);
     } else if (detailDefinitionName == QContactNickname::DefinitionName) {
         success = createNicknames(property, contact);
-    } else if (detailDefinitionName == QContactAvatar::DefinitionName) {
-        success = createAvatar(property,detailDefinition.second, contact);
+    } else if (detailDefinitionName == QContactRingtone::DefinitionName) {
+        success = createRingtone(property, contact);
+    } else if (detailDefinitionName == QContactThumbnail::DefinitionName) {
+        success = createThumbnail(property, contact);
     } else if (detailDefinitionName == QContactTimestamp::DefinitionName) {
         success = createTimeStamp(property, contact);
     } else if (detailDefinitionName == QContactPhoneNumber::DefinitionName) {
@@ -178,9 +194,11 @@
         success = createFamily(property, contact);
     } else if (detailDefinitionName == QContactOnlineAccount::DefinitionName) {
         success = createOnlineAccount(property, contact);
+    } else if (detailDefinitionName == QContactTag::DefinitionName) {
+        success = createTags(property, contact);
     } else if (detailDefinitionName == QContactDisplayLabel::DefinitionName) {
         // This actually sets the QContactName's customLabel field (not QContactDisplayLabel)
-        success = createLabel(property, contact);
+        success = createCustomLabel(property, contact);
     } else {
         // Look up mDetailMappings for a simple mapping from property to detail.
         success = createNameValueDetail(property, contact);
@@ -199,14 +217,18 @@
     QContactDetail detail = contact->detail(QContactName::DefinitionName);
     if (!detail.isEmpty()) {
         // If multiple name properties exist,
-        // discard all except the first occurence
+        // discard all except the first occurrence
         if (!detail.value(QContactName::FieldFirstName).isEmpty())
             return false;
         else
             name = QContactName(static_cast<QContactName>(detail));
     }
 
-    QStringList values = property.value().split(QLatin1Char(';'));
+    QVariant variant = property.variantValue();
+    if (property.valueType() != QVersitProperty::CompoundType
+            || variant.type() != QVariant::StringList)
+        return false;
+    QStringList values = variant.toStringList();
     name.setLastName(takeFirst(values));
     name.setFirstName(takeFirst(values));
     name.setMiddleName(takeFirst(values));
@@ -239,7 +261,11 @@
 {
     QContactAddress address;
 
-    QStringList addressParts = property.value().split(QLatin1Char(';'));
+    QVariant variant = property.variantValue();
+    if (property.valueType() != QVersitProperty::CompoundType
+            || variant.type() != QVariant::StringList)
+        return false;
+    QStringList addressParts = variant.toStringList();
     address.setPostOfficeBox(takeFirst(addressParts));
     // There is no setter for the Extended Address in QContactAddress:
     if (!addressParts.isEmpty())
@@ -266,7 +292,7 @@
         mDetailMappings.value(property.name());
     QString fieldName = detailNameAndFieldName.second;
     QList<QContactOrganization> organizations = contact->details<QContactOrganization>();
-    foreach(QContactOrganization current, organizations) {
+    foreach(const QContactOrganization& current, organizations) {
         if (current.value(fieldName).length() == 0) {
             organization = current;
             break;
@@ -278,7 +304,7 @@
         organization.setTitle(property.value());
     } else if (fieldName == QContactOrganization::FieldRole) {
         organization.setRole(property.value());
-    } else if (fieldName == QContactOrganization::FieldLogo) {
+    } else if (fieldName == QContactOrganization::FieldLogoUrl) {
         setOrganizationLogo(organization, property);
     } else if (fieldName == QContactOrganization::FieldAssistantName) {
         organization.setAssistantName(property.value());
@@ -296,16 +322,12 @@
 void QVersitContactImporterPrivate::setOrganizationNames(
     QContactOrganization& organization, const QVersitProperty& property) const
 {
-    QString value = property.value();
-    int firstSemicolon = value.indexOf(QLatin1Char(';'));
-    if (firstSemicolon >= 0) {
-        organization.setName(value.left(firstSemicolon));
-        QString departmentsStr(value.mid(firstSemicolon+1));
-        QStringList departments =
-            departmentsStr.split(QLatin1Char(';'), QString::SkipEmptyParts);
-        organization.setDepartment(departments);
-    } else {
-        organization.setName(value);
+    QVariant variant = property.variantValue();
+    if (property.valueType() == QVersitProperty::CompoundType
+        && variant.type() == QVariant::StringList) {
+        QStringList values = variant.toStringList();
+        organization.setName(takeFirst(values));
+        organization.setDepartment(values);
     }
 }
 
@@ -319,7 +341,7 @@
     QByteArray data;
     saveDataFromProperty(property, &location, &data);
     if (!location.isEmpty())
-        org.setLogo(location);
+        org.setLogoUrl(QUrl(location));
 }
 
 /*!
@@ -379,12 +401,36 @@
 bool QVersitContactImporterPrivate::createNicknames(
     const QVersitProperty& property, QContact* contact) const
 {
-    QStringList values = property.value().split(QLatin1Char(','), QString::SkipEmptyParts);
+    QVariant variant = property.variantValue();
+    if (property.valueType() != QVersitProperty::ListType
+            || variant.type() != QVariant::StringList)
+        return false;
+    QStringList values = variant.toStringList();
     QStringList contexts = extractContexts(property);
-    foreach(QString value, values) {
+    foreach(const QString& value, values) {
         QContactNickname nickName;
         nickName.setNickname(value);
-        saveDetailWithContext(contact, &nickName, extractContexts(property));
+        saveDetailWithContext(contact, &nickName, contexts);
+    }
+    return true;
+}
+
+/*!
+ * Creates QContactTags from \a property and adds them to \a contact
+ */
+bool QVersitContactImporterPrivate::createTags(
+    const QVersitProperty& property, QContact* contact) const
+{
+    QVariant variant = property.variantValue();
+    if (property.valueType() != QVersitProperty::ListType
+            || variant.type() != QVariant::StringList)
+        return false;
+    QStringList values = variant.toStringList();
+    QStringList contexts = extractContexts(property);
+    foreach(const QString& value, values) {
+        QContactTag tag;
+        tag.setTag(value);
+        saveDetailWithContext(contact, &tag, contexts);
     }
     return true;
 }
@@ -416,31 +462,50 @@
     return true;
 }
 
+bool QVersitContactImporterPrivate::createRingtone(const QVersitProperty &property,
+                                                   QContact *contact) const
+{
+    QString location;
+    QByteArray data;
+    if (saveDataFromProperty(property, &location, &data) && !location.isEmpty()) {
+        QContactRingtone ringtone;
+        ringtone.setAudioRingtoneUrl(location);
+        saveDetailWithContext(contact, &ringtone, extractContexts(property));
+        return true;
+    }
+    return false;
+}
+
 /*!
  * Creates a QContactAvatar from \a property
  */
-bool QVersitContactImporterPrivate::createAvatar(
-    const QVersitProperty& property, const QString& subType, QContact* contact) const
+bool QVersitContactImporterPrivate::createThumbnail(
+    const QVersitProperty& property, QContact* contact) const
 {
     QString location;
     QByteArray data;
-    if (!(saveDataFromProperty(property, &location, &data)))
-        return false;
+    bool success = false;
 
-    QContactAvatar avatar;
-    if (!location.isEmpty())
-        avatar.setAvatar(location);
-    // Creating a pixmap in a non-GUI thread crashes on S60.
-    // XXX reenable this when the QtContacts stores QImages.
-//    if (subType == QContactAvatar::SubTypeImage && !data.isEmpty()) {
-//        QPixmap pixmap;
-//        if (pixmap.loadFromData(data))
-//            avatar.setPixmap(pixmap);
-//    }
-    avatar.setSubType(subType);
+    if (saveDataFromProperty(property, &location, &data) && !location.isEmpty()) {
+        QContactAvatar avatar;
+        avatar.setImageUrl(location);
+        saveDetailWithContext(contact, &avatar, extractContexts(property));
+        success = true;
+    }
+    if (!data.isEmpty()) {
+        QImage image;
+        if (image.loadFromData(data)) {
+            QContactThumbnail thumbnail = contact->detail<QContactThumbnail>();
+            // In the case of multiple thumbnails, pick the smallest one.
+            if (thumbnail.isEmpty() || image.byteCount() < thumbnail.thumbnail().byteCount()) {
+                thumbnail.setThumbnail(image);
+            }
+            saveDetailWithContext(contact, &thumbnail, extractContexts(property));
+            success = true;
+        }
+    }
 
-    saveDetailWithContext(contact, &avatar, extractContexts(property));
-    return true;
+    return success;
 }
 
 /*!
@@ -450,7 +515,11 @@
     const QVersitProperty& property, QContact* contact) const
 {
     QContactGeoLocation geo;
-    QStringList values = property.value().split(QLatin1Char(','));
+    QVariant variant = property.variantValue();
+    if (property.valueType() != QVersitProperty::CompoundType
+            || variant.type() != QVariant::StringList)
+        return false;
+    QStringList values = variant.toStringList();
     geo.setLongitude(takeFirst(values).toDouble());
     geo.setLatitude(takeFirst(values).toDouble());
 
@@ -469,7 +538,12 @@
     if (property.name() == QLatin1String("X-SPOUSE")) {
         family.setSpouse(val);
     } else if (property.name() == QLatin1String("X-CHILDREN")) {
-        family.setChildren(val.split(QLatin1String(",")));
+        QVariant variant = property.variantValue();
+        if (property.valueType() != QVersitProperty::ListType
+                || variant.type() != QVariant::StringList)
+            return false;
+        QStringList values = variant.toStringList();
+        family.setChildren(values);
     }
 
     saveDetailWithContext(contact, &family, extractContexts(property));
@@ -497,7 +571,7 @@
 /*!
  * Creates a simple name-value contact detail.
  */
-bool QVersitContactImporterPrivate::createLabel(
+bool QVersitContactImporterPrivate::createCustomLabel(
     const QVersitProperty& property, QContact* contact) const
 {
     QContactName name;
@@ -521,7 +595,7 @@
     QStringList types =
         property.parameters().values(QLatin1String("TYPE"));
     QStringList contexts;
-    foreach (QString type, types) {
+    foreach (const QString& type, types) {
         QString value = mContextMappings.value(type);
         if (value.length() > 0)
             contexts.append(value);
@@ -538,7 +612,7 @@
     QStringList types =
         property.parameters().values(QLatin1String("TYPE"));
     QStringList subTypes;
-    foreach (QString type, types) {
+    foreach (const QString& type, types) {
         QString subType = mSubTypeMappings.value(type);
         if (subType.length() > 0)
             subTypes += subType;
@@ -620,3 +694,66 @@
         detail->setContexts(contexts);
     contact->saveDetail(detail);
 }
+
+/*! Synthesize the display label from the name of the contact, or, failing that, the nickname of
+the contact, or failing that, the organisation of the contact.
+Returns the synthesized display label.
+ */
+QString QVersitContactImporterPrivate::synthesizedDisplayLabel(const QContact& contact)
+{
+    /* XXX This is copied and modified from QContactManagerEngine.  This should be made a public
+       static function in QCME and called here */
+    QList<QContactName> allNames = contact.details<QContactName>();
+
+    const QLatin1String space(" ");
+
+    // synthesize the display label from the name.
+    foreach (const QContactName& name, allNames) {
+        if (!name.customLabel().isEmpty()) {
+            // default behaviour is to allow the user to define a custom display label.
+            return name.customLabel();
+        }
+
+        QString result;
+        if (!name.value(QContactName::FieldPrefix).trimmed().isEmpty()) {
+           result += name.value(QContactName::FieldPrefix);
+        }
+        if (!name.value(QContactName::FieldFirstName).trimmed().isEmpty()) {
+            if (!result.isEmpty())
+                result += space;
+            result += name.value(QContactName::FieldFirstName);
+        }
+        if (!name.value(QContactName::FieldMiddleName).trimmed().isEmpty()) {
+            if (!result.isEmpty())
+                result += space;
+            result += name.value(QContactName::FieldMiddleName);
+        }
+        if (!name.value(QContactName::FieldLastName).trimmed().isEmpty()) {
+            if (!result.isEmpty())
+                result += space;
+            result += name.value(QContactName::FieldLastName);
+        }
+        if (!name.value(QContactName::FieldSuffix).trimmed().isEmpty()) {
+            if (!result.isEmpty())
+                result += space;
+            result += name.value(QContactName::FieldSuffix);
+        }
+        if (!result.isEmpty())
+            return result;
+    }
+
+    QList<QContactNickname> allNicknames = contact.details<QContactNickname>();
+    foreach (const QContactNickname& nickname, allNicknames) {
+        if (!nickname.nickname().isEmpty())
+            return nickname.nickname();
+    }
+
+    /* Well, we had no non empty names. if we have orgs, fall back to those */
+    QList<QContactOrganization> allOrgs = contact.details<QContactOrganization>();
+    foreach (const QContactOrganization& org, allOrgs) {
+        if (!org.name().isEmpty())
+            return org.name();
+    }
+
+    return QString();
+}