qtmobility/src/versit/qversitcontactexporter_p.cpp
changeset 4 90517678cc4f
parent 1 2b40d63a9c3d
child 8 71781823f776
--- a/qtmobility/src/versit/qversitcontactexporter_p.cpp	Fri Apr 16 15:51:22 2010 +0300
+++ b/qtmobility/src/versit/qversitcontactexporter_p.cpp	Mon May 03 13:18:40 2010 +0300
@@ -65,6 +65,7 @@
 #include <qcontactonlineaccount.h>
 #include <qcontactfamily.h>
 #include <qcontactdisplaylabel.h>
+#include <qcontactthumbnail.h>
 
 #include <QUrl>
 #include <QBuffer>
@@ -119,12 +120,17 @@
 /*!
  * Export QT Contact into Versit Document.
  */
-void QVersitContactExporterPrivate::exportContact(
+bool QVersitContactExporterPrivate::exportContact(
     const QContact& contact,
-    QVersitDocument& document)
+    QVersitDocument& document,
+    QVersitContactExporter::Error* error)
 {
     mVersitType = document.type();
     QList<QContactDetail> allDetails = contact.details();
+    if (allDetails.isEmpty()) {
+        *error = QVersitContactExporter::EmptyContactError;
+        return false;
+    }
     for (int i = 0; i < allDetails.size(); i++) {
         QContactDetail detail = allDetails.at(i);
 
@@ -161,6 +167,12 @@
         } else if (detail.definitionName() == QContactOrganization::DefinitionName) {
             encodeOrganization(document, detail);
             addProperty = false;
+        } else if (detail.definitionName() == QContactRingtone::DefinitionName) {
+            addProperty = encodeRingtone(property, detail);
+        } else if (detail.definitionName() == QContactThumbnail::DefinitionName) {
+            addProperty = encodeThumbnail(property, detail);
+            if (!addProperty)
+                unknown = true;
         } else if (detail.definitionName() == QContactAvatar::DefinitionName){
             addProperty = encodeAvatar(property, detail);
             if (!addProperty)
@@ -170,6 +182,9 @@
         } else if (detail.definitionName() == QContactNickname::DefinitionName) {
             encodeNickname(document, detail);
             addProperty = false;
+        } else if (detail.definitionName() == QContactTag::DefinitionName) {
+            encodeTag(document, detail);
+            addProperty = false;
         } else if (detail.definitionName() == QContactGender::DefinitionName) {
             encodeGender(property, detail);
         } else if (detail.definitionName() == QContactOnlineAccount::DefinitionName) {
@@ -187,12 +202,34 @@
             unknown = true;
         }
 
-        if (addProperty)
+        if (addProperty) {
             document.addProperty(property);
+        }
 
         if (mDetailHandler)
             mDetailHandler->postProcessDetail(contact, detail, !unknown, &document);
     }
