79 } |
80 } |
80 |
81 |
81 int mIndex; |
82 int mIndex; |
82 QMap<QString, QByteArray> mObjects; |
83 QMap<QString, QByteArray> mObjects; |
83 }; |
84 }; |
|
85 |
|
86 |
|
87 class MyDetailHandler : public QVersitContactExporterDetailHandler { |
|
88 public: |
|
89 MyDetailHandler() : detailNumber(0) {} |
|
90 bool preProcessDetail(const QContact& contact, const QContactDetail& detail, |
|
91 QVersitDocument* document) { |
|
92 Q_UNUSED(contact) Q_UNUSED(detail) Q_UNUSED(document) |
|
93 return false; |
|
94 } |
|
95 /* eg. a detail with definition name "Detail" and fields "Field1"="Value1" and |
|
96 * "Field2"="Value2" will be exported to the vCard properties: |
|
97 * G0.DETAIL-FIELD1:Value1 |
|
98 * G0.DETAIL-FIELD2:Value2 |
|
99 * And the next detail (say, "Detail" with a field "Field1"="Value3" will generate: |
|
100 * G1.DETAIL-FIELD1:Value3 |
|
101 * ie. Different details will have different vCard groups. |
|
102 */ |
|
103 bool postProcessDetail(const QContact& contact, const QContactDetail& detail, |
|
104 bool alreadyProcessed, QVersitDocument* document) { |
|
105 Q_UNUSED(contact) |
|
106 // beware: if the base implementation exports some but not all fields, alreadyProcessed |
|
107 // will be true and the unprocessed fields won't be exported |
|
108 if (alreadyProcessed) |
|
109 return false; |
|
110 if (detail.definitionName() == QContactType::DefinitionName) |
|
111 return false; // special case of an unhandled detail that we don't export |
|
112 QVersitProperty property; |
|
113 QVariantMap fields = detail.variantValues(); |
|
114 // fields from the same detail have the same group so the importer can collate them |
|
115 QString detailGroup = QLatin1String("G") + QString::number(detailNumber++); |
|
116 for (QVariantMap::const_iterator it = fields.constBegin(); |
|
117 it != fields.constEnd(); |
|
118 it++) { |
|
119 property.setGroups(QStringList(detailGroup)); |
|
120 // beware: detail.definitionName and the field name will be made uppercase on export |
|
121 property.setName(QLatin1String("X-QCONTACTDETAIL-") |
|
122 + detail.definitionName() |
|
123 + QLatin1String("-") |
|
124 + it.key()); |
|
125 // beware: this might not handle nonstring values properly: |
|
126 property.setValue(it.value()); |
|
127 document->addProperty(property); |
|
128 } |
|
129 return true; |
|
130 } |
|
131 private: |
|
132 int detailNumber; |
|
133 }; |
|
134 |
|
135 class MyPropertyHandler : public QVersitContactImporterPropertyHandler { |
|
136 public: |
|
137 bool preProcessProperty(const QVersitDocument& document, const QVersitProperty& property, |
|
138 int contactIndex, QContact* contact) { |
|
139 Q_UNUSED(document) Q_UNUSED(property) Q_UNUSED(contactIndex) Q_UNUSED(contact) |
|
140 return false; |
|
141 } |
|
142 /* eg. if the document has the properties: |
|
143 * G0.DETAIL-FIELD1:Value1 |
|
144 * G0.DETAIL-FIELD2:Value2 |
|
145 * G1.DETAIL-FIELD1:Value3 |
|
146 * This will generate two details - the first with fields "FIELD1"="Value1" and |
|
147 * "FIELD2"="Value2" and the second with "FIELD1"="Value3" |
|
148 * ie. the vCard groups determine which properties form a single detail. |
|
149 */ |
|
150 bool postProcessProperty(const QVersitDocument& document, const QVersitProperty& property, |
|
151 bool alreadyProcessed, int contactIndex, QContact* contact) { |
|
152 Q_UNUSED(document) Q_UNUSED(contactIndex) |
|
153 const QString prefix = QLatin1String("X-QCONTACTDETAIL-"); |
|
154 if (alreadyProcessed) |
|
155 return false; |
|
156 if (!property.name().startsWith(prefix)) |
|
157 return false; |
|
158 QString detailAndField = property.name().mid(prefix.size()); |
|
159 QStringList detailAndFieldParts = detailAndField.split(QLatin1Char('-'), |
|
160 QString::SkipEmptyParts); |
|
161 if (detailAndFieldParts.size() != 2) |
|
162 return false; |
|
163 QString definitionName = detailAndFieldParts.at(0); |
|
164 QString fieldName = detailAndFieldParts.at(1); |
|
165 if (property.groups().size() != 1) |
|
166 return false; |
|
167 QString group = property.groups().first(); |
|
168 // find a detail generated from the a property with the same group |
|
169 QContactDetail detail = handledDetails.value(group); |
|
170 // make sure the the existing detail has the same definition name |
|
171 if (detail.definitionName() != definitionName) |
|
172 detail = QContactDetail(definitionName); |
|
173 detail.setValue(fieldName, property.value()); |
|
174 contact->saveDetail(&detail); |
|
175 handledDetails.insert(group, detail); |
|
176 return false; |
|
177 } |
|
178 QMap<QString, QContactDetail> handledDetails; // map from group name to detail |
|
179 }; |
|
180 |
84 QTM_END_NAMESPACE |
181 QTM_END_NAMESPACE |
85 |
182 |
86 QTM_USE_NAMESPACE |
183 QTM_USE_NAMESPACE |
87 |
184 |
88 #ifndef TESTDATA_DIR |
185 #ifndef TESTDATA_DIR |
89 #define TESTDATA_DIR "./" |
186 #define TESTDATA_DIR "./" |
90 #endif |
187 #endif |
91 |
188 |
92 Q_DECLARE_METATYPE(QList<QContact>) |
189 Q_DECLARE_METATYPE(QList<QContact>) |
|
190 Q_DECLARE_METATYPE(QContact) |
93 |
191 |
94 void tst_QVersit::testImportFiles() |
192 void tst_QVersit::testImportFiles() |
95 { |
193 { |
96 QFETCH(QString, filename); |
194 QFETCH(QString, filename); |
97 QFETCH(QByteArray, charset); |
195 QFETCH(QByteArray, charset); |
109 QList<QVersitDocument> documents = reader.results(); |
207 QList<QVersitDocument> documents = reader.results(); |
110 QCOMPARE(reader.error(), QVersitReader::NoError); |
208 QCOMPARE(reader.error(), QVersitReader::NoError); |
111 QVersitContactImporter importer; |
209 QVersitContactImporter importer; |
112 MyQVersitResourceHandler resourceHandler; |
210 MyQVersitResourceHandler resourceHandler; |
113 importer.setResourceHandler(&resourceHandler); |
211 importer.setResourceHandler(&resourceHandler); |
|
212 MyPropertyHandler propertyHandler; |
|
213 importer.setPropertyHandler(&propertyHandler); |
114 QVERIFY(importer.importDocuments(documents)); |
214 QVERIFY(importer.importDocuments(documents)); |
115 QList<QContact> contacts = importer.contacts(); |
215 QList<QContact> contacts = importer.contacts(); |
116 |
216 |
117 if (expectedContacts.size() > 0) { |
217 if (expectedContacts.size() > 0) { |
118 QCOMPARE(contacts.size(), expectedContacts.size()); |
218 QCOMPARE(contacts.size(), expectedContacts.size()); |
195 QContact contact; |
294 QContact contact; |
196 QContactName name; |
295 QContactName name; |
197 name.setCustomLabel(QLatin1String("first last")); |
296 name.setCustomLabel(QLatin1String("first last")); |
198 name.setFirstName(QLatin1String("first")); |
297 name.setFirstName(QLatin1String("first")); |
199 name.setLastName(QLatin1String("last")); |
298 name.setLastName(QLatin1String("last")); |
200 name.setMiddleName(QString()); |
|
201 name.setPrefix(QString()); |
|
202 name.setSuffix(QString()); |
|
203 contact.saveDetail(&name); |
299 contact.saveDetail(&name); |
204 QContactOrganization org; |
300 QContactOrganization org; |
205 org.setName(QLatin1String("Nokia")); |
301 org.setName(QLatin1String("Nokia")); |
206 org.setDepartment(QStringList(QLatin1String("Qt DF"))); |
302 org.setDepartment(QStringList(QLatin1String("Qt DF"))); |
207 contact.saveDetail(&org); |
303 contact.saveDetail(&org); |
248 QContactManagerEngine::setContactDisplayLabel(&contact, QLatin1String("name")); |
340 QContactManagerEngine::setContactDisplayLabel(&contact, QLatin1String("name")); |
249 QTEST_NEW_ROW("test1.vcf", "UTF-8", QList<QContact>() << contact); |
341 QTEST_NEW_ROW("test1.vcf", "UTF-8", QList<QContact>() << contact); |
250 } |
342 } |
251 } |
343 } |
252 |
344 |
|
345 void tst_QVersit::testExportImport() |
|
346 { |
|
347 // Test that a contact, when exported, then imported again, is unaltered |
|
348 QFETCH(QContact, contact); |
|
349 |
|
350 QVersitContactExporter exporter; |
|
351 MyDetailHandler detailHandler; |
|
352 exporter.setDetailHandler(&detailHandler); |
|
353 QVERIFY(exporter.exportContacts(QList<QContact>() << contact, QVersitDocument::VCard30Type)); |
|
354 QList<QVersitDocument> documents = exporter.documents(); |
|
355 QCOMPARE(documents.size(), 1); |
|
356 |
|
357 QVersitContactImporter importer; |
|
358 MyPropertyHandler propertyHandler; |
|
359 importer.setPropertyHandler(&propertyHandler); |
|
360 QVERIFY(importer.importDocuments(documents)); |
|
361 QList<QContact> contacts = importer.contacts(); |
|
362 QCOMPARE(contacts.size(), 1); |
|
363 // We can't do a deep compare because detail ids are different |
|
364 QCOMPARE(contacts.first().details().count(), contact.details().count()); |
|
365 } |
|
366 |
|
367 void tst_QVersit::testExportImport_data() |
|
368 { |
|
369 QTest::addColumn<QContact>("contact"); |
|
370 |
|
371 QContact contact; |
|
372 QContactName name; |
|
373 name.setFirstName(QLatin1String("first")); |
|
374 name.setLastName(QLatin1String("last")); |
|
375 name.setCustomLabel(QLatin1String("custom")); |
|
376 contact.saveDetail(&name); |
|
377 // detail definition/field names are encoded as vCard property names, which must be uppercase, |
|
378 // so only uppercase definition/field names work. |
|
379 QContactDetail customDetail1("CUSTOMDETAIL"); |
|
380 customDetail1.setValue(QLatin1String("CUSTOMFIELD11"), QLatin1String("Value11")); |
|
381 customDetail1.setValue(QLatin1String("CUSTOMFIELD12"), QLatin1String("Value12")); |
|
382 contact.saveDetail(&customDetail1); |
|
383 QContactDetail customDetail2("CUSTOMDETAIL"); |
|
384 customDetail2.setValue(QLatin1String("CUSTOMFIELD21"), QLatin1String("Value21")); |
|
385 customDetail2.setValue(QLatin1String("CUSTOMFIELD22"), QLatin1String("Value22")); |
|
386 contact.saveDetail(&customDetail2); |
|
387 contact.setType(QContactType::TypeContact); |
|
388 |
|
389 QTest::newRow("custom detail") << contact; |
|
390 } |
|
391 |
253 QTEST_MAIN(tst_QVersit) |
392 QTEST_MAIN(tst_QVersit) |