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 "qtrackercontactsaverequest.h" |
|
43 #include "trackerchangelistener.h" |
|
44 |
|
45 #include <QtTracker/Tracker> |
|
46 using namespace SopranoLive; |
|
47 |
|
48 #include "qtrackercontactslive.h" |
|
49 |
|
50 // TODO better error handling when saving |
|
51 QTrackerContactSaveRequest::QTrackerContactSaveRequest(QContactAbstractRequest* req, QContactManagerEngine* parent) |
|
52 : QObject(parent), QTrackerContactAsyncRequest(req), errorCount(0) |
|
53 { |
|
54 Q_ASSERT(req); |
|
55 Q_ASSERT(req->type() == QContactAbstractRequest::ContactSaveRequest); |
|
56 Q_ASSERT(parent); |
|
57 |
|
58 QContactSaveRequest* r = qobject_cast<QContactSaveRequest*>(req); |
|
59 if (!r) { |
|
60 QContactManagerEngine::updateRequestState(req, QContactAbstractRequest::FinishedState); |
|
61 return; |
|
62 } |
|
63 |
|
64 QList<QContact> contacts = r->contacts(); |
|
65 |
|
66 if(contacts.isEmpty()) { |
|
67 QMap<int, QContactManager::Error> errors; |
|
68 errors[0] = QContactManager::BadArgumentError; |
|
69 QContactSaveRequest* saveRequest = qobject_cast<QContactSaveRequest*>(req); |
|
70 QContactManagerEngine::updateContactSaveRequest(saveRequest, contacts, QContactManager::BadArgumentError, errors, r->state()); |
|
71 return; |
|
72 } |
|
73 |
|
74 QContactManagerEngine::updateRequestState(req, QContactAbstractRequest::ActiveState); |
|
75 |
|
76 TrackerChangeListener *changeListener = new TrackerChangeListener(parent, this); |
|
77 connect(changeListener, SIGNAL(contactsChanged(const QList<QContactLocalId> &)),SLOT(onTrackerSignal(const QList<QContactLocalId> &))); |
|
78 connect(changeListener, SIGNAL(contactsAdded(const QList<QContactLocalId> &)),SLOT(onTrackerSignal(const QList<QContactLocalId> &))); |
|
79 |
|
80 // Save contacts with batch size |
|
81 /// @todo where to get reasonable batch size |
|
82 int batchSize = 100; |
|
83 for (int i = 0; i < contacts.size(); i+=batchSize) { |
|
84 saveContacts(contacts.mid(i, batchSize)); |
|
85 } |
|
86 } |
|
87 |
|
88 void QTrackerContactSaveRequest::onTrackerSignal(const QList<QContactLocalId> &ids) |
|
89 { |
|
90 computeProgress(ids); |
|
91 } |
|
92 |
|
93 void QTrackerContactSaveRequest::computeProgress(const QList<QContactLocalId> &addedIds) |
|
94 { |
|
95 Q_ASSERT(req->type() == QContactAbstractRequest::ContactSaveRequest); |
|
96 QContactSaveRequest* r = qobject_cast<QContactSaveRequest*>(req); |
|
97 if (!r) { |
|
98 QContactManagerEngine::updateRequestState(req, QContactAbstractRequest::FinishedState); |
|
99 return; |
|
100 } |
|
101 |
|
102 foreach (QContactLocalId id, addedIds) { |
|
103 pendingContactIds.remove(id); |
|
104 // since if was OK, remove entry for error |
|
105 errorsOfContactsFinished.remove(id2Index[id]); |
|
106 } |
|
107 |
|
108 if (pendingContactIds.count() == 0) { |
|
109 // compute master error - part of qtcontacts api |
|
110 QContactManager::Error error = QContactManager::NoError; |
|
111 |
|
112 foreach(QContactManager::Error err, errorsOfContactsFinished.values()) { |
|
113 if( QContactManager::NoError != err ) |
|
114 { |
|
115 error = err; |
|
116 break; |
|
117 } |
|
118 } |
|
119 |
|
120 QContactManagerEngine::updateContactSaveRequest(r, contactsFinished, error, errorsOfContactsFinished, QContactAbstractRequest::FinishedState); |
|
121 } |
|
122 } |
|
123 |
|
124 void QTrackerContactSaveRequest::saveContacts(const QList<QContact> &contacts) |
|
125 { |
|
126 QContactManagerEngine *engine = qobject_cast<QContactManagerEngine *> (parent()); |
|
127 Q_ASSERT(engine); |
|
128 |
|
129 QSettings definitions(QSettings::IniFormat, QSettings::UserScope, "Nokia", "Trackerplugin"); |
|
130 QTrackerContactsLive cLive; |
|
131 RDFServicePtr service = cLive.service(); |
|
132 |
|
133 foreach(QContact contact, contacts) { |
|
134 /* |
|
135 Validation is disabled because it blocks saving contacts parsed from vcards |
|
136 TODO left the commented code while opaque (custom) details are under discussion as remainder |
|
137 QContactManager::Error error; |
|
138 if(!engine->validateContact(contact, error)) { |
|
139 contactsFinished << contact; |
|
140 errorsOfContactsFinished[errorCount++] = error; |
|
141 computeProgress(QList<QContactLocalId>()); |
|
142 continue; |
|
143 } |
|
144 */ |
|
145 Live<nco::PersonContact> ncoContact; |
|
146 bool newContact = false; |
|
147 |
|
148 if(contact.localId() == 0) { |
|
149 // Save new contact. compute ID |
|
150 bool ok; |
|
151 // what if both processes read in the same time and write at the same time, no increment |
|
152 unsigned int m_lastUsedId = definitions.value("nextAvailableContactId", "1").toUInt(&ok); |
|
153 definitions.setValue("nextAvailableContactId", QString::number(++m_lastUsedId)); |
|
154 |
|
155 ncoContact = service->liveNode(QUrl("contact:"+(QString::number(m_lastUsedId)))); |
|
156 QContactId id; |
|
157 id.setLocalId(m_lastUsedId); |
|
158 id.setManagerUri(engine->managerUri()); |
|
159 contact.setId(id); |
|
160 ncoContact->setContactUID(QString::number(m_lastUsedId)); |
|
161 ncoContact->setContentCreated(QDateTime::currentDateTime()); |
|
162 newContact = true; |
|
163 } else { |
|
164 ncoContact = service->liveNode(QUrl("contact:"+QString::number(contact.localId()))); |
|
165 /// @note Following needed in case we save new contact with given localId |
|
166 ncoContact->setContactUID(QString::number(contact.localId())); |
|
167 ncoContact->setContentLastModified(QDateTime::currentDateTime()); |
|
168 } |
|
169 pendingContactIds.insert(contact.localId()); |
|
170 |
|
171 // if there are work related details, need to be saved to Affiliation. |
|
172 if( QTrackerContactSaveRequest::contactHasWorkRelatedDetails(contact)) { |
|
173 addAffiliation(service, contact.localId()); |
|
174 } |
|
175 |
|
176 // Add a special tag for contact added from addressbook, not from fb, telepathy etc. |
|
177 // this is important when returning contacts to sync team |
|
178 RDFVariable rdfContact = RDFVariable::fromType<nco::PersonContact>(); |
|
179 rdfContact.property<nco::contactUID>() = LiteralValue(QString::number(contact.localId())); |
|
180 addTag(service, rdfContact, "addressbook"); |
|
181 |
|
182 saveContactDetails( service, ncoContact, contact, newContact); |
|
183 |
|
184 // name & nickname - different way from other details |
|
185 cLive.setLiveContact(ncoContact); |
|
186 cLive.setQContact(contact); |
|
187 if( !contact.detail<QContactName>().isEmpty() || !contact.detail<QContactNickname>().isEmpty() ) { |
|
188 cLive.saveName(); |
|
189 } |
|
190 |
|
191 contactsFinished << contact; |
|
192 id2Index[contact.localId()] = errorCount; |
|
193 // we fill error here - once response come that everything is OK, remove entry for this contact |
|
194 errorsOfContactsFinished[errorCount++] = QContactManager::BadArgumentError; |
|
195 } |
|
196 // remember to commit the transaction, otherwise all changes will be rolled back. |
|
197 cLive.commit(); |
|
198 } |
|
199 |
|
200 |
|
201 QTrackerContactSaveRequest::~QTrackerContactSaveRequest() |
|
202 { |
|
203 // TODO Auto-generated destructor stub |
|
204 } |
|
205 |
|
206 /*! |
|
207 * Saving has to go in such way that all names are saved at once, all phone numbers together |
|
208 * filled to rdfupdate query etc. |
|
209 * This method goes through the contact and collect which contact detail definitions are there |
|
210 */ |
|
211 QStringList QTrackerContactSaveRequest::detailsDefinitionsInContact(const QContact &c) |
|
212 { |
|
213 QStringList definitions; |
|
214 foreach(const QContactDetail& det, c.details()) |
|
215 { |
|
216 definitions << det.definitionName(); |
|
217 } |
|
218 definitions.removeDuplicates(); |
|
219 return definitions; |
|
220 } |
|
221 |
|
222 //! Just moving this code out of saveContact to make it shorter |
|
223 bool QTrackerContactSaveRequest::contactHasWorkRelatedDetails(const QContact &c) |
|
224 { |
|
225 foreach(const QContactDetail& det, c.details()) |
|
226 { |
|
227 if( det.contexts().contains(QContactDetail::ContextWork)) |
|
228 return true; |
|
229 } |
|
230 return false; |
|
231 } |
|
232 |
|
233 // create nco::Affiliation if there is not one already in tracker |
|
234 void QTrackerContactSaveRequest::addAffiliation(RDFServicePtr service, QContactLocalId contactId) |
|
235 { |
|
236 Live<nco::PersonContact> ncoContact = service->liveNode(QUrl("contact:"+(QString::number(contactId)))); |
|
237 Live<nco::Affiliation> ncoAffiliation = service->liveNode(QUrl("affiliation:"+(QString::number(contactId)))); |
|
238 ncoContact->setHasAffiliation(ncoAffiliation); |
|
239 } |
|
240 |
|
241 void QTrackerContactSaveRequest::saveContactDetails( RDFServicePtr service, |
|
242 Live<nco::PersonContact>& ncoContact, |
|
243 const QContact& contact, |
|
244 bool newContact) |
|
245 { |
|
246 QStringList detailDefinitionsToSave = detailsDefinitionsInContact(contact); |
|
247 |
|
248 // all the rest might need to save to PersonContact and to Affiliation contact |
|
249 RDFVariable rdfPerson = RDFVariable::fromType<nco::PersonContact>(); |
|
250 rdfPerson.property<nco::contactUID>() = LiteralValue(QString::number(contact.localId())); |
|
251 |
|
252 if(not newContact) { |
|
253 // Delete all existing phone numbers - office and home |
|
254 deletePhoneNumbers(service, rdfPerson); |
|
255 } |
|
256 |
|
257 foreach(QString definition, detailDefinitionsToSave) |
|
258 { |
|
259 QList<QContactDetail> details = contact.details(definition); |
|
260 Q_ASSERT(!details.isEmpty()); |
|
261 |
|
262 RDFVariable rdfAffiliation; |
|
263 RDFVariable rdfPerson1; |
|
264 rdfPerson1.property<nco::hasAffiliation>() = rdfAffiliation; |
|
265 rdfPerson1.property<nco::contactUID>() = LiteralValue(QString::number(contact.localId())); |
|
266 |
|
267 QList<QContactDetail> workDetails; |
|
268 QList<QContactDetail> homeDetails; |
|
269 foreach(const QContactDetail& det, details) { |
|
270 // details can be for both contexts, so check for both seperately |
|
271 if( det.contexts().contains(QContactDetail::ContextWork) ) { |
|
272 workDetails << det; |
|
273 } |
|
274 if( det.contexts().contains(QContactDetail::ContextHome)) { |
|
275 homeDetails << det; |
|
276 } |
|
277 if( !det.contexts().contains(QContactDetail::ContextHome) |
|
278 && !det.contexts().contains(QContactDetail::ContextWork)) { |
|
279 homeDetails << det; |
|
280 } |
|
281 } |
|
282 |
|
283 /* Save details */ |
|
284 if(definition == QContactPhoneNumber::DefinitionName) { |
|
285 if (!homeDetails.isEmpty()) { |
|
286 savePhoneNumbers(service, rdfPerson, homeDetails, newContact); |
|
287 } |
|
288 if( !workDetails.isEmpty()) { |
|
289 savePhoneNumbers(service, rdfAffiliation, workDetails, newContact); |
|
290 } |
|
291 } |
|
292 else if(definition == QContactEmailAddress::DefinitionName) { |
|
293 if (!homeDetails.isEmpty()) |
|
294 saveEmails(service, rdfPerson, homeDetails, newContact); |
|
295 if( !workDetails.isEmpty()) |
|
296 saveEmails(service, rdfAffiliation, workDetails, newContact); |
|
297 } |
|
298 else if(definition == QContactAddress::DefinitionName) { |
|
299 if (!homeDetails.isEmpty()) |
|
300 saveAddresses(service, rdfPerson, homeDetails, newContact); |
|
301 if( !workDetails.isEmpty()) |
|
302 saveAddresses(service, rdfAffiliation, workDetails, newContact); |
|
303 } |
|
304 else if(definition == QContactUrl::DefinitionName) { |
|
305 if (!homeDetails.isEmpty()) |
|
306 saveUrls(service, rdfPerson, homeDetails, newContact); |
|
307 if( !workDetails.isEmpty()) |
|
308 saveUrls(service, rdfAffiliation, workDetails, newContact); |
|
309 } |
|
310 else { |
|
311 // TODO refactor (bug: editing photo doesn't work) |
|
312 foreach(const QContactDetail &det, details ) |
|
313 { |
|
314 definition = det.definitionName(); |
|
315 if(definition == QContactAvatar::DefinitionName) { |
|
316 QUrl avatar = det.value(QContactAvatar::FieldImageUrl); |
|
317 Live<nie::DataObject> fdo = service->liveNode( avatar ); |
|
318 ncoContact->setPhoto(fdo); |
|
319 } |
|
320 if(definition == QContactBirthday::DefinitionName) { |
|
321 ncoContact->setBirthDate(QDateTime(det.variantValue(QContactBirthday::FieldBirthday).toDate(), QTime(), Qt::UTC)); |
|
322 } |
|
323 } // end foreach detail |
|
324 } |
|
325 } |
|
326 } |
|
327 |
|
328 // Remove all existing references to phone numbers from the contact so that edits are |
|
329 // reflected to Tracker correctly. |
|
330 // Delete the references to phone numbers - not the numbers themselves as they remain in tracker |
|
331 // with their canonical URI form - might be linked to history. |
|
332 void QTrackerContactSaveRequest::deletePhoneNumbers(RDFServicePtr service, const RDFVariable& rdfContactIn) |
|
333 { |
|
334 { |
|
335 RDFUpdate up; |
|
336 RDFVariable rdfContact = rdfContactIn.deepCopy(); |
|
337 up.addDeletion(rdfContact, nco::hasPhoneNumber::iri(), rdfContact.property<nco::hasPhoneNumber>()); |
|
338 service->executeQuery(up); |
|
339 } |
|
340 |
|
341 // affiliation |
|
342 { |
|
343 RDFUpdate up; |
|
344 RDFVariable rdfContact = rdfContactIn.deepCopy().property<nco::hasAffiliation>(); |
|
345 up.addDeletion(rdfContact, nco::hasPhoneNumber::iri(), rdfContact.property<nco::hasPhoneNumber>()); |
|
346 service->executeQuery(up); |
|
347 } |
|
348 } |
|
349 |
|
350 /*! |
|
351 * write all phone numbers on one query to tracker |
|
352 * TODO this is temporary code for creating new, saving contacts need to handle only what was |
|
353 * changed. |
|
354 */ |
|
355 void QTrackerContactSaveRequest::savePhoneNumbers(RDFServicePtr service, RDFVariable &var, const QList<QContactDetail> &details, bool newContact ) |
|
356 { |
|
357 RDFUpdate up; |
|
358 RDFVariable varForInsert = var.deepCopy(); |
|
359 foreach(const QContactDetail& det, details) |
|
360 { |
|
361 QString formattedValue = det.value(QContactPhoneNumber::FieldNumber); |
|
362 // Strip RFC 3966 visual-separators reg exp "[(|-|.|)| ]" |
|
363 QString value = formattedValue.replace( QRegExp("[\\(|" \ |
|
364 "\\-|" \ |
|
365 "\\.|" \ |
|
366 "\\)|" \ |
|
367 " ]"), ""); |
|
368 // Temporary, because affiliation is still used - to be refactored next week to use Live nodes |
|
369 // using RFC 3966 canonical URI form |
|
370 QUrl newPhone = QString("tel:%1").arg(value); |
|
371 Live<nco::PhoneNumber> ncoPhone = service->liveNode(newPhone); |
|
372 if(not newContact) { |
|
373 ncoPhone->remove(); |
|
374 } |
|
375 |
|
376 QStringList subtypes = det.value<QStringList>(QContactPhoneNumber::FieldSubTypes); |
|
377 |
|
378 if( subtypes.contains(QContactPhoneNumber::SubTypeMobile)) |
|
379 up.addInsertion(newPhone, rdf::type::iri(), nco::CellPhoneNumber::iri()); |
|
380 else if( subtypes.contains(QContactPhoneNumber::SubTypeCar)) |
|
381 up.addInsertion(newPhone, rdf::type::iri(), nco::CarPhoneNumber::iri()); |
|
382 else if( subtypes.contains(QContactPhoneNumber::SubTypeBulletinBoardSystem)) |
|
383 up.addInsertion(newPhone, rdf::type::iri(), nco::BbsNumber::iri()); |
|
384 else if( subtypes.contains(QContactPhoneNumber::SubTypeFax)) |
|
385 up.addInsertion(newPhone, rdf::type::iri(), nco::FaxNumber::iri()); |
|
386 else if( subtypes.contains(QContactPhoneNumber::SubTypeModem)) |
|
387 up.addInsertion(newPhone, rdf::type::iri(), nco::ModemNumber::iri()); |
|
388 else if( subtypes.contains(QContactPhoneNumber::SubTypePager)) |
|
389 up.addInsertion(newPhone, rdf::type::iri(), nco::PagerNumber::iri()); |
|
390 else if( subtypes.contains(QContactPhoneNumber::SubTypeMessagingCapable)) |
|
391 up.addInsertion(newPhone, rdf::type::iri(), nco::MessagingNumber::iri()); |
|
392 else |
|
393 up.addInsertion(newPhone, rdf::type::iri(), nco::VoicePhoneNumber::iri()); |
|
394 |
|
395 up.addInsertion(newPhone, nco::phoneNumber::iri(), LiteralValue(value)); |
|
396 up.addInsertion(varForInsert, nco::hasPhoneNumber::iri(), newPhone); |
|
397 } |
|
398 service->executeQuery(up); |
|
399 } |
|
400 |
|
401 /*! |
|
402 * write all phone numbers on one query to tracker |
|
403 * TODO this is temporary code for creating new, saving contacts need to handle only what was |
|
404 * changed. |
|
405 */ |
|
406 void QTrackerContactSaveRequest::saveEmails(RDFServicePtr service, RDFVariable &var, const QList<QContactDetail> &details, bool newContact ) |
|
407 { |
|
408 RDFUpdate up; |
|
409 RDFVariable varForInsert = var.deepCopy(); |
|
410 RDFVariable emails = var.property<nco::hasEmailAddress>(); |
|
411 if(not newContact) { |
|
412 // delete previous references - keep email IRIs |
|
413 up.addDeletion(RDFVariableStatement(var, nco::hasEmailAddress::iri(), emails)); |
|
414 } |
|
415 |
|
416 foreach(const QContactDetail& det, details) |
|
417 { |
|
418 QString value = det.value(QContactEmailAddress::FieldEmailAddress); |
|
419 // Temporary, because affiliation is still used - to be refactored next week to use only Live nodes |
|
420 QUrl newEmail = QString("mailto:%1").arg(value); |
|
421 Live<nco::EmailAddress> ncoEmail = service->liveNode(newEmail); |
|
422 up.addInsertion(newEmail, rdf::type::iri(), nco::EmailAddress::iri()); |
|
423 up.addInsertion(newEmail, nco::emailAddress::iri(), LiteralValue(value)); |
|
424 up.addInsertion(RDFVariableStatement(varForInsert, nco::hasEmailAddress::iri(), newEmail)); |
|
425 } |
|
426 service->executeQuery(up); |
|
427 } |
|
428 |
|
429 /*! |
|
430 * write all Urls |
|
431 * TODO this is temporary code for creating new, saving contacts need to handle only what was |
|
432 * changed. |
|
433 */ |
|
434 void QTrackerContactSaveRequest::saveUrls(RDFServicePtr service, RDFVariable &rdfContact, const QList<QContactDetail> &details, bool newContact ) |
|
435 { |
|
436 RDFUpdate up; |
|
437 RDFVariable varForInsert = rdfContact.deepCopy(); |
|
438 RDFVariable urls = rdfContact.property<nco::url>(); |
|
439 RDFVariable urltypes = urls.property<rdf::type>(); |
|
440 |
|
441 RDFVariable websiteUrls = rdfContact.property<nco::websiteUrl>(); |
|
442 RDFVariable websiteUrlTypes = websiteUrls.property<rdf::type>(); |
|
443 |
|
444 if(not newContact) { |
|
445 // first part - deleting previous before adding new again is to be removed |
|
446 up.addDeletion(RDFVariableStatement(rdfContact, nco::url::iri(), urls)); |
|
447 up.addDeletion(RDFVariableStatement(rdfContact, nco::websiteUrl::iri(), websiteUrls)); |
|
448 } |
|
449 |
|
450 // second part, write all urls |
|
451 foreach(const QContactDetail& det, details) |
|
452 { |
|
453 QUrl newUrl(det.value(QContactUrl::FieldUrl));//::tracker()->createLiveNode().uri(); |
|
454 if(det.value(QContactUrl::FieldSubType) == QContactUrl::SubTypeFavourite) |
|
455 { |
|
456 up.addInsertion(varForInsert, nco::url::iri(), newUrl); |
|
457 } |
|
458 else // if not favourite, then homepage. don't support other |
|
459 { |
|
460 up.addInsertion(varForInsert, nco::websiteUrl::iri(), newUrl); // add it to contact |
|
461 } |
|
462 } |
|
463 service->executeQuery(up); |
|
464 } |
|
465 |
|
466 /*! |
|
467 * write all phone numbers on one query to tracker |
|
468 * TODO this is temporary code for creating new, saving contacts need to handle only what was |
|
469 * changed. |
|
470 */ |
|
471 void QTrackerContactSaveRequest::saveAddresses(RDFServicePtr service, RDFVariable &var, const QList<QContactDetail> &details, bool newContact ) |
|
472 { |
|
473 RDFUpdate up; |
|
474 RDFVariable varForInsert = var.deepCopy(); |
|
475 RDFVariable addresses = var.property<nco::hasPostalAddress>(); |
|
476 RDFVariable types = addresses.property<rdf::type>(); |
|
477 if(not newContact) { |
|
478 up.addDeletion(RDFVariableStatement(var, nco::hasPostalAddress::iri(), addresses)); |
|
479 up.addDeletion(addresses, rdf::type::iri(), types); |
|
480 } |
|
481 foreach(const QContactDetail& det, details) |
|
482 { |
|
483 QUrl newPostalAddress = ::tracker()->createLiveNode().uri(); |
|
484 // TODO nco:DomesticDeliveryAddress, nco:InternationalDeliveryAddress, nco:ParcelDeliveryAddress |
|
485 up.addInsertion(newPostalAddress, rdf::type::iri(), nco::PostalAddress::iri()); |
|
486 if( det.hasValue(QContactAddress::FieldStreet)) |
|
487 up.addInsertion(newPostalAddress, nco::streetAddress::iri(), LiteralValue(det.value(QContactAddress::FieldStreet))); |
|
488 if( det.hasValue(QContactAddress::FieldLocality)) |
|
489 up.addInsertion(newPostalAddress, nco::locality::iri(), LiteralValue(det.value(QContactAddress::FieldLocality))); |
|
490 if( det.hasValue(QContactAddress::FieldCountry)) |
|
491 up.addInsertion(newPostalAddress, nco::country::iri(), LiteralValue(det.value(QContactAddress::FieldCountry))); |
|
492 if( det.hasValue(QContactAddress::FieldPostcode)) |
|
493 up.addInsertion(newPostalAddress, nco::postalcode::iri(), LiteralValue(det.value(QContactAddress::FieldPostcode))); |
|
494 if( det.hasValue(QContactAddress::FieldRegion)) |
|
495 up.addInsertion(newPostalAddress, nco::region::iri(), LiteralValue(det.value(QContactAddress::FieldRegion))); |
|
496 |
|
497 up.addInsertion(RDFVariableStatement(varForInsert, nco::hasPostalAddress::iri(), newPostalAddress)); |
|
498 } |
|
499 service->executeQuery(up); |
|
500 } |
|
501 |
|
502 /*! |
|
503 * Not very good solution, but we add "addressbook" tag to identify which contacts |
|
504 * are added but addressbook ( in order to separate them from facebook and telepathy |
|
505 * contacts |
|
506 */ |
|
507 void QTrackerContactSaveRequest::createTagIfItDoesntExistAlready(SopranoLive::RDFServicePtr service, const QString &tag) |
|
508 { |
|
509 static bool checked = false; |
|
510 // only once, if someone remove tag we are in problems (lost contacts) |
|
511 if( !checked ) |
|
512 { |
|
513 checked = true; |
|
514 RDFVariable rdfTag = RDFVariable::fromType<nao::Tag>(); |
|
515 RDFVariable labelVar = rdfTag.optional().property<nao::prefLabel>(); |
|
516 labelVar = LiteralValue(tag); |
|
517 RDFFilter doesntExist = labelVar.isBound().not_();// do not create if it already exist |
|
518 |
|
519 RDFUpdate up; |
|
520 |
|
521 QUrl newTag = ::tracker()->createLiveNode().uri(); |
|
522 rdfTag = newTag; |
|
523 QList<RDFVariableStatement> insertions; |
|
524 insertions << RDFVariableStatement(rdfTag, rdf::type::iri(), nao::Tag::iri()) |
|
525 << RDFVariableStatement(newTag, nao::prefLabel::iri(), labelVar); |
|
526 up.addInsertion(insertions); // this way we apply filter doesntExist to both insertions |
|
527 service->executeQuery(up); |
|
528 } |
|
529 } |
|
530 |
|
531 void QTrackerContactSaveRequest::addTag(RDFServicePtr service, RDFVariable &var, const QString &tag) |
|
532 { |
|
533 // TODO do all in one RDF query: create tag if not existing |
|
534 createTagIfItDoesntExistAlready(service, tag); |
|
535 RDFUpdate up; |
|
536 RDFVariable rdftag; |
|
537 rdftag.property<nao::prefLabel>() = LiteralValue(tag); |
|
538 up.addInsertion(var, nao::hasTag::iri(), rdftag); |
|
539 service->executeQuery(up); |
|
540 } |
|