+
+    // Search through the document for FN or N properties.  This will find it even if it was added
+    // by a detail handler.
+    if (!documentContainsName(document)) {
+        *error = QVersitContactExporter::NoNameError;
+        return false;
+    }
+    return true;
+}
+
+/*!
+ * Returns true if and only if \a document has a "FN" or "N" property.
+ */
+bool QVersitContactExporterPrivate::documentContainsName(const QVersitDocument &document)
+{
+    foreach (const QVersitProperty& property, document.properties()) {
+        const QString& name = property.name();
+        if (name == QLatin1String("FN") || name == QLatin1String("N"))
+            return true;
+    }
+    return false;
 }
 
 /*!
@@ -203,12 +240,13 @@
     const QContactDetail& detail)
 {
     QContactName contactName = static_cast<QContactName>(detail);
-    property.setValue(QString::fromAscii("%1;%2;%3;%4;%5").arg(
-            escape(contactName.lastName()),
-            escape(contactName.firstName()),
-            escape(contactName.middleName()),
-            escape(contactName.prefix()),
-            escape(contactName.suffix())));
+    property.setValue(QStringList()
+                      << contactName.lastName()
+                      << contactName.firstName()
+                      << contactName.middleName()
+                      << contactName.prefix()
+                      << contactName.suffix());
+    property.setValueType(QVersitProperty::CompoundType);
 }
 
 /*!
@@ -220,7 +258,7 @@
 {
     QContactPhoneNumber phoneNumber = static_cast<QContactPhoneNumber>(detail);
     encodeParameters(property, phoneNumber.contexts(), phoneNumber.subTypes());
-    setEscapedValue(property,phoneNumber.number());
+    property.setValue(phoneNumber.number());
 }
 
 /*!
@@ -232,7 +270,7 @@
 {
     QContactEmailAddress emailAddress = static_cast<QContactEmailAddress>(detail);
     encodeParameters(property, emailAddress.contexts());
-    setEscapedValue(property,emailAddress.emailAddress());
+    property.setValue(emailAddress.emailAddress());
 }
 
 /*!
@@ -244,14 +282,15 @@
 {
     QContactAddress address = static_cast<QContactAddress>(detail);
     encodeParameters(property, address.contexts(), address.subTypes());
-    // Leave out the extended address field:
-    property.setValue(QString::fromAscii("%1;;%2;%3;%4;%5;%6").arg(
-            escape(address.postOfficeBox()),
-            escape(address.street()),
-            escape(address.locality()),
-            escape(address.region()),
-            escape(address.postcode()),
-            escape(address.country())));
+    property.setValue(QStringList()
+                      << address.postOfficeBox()
+                      << QString() // Leave out the extended address field
+                      << address.street()
+                      << address.locality()
+                      << address.region()
+                      << address.postcode()
+                      << address.country());
+    property.setValueType(QVersitProperty::CompoundType);
 }
 
 /*!
@@ -276,7 +315,7 @@
     const QContactDetail& detail)
 {
     QContactGuid uid = static_cast<QContactGuid>(detail);
-    setEscapedValue(property,uid.guid());
+    property.setValue(uid.guid());
 }
 
 /*!
@@ -334,7 +373,7 @@
     const QContactDetail& detail)
 {
     QContactNote contactNote = static_cast<QContactNote>(detail);
-    setEscapedValue(property,contactNote.note());
+    property.setValue(contactNote.note());
 }
 
 /*!
@@ -345,10 +384,9 @@
     const QContactDetail& detail)
 {
     QContactGeoLocation geoLocation = static_cast<QContactGeoLocation>(detail);
-    QString value =
-        QString::number(geoLocation.longitude()) + QLatin1Char(',') +
-        QString::number(geoLocation.latitude());
-    property.setValue(value);
+    property.setValue(QStringList() << QString::number(geoLocation.longitude())
+                      << QString::number(geoLocation.latitude()));
+    property.setValueType(QVersitProperty::CompoundType);
 }
 
 /*!
@@ -362,26 +400,22 @@
     if (organization.title().length() > 0) {
         QVersitProperty property;
         property.setName(QLatin1String("TITLE"));
-        setEscapedValue(property,organization.title());
+        property.setValue(organization.title());
         document.addProperty(property);
     }
     if (organization.name().length() > 0 || organization.department().size() > 0) {
         QVersitProperty property;
         property.setName(QLatin1String("ORG"));
-        QString value = escape(organization.name());
-        QStringList departments(organization.department());
-        if (departments.count() == 0)
-            value += QLatin1Char(';');
-        foreach (QString department, departments) {
-            value += QLatin1Char(';');
-            value += escape(department);
-        }
-        property.setValue(value);
+        QStringList values(organization.name());
+        values.append(organization.department());
+        property.setValue(values);
+        property.setValueType(QVersitProperty::CompoundType);
         document.addProperty(property);
     }
-    if (organization.logo().length() > 0) {
+    if (organization.logoUrl().isValid()) {
         QVersitProperty property;
-        if (encodeContentFromFile(organization.logo(), property)) {
+        // XXX TODO: FIXME!
+        if (encodeContentFromFile(organization.logoUrl().toString(), property)) {
             property.setName(QLatin1String("LOGO"));
             document.addProperty(property);
         }
@@ -389,43 +423,68 @@
     if (organization.assistantName().length() > 0) {
         QVersitProperty property;
         property.setName(QLatin1String("X-ASSISTANT"));
-        setEscapedValue(property,organization.assistantName());
+        property.setValue(organization.assistantName());
         document.addProperty(property);
     }
 
     if (organization.role().length() > 0) {
         QVersitProperty property;
         property.setName(QLatin1String("ROLE"));
-        setEscapedValue(property,organization.role());
+        property.setValue(organization.role());
         document.addProperty(property);
     }
 }
 
+bool QVersitContactExporterPrivate::encodeRingtone(QVersitProperty &property, const QContactDetail &detail)
+{
+    QContactRingtone ringtone = static_cast<QContactRingtone>(detail);
+    Q_ASSERT(property.name() == QLatin1String("SOUND"));
+    return encodeContentFromFile(ringtone.audioRingtoneUrl().toLocalFile(), property);
+}
+
 /*!
- * Encode avatar content into the Versit Document
+ * Encode thumbnail content into the Versit Document
+ */
+bool QVersitContactExporterPrivate::encodeThumbnail(
+    QVersitProperty& property,
+    const QContactDetail& detail)
+{
+    QContactThumbnail contactThumbnail = static_cast<QContactThumbnail>(detail);
+    property.setName(QLatin1String("PHOTO"));
+    QImage image = contactThumbnail.thumbnail();
+    if (image.isNull())
+        return false;
+    QByteArray imageData;
+    QBuffer buffer(&imageData);
+    buffer.open(QIODevice::WriteOnly);
+    // Always store a pixmap as a PNG.
+    if (!image.save(&buffer, "PNG")) {
+        return false;
+    }
+    property.setValue(imageData);
+    property.insertParameter(QLatin1String("TYPE"), QLatin1String("PNG"));
+    return true;
+}
+
+/*!
+ * Encode avatar URIs into the Versit Document
  */
 bool QVersitContactExporterPrivate::encodeAvatar(
     QVersitProperty& property,
     const QContactDetail& detail)
 {
+    property.setName(QLatin1String("PHOTO"));
     QContactAvatar contactAvatar = static_cast<QContactAvatar>(detail);
-    bool encoded = false;
-    QString propertyName;
-    if (contactAvatar.subType() == QContactAvatar::SubTypeImage) {
-        propertyName = QLatin1String("PHOTO");
-    } else if (contactAvatar.subType() == QContactAvatar::SubTypeAudioRingtone) {
-        propertyName = QLatin1String("SOUND");
+    QUrl imageUrl(contactAvatar.imageUrl());
+    // XXX: fix up this mess: checking the scheme here and in encodeContentFromFile,
+    // organisation logo and ringtone are QStrings but avatar is a QUrl
+    if (!imageUrl.scheme().isEmpty() && !imageUrl.host().isEmpty()) {
+        property.insertParameter(QLatin1String("VALUE"), QLatin1String("URL"));
+        property.setValue(imageUrl.toString());
+        return true;
     } else {
-        // NOP
+        return encodeContentFromFile(contactAvatar.imageUrl().toString(), property);
     }
-    if (propertyName.length() > 0) {
-        encoded = encodeContentFromFile(contactAvatar.avatar(), property);
-        if (!encoded)
-            encoded = encodeContentFromPixmap(contactAvatar.pixmap(), property);
-        if (encoded)
-            property.setName(propertyName);
-    }
-    return encoded;
 }
 
 /*!
@@ -436,7 +495,7 @@
     QContactDetail& detail)
 {
     QContactGender gender = static_cast<QContactGender>(detail);
-    setEscapedValue(property,gender.gender());
+    property.setValue(gender.gender());
 }
 
 /*!
@@ -448,27 +507,55 @@
 {
     QContactNickname nicknameDetail = static_cast<QContactNickname>(detail);
     QVersitProperty property;
-    property.setName(QLatin1String("X-NICKNAME"));
     bool found = false;
-    foreach (QVersitProperty currentProperty, document.properties()) {
+    // XXX TODO: ensure it works for both X-NICKNAME and NICKNAME
+    foreach (const QVersitProperty& currentProperty, document.properties()) {
         if (currentProperty.name() == QLatin1String("X-NICKNAME")) {
             property = currentProperty;
             found = true;
             break;
         }
     }
-    QString value(property.value());
-    if (found)
-        value += QLatin1Char(',');
-    QString nickname = escape(nicknameDetail.nickname());
-    value.append(nickname);
+    QStringList value(property.variantValue().toStringList());
+    if (!found)
+        property.setName(QLatin1String("X-NICKNAME"));
+    value.append(nicknameDetail.nickname());
     property.setValue(value);
+    property.setValueType(QVersitProperty::ListType);
     // Replace the current property
     document.removeProperties(QLatin1String("X-NICKNAME"));
     document.addProperty(property);
 }
 
 /*!
+ * Encodes a contact tag into the Versit Document
+ */
+void QVersitContactExporterPrivate::encodeTag(
+    QVersitDocument& document,
+    const QContactDetail& detail)
+{
+    QContactTag tagDetail = static_cast<QContactTag>(detail);
+    QVersitProperty property;
+    bool found = false;
+    foreach (const QVersitProperty& currentProperty, document.properties()) {
+        if (currentProperty.name() == QLatin1String("CATEGORIES")) {
+            property = currentProperty;
+            found = true;
+            break;
+        }
+    }
+    QStringList value(property.variantValue().toStringList());
+    if (!found)
+        property.setName(QLatin1String("CATEGORIES"));
+    value.append(tagDetail.tag());
+    property.setValue(value);
+    property.setValueType(QVersitProperty::ListType);
+    // Replace the current property
+    document.removeProperties(QLatin1String("CATEGORIES"));
+    document.addProperty(property);
+}
+
+/*!
  * Encode anniversary information into Versit Document
  */
 void QVersitContactExporterPrivate::encodeAnniversary(
@@ -500,7 +587,7 @@
         if (subTypes.contains(QContactOnlineAccount::SubTypeImpp))
             name = QLatin1String("X-IMPP");
         property.setName(name);
-        setEscapedValue(property,onlineAccount.accountUri());
+        property.setValue(onlineAccount.accountUri());
     }
     return encoded;
 }
