|
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 "qversitdefs_p.h" |
|
43 #include "qversitcontactimporter_p.h" |
|
44 #include "qversitdocument.h" |
|
45 #include "qversitproperty.h" |
|
46 #include "qmobilityglobal.h" |
|
47 |
|
48 #include <qcontactmanagerengine.h> |
|
49 #include <qcontact.h> |
|
50 #include <qcontactdetail.h> |
|
51 #include <qcontactname.h> |
|
52 #include <qcontactphonenumber.h> |
|
53 #include <qcontactaddress.h> |
|
54 #include <qcontactemailaddress.h> |
|
55 #include <qcontactorganization.h> |
|
56 #include <qcontacturl.h> |
|
57 #include <qcontactguid.h> |
|
58 #include <qcontacttimestamp.h> |
|
59 #include <qcontactanniversary.h> |
|
60 #include <qcontactbirthday.h> |
|
61 #include <qcontactgender.h> |
|
62 #include <qcontactnickname.h> |
|
63 #include <qcontactavatar.h> |
|
64 #include <qcontactgeolocation.h> |
|
65 #include <qcontactnote.h> |
|
66 #include <qcontactonlineaccount.h> |
|
67 #include <qcontactfamily.h> |
|
68 #include <qcontactdisplaylabel.h> |
|
69 #include <qcontactthumbnail.h> |
|
70 #include <qcontactringtone.h> |
|
71 |
|
72 #include <QHash> |
|
73 #include <QFile> |
|
74 |
|
75 QTM_USE_NAMESPACE |
|
76 |
|
77 /*! |
|
78 * Constructor. |
|
79 */ |
|
80 QVersitContactImporterPrivate::QVersitContactImporterPrivate() : |
|
81 mPropertyHandler(NULL), |
|
82 mPropertyHandler2(NULL), |
|
83 mPropertyHandlerVersion(0), |
|
84 mDefaultResourceHandler(new QVersitDefaultResourceHandler), |
|
85 mResourceHandler(mDefaultResourceHandler) |
|
86 { |
|
87 // Contact detail mappings |
|
88 int versitPropertyCount = |
|
89 sizeof(versitContactDetailMappings)/sizeof(VersitContactDetailMapping); |
|
90 for (int i=0; i < versitPropertyCount; i++) { |
|
91 QString versitPropertyName = |
|
92 QLatin1String(versitContactDetailMappings[i].versitPropertyName); |
|
93 QPair<QString,QString> contactDetail; |
|
94 contactDetail.first = |
|
95 QLatin1String(versitContactDetailMappings[i].contactDetailDefinitionName); |
|
96 contactDetail.second = |
|
97 QLatin1String(versitContactDetailMappings[i].contactDetailValueKey); |
|
98 mDetailMappings.insert(versitPropertyName,contactDetail); |
|
99 } |
|
100 |
|
101 // Context mappings |
|
102 int contextCount = sizeof(versitContextMappings)/sizeof(VersitMapping); |
|
103 for (int i=0; i < contextCount; i++) { |
|
104 mContextMappings.insert( |
|
105 QLatin1String(versitContextMappings[i].versitString), |
|
106 QLatin1String(versitContextMappings[i].contactString)); |
|
107 } |
|
108 |
|
109 // Subtype mappings |
|
110 int subTypeCount = sizeof(versitSubTypeMappings)/sizeof(VersitMapping); |
|
111 for (int i=0; i < subTypeCount; i++) { |
|
112 mSubTypeMappings.insert( |
|
113 QLatin1String(versitSubTypeMappings[i].versitString), |
|
114 QLatin1String(versitSubTypeMappings[i].contactString)); |
|
115 } |
|
116 } |
|
117 |
|
118 /*! |
|
119 * Destructor. |
|
120 */ |
|
121 QVersitContactImporterPrivate::~QVersitContactImporterPrivate() |
|
122 { |
|
123 delete mDefaultResourceHandler; |
|
124 } |
|
125 |
|
126 /*! |
|
127 * Generates a QContact from \a versitDocument. |
|
128 */ |
|
129 bool QVersitContactImporterPrivate::importContact( |
|
130 const QVersitDocument& document, int contactIndex, QContact* contact, |
|
131 QVersitContactImporter::Error* error) |
|
132 { |
|
133 if (document.type() != QVersitDocument::VCard21Type |
|
134 && document.type() != QVersitDocument::VCard30Type) { |
|
135 *error = QVersitContactImporter::InvalidDocumentError; |
|
136 return false; |
|
137 } |
|
138 const QList<QVersitProperty> properties = document.properties(); |
|
139 if (properties.size() == 0) { |
|
140 *error = QVersitContactImporter::EmptyDocumentError; |
|
141 return false; |
|
142 } |
|
143 |
|
144 // First, do the properties with PREF set so they appear first in the contact details |
|
145 foreach (const QVersitProperty& property, properties) { |
|
146 QStringList typeParameters = property.parameters().values(QLatin1String("TYPE")); |
|
147 if (typeParameters.contains(QLatin1String("PREF"), Qt::CaseInsensitive)) |
|
148 importProperty(document, property, contactIndex, contact); |
|
149 } |
|
150 // ... then, do the rest of the properties. |
|
151 foreach (const QVersitProperty& property, properties) { |
|
152 QStringList typeParameters = property.parameters().values(QLatin1String("TYPE")); |
|
153 if (!typeParameters.contains(QLatin1String("PREF"), Qt::CaseInsensitive)) |
|
154 importProperty(document, property, contactIndex, contact); |
|
155 } |
|
156 |
|
157 contact->setType(QContactType::TypeContact); |
|
158 QContactManagerEngine::setContactDisplayLabel(contact, QVersitContactImporterPrivate::synthesizedDisplayLabel(*contact)); |
|
159 |
|
160 if (mPropertyHandler2 && mPropertyHandlerVersion > 1) { |
|
161 mPropertyHandler2->documentProcessed(document, contact); |
|
162 } |
|
163 |
|
164 return true; |
|
165 } |
|
166 |
|
167 void QVersitContactImporterPrivate::importProperty( |
|
168 const QVersitDocument& document, const QVersitProperty& property, int contactIndex, |
|
169 QContact* contact) |
|
170 { |
|
171 if (mPropertyHandler |
|
172 && mPropertyHandlerVersion == 1 |
|
173 && mPropertyHandler->preProcessProperty(document, property, contactIndex, contact)) |
|
174 return; |
|
175 |
|
176 QPair<QString,QString> detailDefinition = |
|
177 mDetailMappings.value(property.name()); |
|
178 QString detailDefinitionName = detailDefinition.first; |
|
179 |
|
180 QList<QContactDetail> updatedDetails; |
|
181 |
|
182 bool success = false; |
|
183 |
|
184 // The following functions create and save the details to the contact |
|
185 if (detailDefinitionName == QContactAddress::DefinitionName) { |
|
186 success = createAddress(property, contact, &updatedDetails); // pass in group |
|
187 } else if (detailDefinitionName == QContactName::DefinitionName) { |
|
188 success = createName(property, contact, &updatedDetails); |
|
189 } else if (detailDefinitionName == QContactBirthday::DefinitionName) { |
|
190 success = createBirthday(property, contact, &updatedDetails); |
|
191 } else if (detailDefinitionName == QContactGeoLocation::DefinitionName){ |
|
192 success = createGeoLocation(property, contact, &updatedDetails); |
|
193 } else if (detailDefinitionName == QContactOrganization::DefinitionName) { |
|
194 success = createOrganization(property, contact, &updatedDetails); |
|
195 } else if (detailDefinitionName == QContactNickname::DefinitionName) { |
|
196 success = createNicknames(property, contact, &updatedDetails); |
|
197 } else if (detailDefinitionName == QContactRingtone::DefinitionName) { |
|
198 success = createRingtone(property, contact, &updatedDetails); |
|
199 } else if (detailDefinitionName == QContactThumbnail::DefinitionName) { |
|
200 success = createThumbnail(property, contact, &updatedDetails); |
|
201 } else if (detailDefinitionName == QContactTimestamp::DefinitionName) { |
|
202 success = createTimeStamp(property, contact, &updatedDetails); |
|
203 } else if (detailDefinitionName == QContactPhoneNumber::DefinitionName) { |
|
204 success = createPhone(property, contact, &updatedDetails); |
|
205 } else if (detailDefinitionName == QContactAnniversary::DefinitionName) { |
|
206 success = createAnniversary(property, contact, &updatedDetails); |
|
207 } else if (detailDefinitionName == QContactFamily::DefinitionName) { |
|
208 success = createFamily(property, contact, &updatedDetails); |
|
209 } else if (detailDefinitionName == QContactOnlineAccount::DefinitionName) { |
|
210 success = createOnlineAccount(property, contact, &updatedDetails); |
|
211 } else if (detailDefinitionName == QContactTag::DefinitionName) { |
|
212 success = createTags(property, contact, &updatedDetails); |
|
213 } else if (detailDefinitionName == QContactDisplayLabel::DefinitionName) { |
|
214 success = createCustomLabel(property, contact, &updatedDetails); |
|
215 } else { |
|
216 // Look up mDetailMappings for a simple mapping from property to detail. |
|
217 success = createNameValueDetail(property, contact, &updatedDetails); |
|
218 } |
|
219 |
|
220 if (mPropertyHandler2 && mPropertyHandlerVersion > 1) { |
|
221 mPropertyHandler2->propertyProcessed(document, property, success, *contact, &updatedDetails); |
|
222 } |
|
223 |
|
224 foreach (QContactDetail detail, updatedDetails) { |
|
225 contact->saveDetail(&detail); |
|
226 } |
|
227 |
|
228 if (mPropertyHandler && mPropertyHandlerVersion == 1) |
|
229 mPropertyHandler->postProcessProperty(document, property, success, contactIndex, contact); |
|
230 } |
|
231 /*! |
|
232 * Creates a QContactName from \a property |
|
233 */ |
|
234 bool QVersitContactImporterPrivate::createName( |
|
235 const QVersitProperty& property, |
|
236 QContact* contact, |
|
237 QList<QContactDetail>* updatedDetails) |
|
238 { |
|
239 QContactName name; |
|
240 QContactDetail detail = contact->detail(QContactName::DefinitionName); |
|
241 if (!detail.isEmpty()) { |
|
242 // If multiple name properties exist, |
|
243 // discard all except the first occurrence |
|
244 if (!detail.value(QContactName::FieldFirstName).isEmpty()) |
|
245 return false; |
|
246 else |
|
247 name = QContactName(static_cast<QContactName>(detail)); |
|
248 } |
|
249 |
|
250 QVariant variant = property.variantValue(); |
|
251 if (property.valueType() != QVersitProperty::CompoundType |
|
252 || variant.type() != QVariant::StringList) |
|
253 return false; |
|
254 QStringList values = variant.toStringList(); |
|
255 QString value(takeFirst(values)); |
|
256 if (!value.isEmpty()) |
|
257 name.setLastName(value); |
|
258 value = takeFirst(values); |
|
259 if (!value.isEmpty()) |
|
260 name.setFirstName(value); |
|
261 value = takeFirst(values); |
|
262 if (!value.isEmpty()) |
|
263 name.setMiddleName(value); |
|
264 value = takeFirst(values); |
|
265 if (!value.isEmpty()) |
|
266 name.setPrefix(value); |
|
267 value = takeFirst(values); |
|
268 if (!value.isEmpty()) |
|
269 name.setSuffix(value); |
|
270 |
|
271 saveDetailWithContext(updatedDetails, name, extractContexts(property)); |
|
272 return true; |
|
273 } |
|
274 |
|
275 /*! |
|
276 * Creates a QContactPhoneNumber from \a property |
|
277 */ |
|
278 bool QVersitContactImporterPrivate::createPhone( |
|
279 const QVersitProperty& property, |
|
280 QContact* contact, |
|
281 QList<QContactDetail>* updatedDetails) |
|
282 { |
|
283 Q_UNUSED(contact) |
|
284 QContactPhoneNumber phone; |
|
285 QString value(property.value()); |
|
286 if (value.isEmpty()) |
|
287 return false; |
|
288 phone.setNumber(property.value()); |
|
289 QStringList subTypes(extractSubTypes(property)); |
|
290 if (property.name() == QLatin1String("X-ASSISTANT-TEL")) |
|
291 subTypes << QContactPhoneNumber::SubTypeAssistant; |
|
292 if (!subTypes.isEmpty()) |
|
293 phone.setSubTypes(subTypes); |
|
294 |
|
295 saveDetailWithContext(updatedDetails, phone, extractContexts(property)); |
|
296 return true; |
|
297 } |
|
298 |
|
299 /*! |
|
300 * Creates a QContactAddress from \a property |
|
301 */ |
|
302 bool QVersitContactImporterPrivate::createAddress( |
|
303 const QVersitProperty& property, |
|
304 QContact* contact, |
|
305 QList<QContactDetail>* updatedDetails) |
|
306 { |
|
307 Q_UNUSED(contact) |
|
308 QContactAddress address; |
|
309 |
|
310 QVariant variant = property.variantValue(); |
|
311 if (property.valueType() != QVersitProperty::CompoundType |
|
312 || variant.type() != QVariant::StringList) |
|
313 return false; |
|
314 QStringList addressParts = variant.toStringList(); |
|
315 QString value(takeFirst(addressParts)); |
|
316 if (!value.isEmpty()) |
|
317 address.setPostOfficeBox(value); |
|
318 // There is no setter for the Extended Address in QContactAddress: |
|
319 if (!addressParts.isEmpty()) |
|
320 addressParts.removeFirst(); |
|
321 value = takeFirst(addressParts); |
|
322 if (!value.isEmpty()) |
|
323 address.setStreet(value); |
|
324 value = takeFirst(addressParts); |
|
325 if (!value.isEmpty()) |
|
326 address.setLocality(value); |
|
327 value = takeFirst(addressParts); |
|
328 if (!value.isEmpty()) |
|
329 address.setRegion(value); |
|
330 value = takeFirst(addressParts); |
|
331 if (!value.isEmpty()) |
|
332 address.setPostcode(value); |
|
333 value = takeFirst(addressParts); |
|
334 if (!value.isEmpty()) |
|
335 address.setCountry(value); |
|
336 QStringList subTypes(extractSubTypes(property)); |
|
337 if (!subTypes.isEmpty()) |
|
338 address.setSubTypes(subTypes); |
|
339 |
|
340 saveDetailWithContext(updatedDetails, address, extractContexts(property)); |
|
341 return true; |
|
342 } |
|
343 |
|
344 /*! |
|
345 * Creates a QContactOrganization from \a property |
|
346 */ |
|
347 bool QVersitContactImporterPrivate::createOrganization( |
|
348 const QVersitProperty& property, |
|
349 QContact* contact, |
|
350 QList<QContactDetail>* updatedDetails) |
|
351 { |
|
352 QContactOrganization organization; |
|
353 QPair<QString,QString> detailNameAndFieldName = |
|
354 mDetailMappings.value(property.name()); |
|
355 QString fieldName = detailNameAndFieldName.second; |
|
356 QList<QContactOrganization> organizations = contact->details<QContactOrganization>(); |
|
357 foreach(const QContactOrganization& current, organizations) { |
|
358 if (current.value(fieldName).length() == 0) { |
|
359 organization = current; |
|
360 break; |
|
361 } |
|
362 } |
|
363 if (fieldName == QContactOrganization::FieldName) { |
|
364 setOrganizationNames(organization, property); |
|
365 } else if (fieldName == QContactOrganization::FieldTitle) { |
|
366 organization.setTitle(property.value()); |
|
367 } else if (fieldName == QContactOrganization::FieldRole) { |
|
368 organization.setRole(property.value()); |
|
369 } else if (fieldName == QContactOrganization::FieldLogoUrl) { |
|
370 setOrganizationLogo(organization, property); |
|
371 } else if (fieldName == QContactOrganization::FieldAssistantName) { |
|
372 organization.setAssistantName(property.value()); |
|
373 } else { |
|
374 return false; |
|
375 } |
|
376 |
|
377 saveDetailWithContext(updatedDetails, organization, extractContexts(property)); |
|
378 return true; |
|
379 } |
|
380 |
|
381 /*! |
|
382 * Set the organization name and department(s) from \a property. |
|
383 */ |
|
384 void QVersitContactImporterPrivate::setOrganizationNames( |
|
385 QContactOrganization& organization, const QVersitProperty& property) const |
|
386 { |
|
387 QVariant variant = property.variantValue(); |
|
388 if (property.valueType() == QVersitProperty::CompoundType |
|
389 && variant.type() == QVariant::StringList) { |
|
390 QStringList values = variant.toStringList(); |
|
391 QString name(takeFirst(values)); |
|
392 if (!name.isEmpty()) |
|
393 organization.setName(name); |
|
394 if (!values.isEmpty()) |
|
395 organization.setDepartment(values); |
|
396 } |
|
397 } |
|
398 |
|
399 /*! |
|
400 * Set the organization logo from \a property. |
|
401 */ |
|
402 void QVersitContactImporterPrivate::setOrganizationLogo( |
|
403 QContactOrganization& org, const QVersitProperty& property) const |
|
404 { |
|
405 QString location; |
|
406 QByteArray data; |
|
407 saveDataFromProperty(property, &location, &data); |
|
408 if (!location.isEmpty()) |
|
409 org.setLogoUrl(QUrl(location)); |
|
410 } |
|
411 |
|
412 /*! |
|
413 * Creates a QContactTimeStamp from \a property |
|
414 */ |
|
415 bool QVersitContactImporterPrivate::createTimeStamp( |
|
416 const QVersitProperty& property, |
|
417 QContact* contact, |
|
418 QList<QContactDetail>* updatedDetails) |
|
419 { |
|
420 Q_UNUSED(contact) |
|
421 QContactTimestamp timeStamp; |
|
422 QString value(property.value()); |
|
423 bool utc = value.endsWith(QLatin1Char('Z'), Qt::CaseInsensitive); |
|
424 if (utc) |
|
425 value.chop(1); // take away z from end; |
|
426 |
|
427 QDateTime dateTime = parseDateTime(value,QLatin1String("yyyyMMddThhmmss")); |
|
428 if (!dateTime.isValid()) |
|
429 return false; |
|
430 if (utc) |
|
431 dateTime.setTimeSpec(Qt::UTC); |
|
432 timeStamp.setLastModified(dateTime); |
|
433 saveDetailWithContext(updatedDetails, timeStamp, extractContexts(property)); |
|
434 return true; |
|
435 } |
|
436 |
|
437 /*! |
|
438 * Creates a QContactAnniversary from \a property |
|
439 */ |
|
440 bool QVersitContactImporterPrivate::createAnniversary( |
|
441 const QVersitProperty& property, |
|
442 QContact* contact, |
|
443 QList<QContactDetail>* updatedDetails) |
|
444 { |
|
445 Q_UNUSED(contact) |
|
446 QContactAnniversary anniversary; |
|
447 QDateTime dateTime = parseDateTime(property.value(), QLatin1String("yyyyMMdd")); |
|
448 if (!dateTime.isValid()) |
|
449 return false; |
|
450 anniversary.setOriginalDate(dateTime.date()); |
|
451 saveDetailWithContext(updatedDetails, anniversary, extractContexts(property)); |
|
452 return true; |
|
453 } |
|
454 |
|
455 /*! |
|
456 * Creates a QContactBirthday from \a property |
|
457 */ |
|
458 bool QVersitContactImporterPrivate::createBirthday( |
|
459 const QVersitProperty& property, |
|
460 QContact* contact, |
|
461 QList<QContactDetail>* updatedDetails) |
|
462 { |
|
463 Q_UNUSED(contact) |
|
464 QContactBirthday bday; |
|
465 QDateTime dateTime = parseDateTime(property.value(), QLatin1String("yyyyMMdd")); |
|
466 if (!dateTime.isValid()) |
|
467 return false; |
|
468 bday.setDate(dateTime.date()); |
|
469 saveDetailWithContext(updatedDetails, bday, extractContexts(property)); |
|
470 return true; |
|
471 } |
|
472 |
|
473 /*! |
|
474 * Creates QContactNicknames from \a property |
|
475 */ |
|
476 bool QVersitContactImporterPrivate::createNicknames( |
|
477 const QVersitProperty& property, |
|
478 QContact* contact, |
|
479 QList<QContactDetail>* updatedDetails) |
|
480 { |
|
481 Q_UNUSED(contact) |
|
482 QVariant variant = property.variantValue(); |
|
483 if (property.valueType() != QVersitProperty::ListType |
|
484 || variant.type() != QVariant::StringList) |
|
485 return false; |
|
486 QStringList values = variant.toStringList(); |
|
487 QStringList contexts = extractContexts(property); |
|
488 foreach(const QString& value, values) { |
|
489 if (!value.isEmpty()) { |
|
490 QContactNickname nickName; |
|
491 nickName.setNickname(value); |
|
492 saveDetailWithContext(updatedDetails, nickName, contexts); |
|
493 } |
|
494 } |
|
495 return true; |
|
496 } |
|
497 |
|
498 /*! |
|
499 * Creates QContactTags from \a property |
|
500 */ |
|
501 bool QVersitContactImporterPrivate::createTags( |
|
502 const QVersitProperty& property, |
|
503 QContact* contact, |
|
504 QList<QContactDetail>* updatedDetails) |
|
505 { |
|
506 Q_UNUSED(contact) |
|
507 QVariant variant = property.variantValue(); |
|
508 if (property.valueType() != QVersitProperty::ListType |
|
509 || variant.type() != QVariant::StringList) |
|
510 return false; |
|
511 QStringList values = variant.toStringList(); |
|
512 QStringList contexts = extractContexts(property); |
|
513 foreach(const QString& value, values) { |
|
514 if (!value.isEmpty()) { |
|
515 QContactTag tag; |
|
516 tag.setTag(value); |
|
517 saveDetailWithContext(updatedDetails, tag, contexts); |
|
518 } |
|
519 } |
|
520 return true; |
|
521 } |
|
522 |
|
523 /*! |
|
524 * Creates a QContactOnlineAccount from \a property |
|
525 */ |
|
526 bool QVersitContactImporterPrivate::createOnlineAccount( |
|
527 const QVersitProperty& property, |
|
528 QContact* contact, |
|
529 QList<QContactDetail>* updatedDetails) |
|
530 { |
|
531 Q_UNUSED(contact) |
|
532 QContactOnlineAccount onlineAccount; |
|
533 QString value(property.value()); |
|
534 if (value.isEmpty()) |
|
535 return false; |
|
536 onlineAccount.setAccountUri(property.value()); |
|
537 if (property.name() == QLatin1String("X-SIP")) { |
|
538 QStringList subTypes = extractSubTypes(property); |
|
539 if (subTypes.isEmpty()) |
|
540 subTypes.append(QContactOnlineAccount::SubTypeSip); |
|
541 onlineAccount.setSubTypes(subTypes); |
|
542 } else if (property.name() == QLatin1String("X-IMPP") || |
|
543 property.name() == QLatin1String("IMPP") || |
|
544 property.name() == QLatin1String("X-JABBER")) { |
|
545 onlineAccount.setSubTypes(QContactOnlineAccount::SubTypeImpp); |
|
546 } |
|
547 |
|
548 saveDetailWithContext(updatedDetails, onlineAccount, extractContexts(property)); |
|
549 return true; |
|
550 } |
|
551 |
|
552 /*! |
|
553 * Creates a QContactRingtone from \a property |
|
554 */ |
|
555 bool QVersitContactImporterPrivate::createRingtone( |
|
556 const QVersitProperty& property, |
|
557 QContact* contact, |
|
558 QList<QContactDetail>* updatedDetails) |
|
559 { |
|
560 Q_UNUSED(contact) |
|
561 QString location; |
|
562 QByteArray data; |
|
563 if (saveDataFromProperty(property, &location, &data) && !location.isEmpty()) { |
|
564 QContactRingtone ringtone; |
|
565 ringtone.setAudioRingtoneUrl(location); |
|
566 saveDetailWithContext(updatedDetails, ringtone, extractContexts(property)); |
|
567 return true; |
|
568 } |
|
569 return false; |
|
570 } |
|
571 |
|
572 /*! |
|
573 * Creates a QContactAvatar from \a property |
|
574 */ |
|
575 bool QVersitContactImporterPrivate::createThumbnail( |
|
576 const QVersitProperty& property, |
|
577 QContact* contact, |
|
578 QList<QContactDetail>* updatedDetails) |
|
579 { |
|
580 QString location; |
|
581 QByteArray data; |
|
582 bool success = false; |
|
583 |
|
584 if (saveDataFromProperty(property, &location, &data) && !location.isEmpty()) { |
|
585 QContactAvatar avatar; |
|
586 avatar.setImageUrl(location); |
|
587 saveDetailWithContext(updatedDetails, avatar, extractContexts(property)); |
|
588 success = true; |
|
589 } |
|
590 if (!data.isEmpty()) { |
|
591 QImage image; |
|
592 if (image.loadFromData(data)) { |
|
593 QContactThumbnail thumbnail = contact->detail<QContactThumbnail>(); |
|
594 // In the case of multiple thumbnails, pick the smallest one. |
|
595 if (thumbnail.isEmpty() || image.byteCount() < thumbnail.thumbnail().byteCount()) { |
|
596 thumbnail.setThumbnail(image); |
|
597 } |
|
598 saveDetailWithContext(updatedDetails, thumbnail, extractContexts(property)); |
|
599 success = true; |
|
600 } |
|
601 } |
|
602 |
|
603 return success; |
|
604 } |
|
605 |
|
606 /*! |
|
607 * Creates a QContactGeoLocation from \a property |
|
608 */ |
|
609 bool QVersitContactImporterPrivate::createGeoLocation( |
|
610 const QVersitProperty& property, |
|
611 QContact* contact, |
|
612 QList<QContactDetail>* updatedDetails) |
|
613 { |
|
614 Q_UNUSED(contact) |
|
615 QContactGeoLocation geo; |
|
616 QVariant variant = property.variantValue(); |
|
617 if (property.valueType() != QVersitProperty::CompoundType |
|
618 || variant.type() != QVariant::StringList) |
|
619 return false; |
|
620 QStringList values = variant.toStringList(); |
|
621 bool ok1; |
|
622 geo.setLongitude(takeFirst(values).toDouble(&ok1)); |
|
623 bool ok2; |
|
624 geo.setLatitude(takeFirst(values).toDouble(&ok2)); |
|
625 |
|
626 if (ok1 && ok2) { |
|
627 saveDetailWithContext(updatedDetails, geo, extractContexts(property)); |
|
628 return true; |
|
629 } else { |
|
630 return false; |
|
631 } |
|
632 } |
|
633 |
|
634 /*! |
|
635 * Creates a QContactFamily from \a property |
|
636 */ |
|
637 bool QVersitContactImporterPrivate::createFamily( |
|
638 const QVersitProperty& property, |
|
639 QContact* contact, |
|
640 QList<QContactDetail>* updatedDetails) |
|
641 { |
|
642 QString val = property.value(); |
|
643 QContactFamily family = contact->detail<QContactFamily>(); |
|
644 if (property.name() == QLatin1String("X-SPOUSE")) { |
|
645 if (val.isEmpty()) |
|
646 return false; |
|
647 family.setSpouse(val); |
|
648 } else if (property.name() == QLatin1String("X-CHILDREN")) { |
|
649 QVariant variant = property.variantValue(); |
|
650 if (property.valueType() != QVersitProperty::ListType |
|
651 || variant.type() != QVariant::StringList) |
|
652 return false; |
|
653 QStringList values = variant.toStringList(); |
|
654 if (values.isEmpty()) |
|
655 return false; |
|
656 family.setChildren(values); |
|
657 } else { |
|
658 return false; |
|
659 } |
|
660 |
|
661 saveDetailWithContext(updatedDetails, family, extractContexts(property)); |
|
662 return true; |
|
663 } |
|
664 |
|
665 /*! |
|
666 * Creates a simple name-value contact detail. |
|
667 */ |
|
668 bool QVersitContactImporterPrivate::createNameValueDetail( |
|
669 const QVersitProperty& property, |
|
670 QContact* contact, |
|
671 QList<QContactDetail>* updatedDetails) |
|
672 { |
|
673 Q_UNUSED(contact) |
|
674 QString value(property.value()); |
|
675 if (value.isEmpty()) |
|
676 return false; |
|
677 QPair<QString,QString> nameAndValueType = |
|
678 mDetailMappings.value(property.name()); |
|
679 if (nameAndValueType.first.isEmpty()) |
|
680 return false; |
|
681 |
|
682 QContactDetail detail(nameAndValueType.first); |
|
683 detail.setValue(nameAndValueType.second, value); |
|
684 |
|
685 saveDetailWithContext(updatedDetails, detail, extractContexts(property)); |
|
686 return true; |
|
687 } |
|
688 |
|
689 /*! |
|
690 * Find an existing QContactName and set the CustomLabel field on it |
|
691 */ |
|
692 bool QVersitContactImporterPrivate::createCustomLabel( |
|
693 const QVersitProperty& property, |
|
694 QContact* contact, |
|
695 QList<QContactDetail>* updatedDetails) |
|
696 { |
|
697 QString label(property.value()); |
|
698 if (!label.isEmpty()) { |
|
699 QContactName name; |
|
700 QContactName existingName = contact->detail<QContactName>(); |
|
701 if (!existingName.isEmpty()) { |
|
702 name = existingName; |
|
703 } |
|
704 |
|
705 name.setCustomLabel(property.value()); |
|
706 |
|
707 saveDetailWithContext(updatedDetails, name, extractContexts(property)); |
|
708 return true; |
|
709 } else { |
|
710 return false; |
|
711 } |
|
712 } |
|
713 |
|
714 /*! |
|
715 * Extracts the list of contexts from \a types |
|
716 */ |
|
717 QStringList QVersitContactImporterPrivate::extractContexts( |
|
718 const QVersitProperty& property) const |
|
719 { |
|
720 QStringList types = property.parameters().values(QLatin1String("TYPE")); |
|
721 QStringList contexts; |
|
722 foreach (const QString& type, types) { |
|
723 QString value = mContextMappings.value(type.toUpper()); |
|
724 if (value.length() > 0) |
|
725 contexts.append(value); |
|
726 } |
|
727 return contexts; |
|
728 } |
|
729 |
|
730 /*! |
|
731 * Extracts the list of subtypes from \a property |
|
732 */ |
|
733 QStringList QVersitContactImporterPrivate::extractSubTypes( |
|
734 const QVersitProperty& property) const |
|
735 { |
|
736 QStringList types = property.parameters().values(QLatin1String("TYPE")); |
|
737 QStringList subTypes; |
|
738 foreach (const QString& type, types) { |
|
739 QString subType = mSubTypeMappings.value(type.toUpper()); |
|
740 if (subType.length() > 0) |
|
741 subTypes += subType; |
|
742 } |
|
743 return subTypes; |
|
744 } |
|
745 |
|
746 /*! |
|
747 * Takes the first value in \a list, or an empty QString is if the list is empty. |
|
748 */ |
|
749 QString QVersitContactImporterPrivate::takeFirst(QList<QString>& list) const |
|
750 { |
|
751 return list.empty() ? QString() : list.takeFirst(); |
|
752 } |
|
753 |
|
754 /*! |
|
755 * Parses a date and time from text |
|
756 */ |
|
757 QDateTime QVersitContactImporterPrivate::parseDateTime( |
|
758 const QString& value, |
|
759 const QString& format) const |
|
760 { |
|
761 QDateTime dateTime; |
|
762 if (value.contains(QLatin1Char('-'))) { |
|
763 dateTime = QDateTime::fromString(value,Qt::ISODate); |
|
764 } else { |
|
765 dateTime = QDateTime::fromString(value, format); |
|
766 } |
|
767 return dateTime; |
|
768 } |
|
769 |
|
770 /*! |
|
771 * Extracts either a location (URI/filepath) from a \a property, or data (eg. if it was base64 |
|
772 * encoded). If the property contains data, an attempt is made to save it and the location of the |
|
773 * saved resource is recovered to *\a location. The data is stored into *\a data. |
|
774 */ |
|
775 bool QVersitContactImporterPrivate::saveDataFromProperty(const QVersitProperty &property, |
|
776 QString *location, |
|
777 QByteArray *data) const |
|
778 { |
|
779 bool found = false; |
|
780 const QString valueParam = property.parameters().value(QLatin1String("VALUE")); |
|
781 QVariant variant(property.variantValue()); |
|
782 if (variant.type() == QVariant::String |
|
783 || valueParam == QLatin1String("URL")) { |
|
784 *location = property.value(); |
|
785 found |= !location->isEmpty(); |
|
786 } else if (variant.type() == QVariant::ByteArray) { |
|
787 *data = variant.toByteArray(); |
|
788 if (!data->isEmpty()) { |
|
789 found = true; |
|
790 *location = saveContentToFile(property, *data); |
|
791 } |
|
792 } |
|
793 return found; |
|
794 } |
|
795 |
|
796 /*! |
|
797 * Writes \a data to a file and returns the filename. \a property specifies the context in which |
|
798 * the data was found. |
|
799 */ |
|
800 QString QVersitContactImporterPrivate::saveContentToFile( |
|
801 const QVersitProperty& property, const QByteArray& data) const |
|
802 { |
|
803 QString filename; |
|
804 bool ok = false; |
|
805 if (mResourceHandler) |
|
806 ok = mResourceHandler->saveResource(data, property, &filename); |
|
807 return ok ? filename : QString(); |
|
808 } |
|
809 |
|
810 /*! |
|
811 * Adds \a detail to the \a updatedDetails list. Also sets the contexts to \a contexts if it is not |
|
812 * empty. |
|
813 */ |
|
814 void QVersitContactImporterPrivate::saveDetailWithContext( |
|
815 QList<QContactDetail>* updatedDetails, |
|
816 QContactDetail detail, |
|
817 const QStringList& contexts) |
|
818 { |
|
819 if (!contexts.isEmpty()) |
|
820 detail.setContexts(contexts); |
|
821 updatedDetails->append(detail); |
|
822 } |
|
823 |
|
824 /*! Synthesize the display label from the name of the contact, or, failing that, the nickname of |
|
825 the contact, or failing that, the organisation of the contact. |
|
826 Returns the synthesized display label. |
|
827 */ |
|
828 QString QVersitContactImporterPrivate::synthesizedDisplayLabel(const QContact& contact) |
|
829 { |
|
830 /* XXX This is copied and modified from QContactManagerEngine. This should be made a public |
|
831 static function in QCME and called here */ |
|
832 QList<QContactName> allNames = contact.details<QContactName>(); |
|
833 |
|
834 const QLatin1String space(" "); |
|
835 |
|
836 // synthesize the display label from the name. |
|
837 foreach (const QContactName& name, allNames) { |
|
838 if (!name.customLabel().isEmpty()) { |
|
839 // default behaviour is to allow the user to define a custom display label. |
|
840 return name.customLabel(); |
|
841 } |
|
842 |
|
843 QString result; |
|
844 if (!name.value(QContactName::FieldPrefix).trimmed().isEmpty()) { |
|
845 result += name.value(QContactName::FieldPrefix); |
|
846 } |
|
847 if (!name.value(QContactName::FieldFirstName).trimmed().isEmpty()) { |
|
848 if (!result.isEmpty()) |
|
849 result += space; |
|
850 result += name.value(QContactName::FieldFirstName); |
|
851 } |
|
852 if (!name.value(QContactName::FieldMiddleName).trimmed().isEmpty()) { |
|
853 if (!result.isEmpty()) |
|
854 result += space; |
|
855 result += name.value(QContactName::FieldMiddleName); |
|
856 } |
|
857 if (!name.value(QContactName::FieldLastName).trimmed().isEmpty()) { |
|
858 if (!result.isEmpty()) |
|
859 result += space; |
|
860 result += name.value(QContactName::FieldLastName); |
|
861 } |
|
862 if (!name.value(QContactName::FieldSuffix).trimmed().isEmpty()) { |
|
863 if (!result.isEmpty()) |
|
864 result += space; |
|
865 result += name.value(QContactName::FieldSuffix); |
|
866 } |
|
867 if (!result.isEmpty()) |
|
868 return result; |
|
869 } |
|
870 |
|
871 QList<QContactNickname> allNicknames = contact.details<QContactNickname>(); |
|
872 foreach (const QContactNickname& nickname, allNicknames) { |
|
873 if (!nickname.nickname().isEmpty()) |
|
874 return nickname.nickname(); |
|
875 } |
|
876 |
|
877 /* Well, we had no non empty names. if we have orgs, fall back to those */ |
|
878 QList<QContactOrganization> allOrgs = contact.details<QContactOrganization>(); |
|
879 foreach (const QContactOrganization& org, allOrgs) { |
|
880 if (!org.name().isEmpty()) |
|
881 return org.name(); |
|
882 } |
|
883 |
|
884 return QString(); |
|
885 } |