@@ -517,15 +604,15 @@
     if (family.spouse().size()) {
         QVersitProperty property;
         property.setName(QLatin1String("X-SPOUSE"));
-        setEscapedValue(property,family.spouse());
+        property.setValue(family.spouse());
         document.addProperty(property);
     }
 
     if (family.children().size()) {
         QVersitProperty property;
         property.setName(QLatin1String("X-CHILDREN"));
-        QString children = family.children().join(QLatin1String(","));
-        setEscapedValue(property,children);
+        property.setValue(family.children());
+        property.setValueType(QVersitProperty::ListType);
         document.addProperty(property);
     }
     return false;
@@ -544,7 +631,7 @@
     QContactDisplayLabel displayLabel = static_cast<QContactDisplayLabel>(detail);
     if (displayLabel.label().size()) {
         encoded = true;
-        setEscapedValue(property,displayLabel.label());
+        property.setValue(displayLabel.label());
     } else {
         QContactDetail contactDetail;
         for (int i = 0; i < contact.details().count(); i++) {
@@ -563,7 +650,7 @@
             name.firstName().length() ||
             name.lastName().length()) {
             encoded = true;
-            property.setValue(escape(value));
+            property.setValue(value);
         }
     }
     return encoded;
@@ -635,49 +722,3 @@
     property.setValue(value);
     return encodeContent;
 }
-
-/*!
- * Encode embedded content from the given \a pixmap into \a property.
- */
-bool QVersitContactExporterPrivate::encodeContentFromPixmap(const QPixmap& pixmap,
-                                                            QVersitProperty& property)
-{
-    if (pixmap.isNull())
-        return false;
-    QByteArray imageData;
-    QBuffer buffer(&imageData);
-    buffer.open(QIODevice::WriteOnly);
-    // Always store a pixmap as a PNG.
-    if (!pixmap.save(&buffer, "PNG")) {
-        return false;
-    }
-    property.setValue(imageData);
-    property.insertParameter(QLatin1String("TYPE"), QLatin1String("PNG"));
-    return true;
-}
-
-/*!
- * Escapes \a value if necessary and sets it to \a property
- */
-void QVersitContactExporterPrivate::setEscapedValue(
-    QVersitProperty& property,
-    const QString& value)
-{
-    QString escapedValue(escape(value));
-    property.setValue(escapedValue);
-}
-
-/*!
- * Escapes \a value if necessary.
- * For vCard there is no concept of escaping the property values.
- * Starting from 3.0 the property values having certain special
- * characters should be escaped.
- */
-QString QVersitContactExporterPrivate::escape(const QString& value)
-{
-    QString escaped(value);
-    if (mVersitType != QVersitDocument::VCard21Type) {
-        VersitUtils::backSlashEscape(escaped);
-    }
-    return escaped;
-}