Fix method signature of filterSupported().
[qtcontacts-tracker:qtcontacts-tracker.git] / qcontacttrackerbackend.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 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 "qcontacttrackerbackend_p.h"
43
44 #include <QtTracker/Tracker>
45 #include <QtTracker/ontologies/nco.h>
46 #include <QtTracker/ontologies/nie.h>
47 #include <QtTracker/ontologies/nao.h>
48 #include <QRegExp>
49 #include <QDir>
50 #include <QFile>
51 #include <QSet>
52 #include <QList>
53
54 #include "qtcontacts.h"
55
56 #include "trackerchangelistener.h"
57 #include "qtrackercontactsaverequest.h"
58 #include <qtrackerrelationshipfetchrequest.h>
59 #include <qtrackerrelationshipsaverequest.h>
60 #include <qtrackercontactidfetchrequest.h>
61
62
63 QContactManagerEngine* ContactTrackerFactory::engine(const QMap<QString, QString>& parameters, QContactManager::Error& error)
64 {
65     Q_UNUSED(error);
66     QString version = QLatin1String(VERSION_INFO);
67     return new QContactTrackerEngine(managerName(), version.toInt(), parameters);
68 }
69
70 QString ContactTrackerFactory::managerName() const
71 {
72     return QString("tracker");
73 }
74 Q_EXPORT_PLUGIN2(qtcontacts_tracker, ContactTrackerFactory);
75
76 QContactTrackerEngine::QContactTrackerEngine(const QString& engineName, int engineVersion, const QMap<QString, QString>& parameters)
77     : d(new QContactTrackerEngineData),
78     contactArchiveFile("removed"),
79     contactArchiveDir(QDir::homePath()+"/.contacts")
80 {
81     Q_UNUSED(parameters);
82     d->m_engineName = engineName;
83     d->m_engineVersion = engineVersion;
84     connectToSignals();
85 }
86
87 QContactTrackerEngine::QContactTrackerEngine(const QMap<QString, QString>& parameters)
88     : d(new QContactTrackerEngineData),
89     contactArchiveFile("removed"),
90     contactArchiveDir(QDir::homePath()+"/.contacts")
91 {
92     Q_UNUSED(parameters);
93     connectToSignals();
94 }
95
96 QContactTrackerEngine::QContactTrackerEngine(const QContactTrackerEngine& other)
97     : QContactManagerEngine(), d(other.d)
98 {
99     Q_UNUSED(other);
100     connectToSignals();
101 }
102
103 void QContactTrackerEngine::connectToSignals()
104 {
105     TrackerChangeListener *listener = new TrackerChangeListener(this);
106     connect(listener, SIGNAL(contactsAdded(const QList<QContactLocalId>&)), SIGNAL(contactsAdded(const QList<QContactLocalId>&)));
107     connect(listener, SIGNAL(contactsChanged(const QList<QContactLocalId>&)), SIGNAL(contactsChanged(const QList<QContactLocalId>&)));
108     connect(listener, SIGNAL(contactsRemoved(const QList<QContactLocalId>&)), SIGNAL(contactsRemoved(const QList<QContactLocalId>&)));
109 }
110
111 QContactTrackerEngine& QContactTrackerEngine::operator=(const QContactTrackerEngine& other)
112 {
113     d = other.d;
114     return *this;
115 }
116
117 QContactTrackerEngine::~QContactTrackerEngine()
118 {
119 }
120
121 QContactManagerEngine* QContactTrackerEngine::clone()
122 {
123     // this engine allows sharing - so we increase the reference count.
124     d->m_refCount.ref();
125     return this;
126 }
127
128 void QContactTrackerEngine::deref()
129 {
130     if (!d->m_refCount.deref())
131         delete this;
132 }
133
134 QList<QContactLocalId> QContactTrackerEngine::contactIds(const QList<QContactSortOrder>& sortOrders, QContactManager::Error& error) const
135 {
136     return contactIds(QContactFilter(), sortOrders, error);
137 }
138
139 QList<QContactLocalId> QContactTrackerEngine::contactIds(const QContactFilter& filter, const QList<QContactSortOrder>& sortOrders, QContactManager::Error& error) const
140 {
141     QContactLocalIdFetchRequest request;
142     request.setFilter(filter);
143     request.setSorting(sortOrders);
144
145     QContactTrackerEngine engine(*this);
146     engine.startRequest(&request);
147     // 10 seconds should be enough
148     engine.waitForRequestFinished(&request, 10000);
149     if(!request.isFinished()) {
150         error = QContactManager::UnspecifiedError;
151     }
152     else {
153         // leave the code for now while not all other code is fixed
154         error = request.error();
155     }
156     return request.ids();
157 }
158
159 QList<QContact> QContactTrackerEngine::contacts(const QList<QContactSortOrder>& sortOrders, const QStringList& definitionRestrictions, QContactManager::Error& error) const
160 {
161     return contacts(QContactFilter(), sortOrders, definitionRestrictions, error);
162 }
163
164 QList<QContact> QContactTrackerEngine::contacts(const QContactFilter& filter, const QList<QContactSortOrder>& sortOrders, const QStringList& definitionRestrictions, QContactManager::Error& error) const
165 {
166     // the rest of the code is for internal usage, unit tests etc.
167     QContactFetchRequest request;
168     request.setDefinitionRestrictions(definitionRestrictions);
169     request.setFilter(filter);
170     request.setSorting(sortOrders);
171
172     QContactTrackerEngine engine(*this);
173     engine.startRequest(&request);
174     // 10 seconds should be enough
175     engine.waitForRequestFinished(&request, 10000);
176
177     if( !request.isFinished()) {
178         error = QContactManager::UnspecifiedError;
179     }
180     else {
181         // leave the code for now while not all other code is fixed
182         error = request.error();
183     }
184     return request.contacts();
185 }
186
187 QContact QContactTrackerEngine::contact(const QContactLocalId& contactId, QContactManager::Error& error ) const
188 {
189     qWarning() << "QContactManager::contact()" << "api is not supported for tracker plugin. Please use asynchronous API QContactFetchRequest.";
190     return contact_impl(contactId, error);
191 }
192 // used in tests, removed warning while decided if to provide sync api. Until then customers are advised to use async
193 QContact QContactTrackerEngine::contact_impl(const QContactLocalId& contactId, QContactManager::Error& error ) const
194 {
195     // the rest of the code is for internal usage, unit tests etc.
196     QContactLocalIdFilter idlist;
197     QList<QContactLocalId> ids; ids << contactId;
198     idlist.setIds(ids);
199     QContactFetchRequest request;
200     QStringList fields;
201
202     fields << QContactAvatar::DefinitionName
203             << QContactBirthday::DefinitionName
204             << QContactAddress::DefinitionName
205             << QContactEmailAddress::DefinitionName
206             << QContactDisplayLabel::DefinitionName
207             << QContactGender::DefinitionName
208             << QContactAnniversary::DefinitionName
209             << QContactName::DefinitionName
210             << QContactOnlineAccount::DefinitionName
211             << QContactOrganization::DefinitionName
212             << QContactPhoneNumber::DefinitionName
213             << QContactOnlineAccount::DefinitionName
214             << QContactUrl::DefinitionName;
215     request.setDefinitionRestrictions(fields);
216     request.setFilter(idlist);
217
218     QContactTrackerEngine engine(*this);
219     engine.startRequest(&request);
220     // 10 seconds should be enough
221     engine.waitForRequestFinished(&request, 10000);
222
223     if( !request.isFinished()) {
224         error = QContactManager::UnspecifiedError;
225         return QContact();
226     }
227     else if(request.contacts().size() == 0)
228     {
229         error = QContactManager::DoesNotExistError;
230         return QContact();
231     }
232     else {
233         // leave the code for now while not all other code is fixed
234         error = request.error();
235         return request.contacts()[0];
236     }
237
238 }
239
240 bool QContactTrackerEngine::waitForRequestFinished(QContactAbstractRequest* req, int msecs)
241 {
242     Q_ASSERT(req);
243     if(!req->isActive())
244     {
245         return req->isFinished(); // might be already finished
246     }
247     QTime t;
248     t.start();
249     while(t.elapsed() < msecs || msecs == 0) // 0 for infinite
250     {
251         usleep(10000);
252         QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
253         if(req->isFinished())
254             return true;
255     }
256     qDebug() << Q_FUNC_INFO <<"Status Finished" << req->isFinished();
257     return req->isFinished();
258
259 }
260
261 bool QContactTrackerEngine::saveContact( QContact* contact, QContactManager::Error& error)
262 {
263     // Signal emitted from TrackerChangeListener
264     QContactSaveRequest request;
265     QList<QContact> contacts(QList<QContact>()<<*contact);
266     request.setContacts(contacts);
267     QContactTrackerEngine engine(*this);
268     engine.startRequest(&request);
269     // 10 seconds should be enough
270     engine.waitForRequestFinished(&request, 10000);
271     error = request.error();
272     Q_ASSERT(request.contacts().size() == 1);
273     *contact = request.contacts()[0];
274
275     if( request.isFinished() && error == QContactManager::NoError)
276         return true;
277     else
278         return false;
279 }
280
281 bool QContactTrackerEngine::removeContact(const QContactLocalId& contactId, QContactManager::Error& error)
282 {
283     error = QContactManager::NoError;
284
285     // TODO: Do with LiveNodes when they support strict querying.
286     RDFVariable RDFContact = RDFVariable::fromType<nco::PersonContact>();
287     RDFContact.property<nco::contactUID>() = LiteralValue(QString::number(contactId));
288     RDFSelect query;
289
290     query.addColumn("contact_uri", RDFContact);
291     LiveNodes ncoContacts = ::tracker()->modelQuery(query);
292     if(ncoContacts->rowCount() == 0) {
293         error = QContactManager::DoesNotExistError;
294         return false;
295     }
296
297
298     Live< nco::PersonContact> ncoContact = ncoContacts->liveNode(0);
299     LiveNodes contactMediums = ncoContact->getHasContactMediums();
300     foreach(Live<nco::ContactMedium> media, contactMediums) {
301         media->remove();
302     }
303     ncoContact->remove();
304
305     //Temporary workaround to get removed- signal
306     QList<QContactLocalId> removed;
307     removed << contactId;
308     emit contactsRemoved(removed);
309
310     return true;
311 }
312
313 bool QContactTrackerEngine::saveContacts(QList<QContact>* contacts, QMap<int, QContactManager::Error>* errorMap, QContactManager::Error& error)
314 {
315     // @todo: Handle errors per saved contact.
316     Q_UNUSED(errorMap)
317
318     error = QContactManager::NoError;
319
320     if(contacts == 0) {
321         error = QContactManager::BadArgumentError;
322         return false;
323     }
324
325     // Signal emitted from TrackerChangeListener
326     QContactSaveRequest request;
327     QList<QContact> contactList;
328     for (int i = 0; i < contacts->size(); ++i) {
329         contactList.append(contacts->at(i));
330     }
331     request.setContacts(contactList);
332     QContactTrackerEngine engine(*this);
333     engine.startRequest(&request);
334     /// @todo what should be the delay
335     engine.waitForRequestFinished(&request, 1000*contacts->size());
336     /// @todo what should we do in case request.isFinished() == false
337     if (request.isFinished() == false) {
338         qWarning() << "QContactTrackerEngine::saveContacts:" << "request not finished";
339     }
340     error = request.error();
341     for (int i = 0; i < contacts->size(); ++i) {
342         (*contacts)[i] = request.contacts().at(i);
343     }
344
345     // Returns false if we have any errors - true if everything went ok.
346     return (request.errorMap().isEmpty() && error == QContactManager::NoError);
347 }
348
349 bool QContactTrackerEngine::removeContacts(QList<QContactLocalId>* contactIds, QMap<int, QContactManager::Error>* errorMap, QContactManager::Error& error)
350 {
351     // Cannot report errors - giving up.
352     if(!errorMap) {
353         error = QContactManager::BadArgumentError;
354         return false;
355     }
356
357     // let's clear the error hash so there is nothing old haunting us.
358     errorMap->clear();
359
360     if (!contactIds) {
361         error = QContactManager::BadArgumentError;
362         return false;
363     }
364
365     for (int i = 0; i < contactIds->count(); i++) {
366         QContactManager::Error lastError;
367         removeContact(contactIds->at(i), lastError);
368         if (lastError == QContactManager::NoError) {
369             (*contactIds)[i] = 0;
370         }
371         else {
372             errorMap->insert(i, lastError);
373         }
374     }
375
376     // Returns true if no errors were encountered - false if there was errors.
377     // emit signals removed as they are fired from QContactManager
378     return (errorMap->isEmpty());
379 }
380
381 QMap<QString, QContactDetailDefinition> QContactTrackerEngine::detailDefinitions(const QString& contactType,
382                                                                                  QContactManager::Error& error) const
383 {
384     if (contactType != QContactType::TypeContact) {
385         error = QContactManager::InvalidContactTypeError;
386         return QMap<QString, QContactDetailDefinition>();
387     }
388
389     // lazy initialisation of schema definitions.
390     if (d->m_definitions.isEmpty()) {
391         // none in the list?  get the schema definitions, and modify them to match our capabilities.
392         d->m_definitions = QContactManagerEngine::schemaDefinitions().value(QContactType::TypeContact);
393
394         // modification: name is unique
395         QContactDetailDefinition nameDef = d->m_definitions.value(QContactName::DefinitionName);
396         nameDef.setUnique(true);
397         d->m_definitions.insert(QContactName::DefinitionName, nameDef);
398
399         // modification: avatar is unique.
400         QContactDetailDefinition avatarDef = d->m_definitions.value(QContactAvatar::DefinitionName);
401         avatarDef.setUnique(true);
402         d->m_definitions.insert(QContactAvatar::DefinitionName, avatarDef);
403
404         // modification: url is unique.
405         {
406             const QContactDetailDefinition urlDef = d->m_definitions.value(
407                     QContactUrl::DefinitionName);
408             QContactDetailDefinition newUrlDef;
409
410             QMap<QString, QContactDetailFieldDefinition> urlFieldNames = urlDef.fields();
411             QMap<QString, QContactDetailFieldDefinition> &fields(urlFieldNames);
412             QContactDetailFieldDefinition f;
413
414             f.setDataType(QVariant::String);
415             QVariantList subTypes;
416             // removing social networking url
417             subTypes << QString(QLatin1String(QContactUrl::SubTypeFavourite));
418             subTypes << QString(QLatin1String(QContactUrl::SubTypeHomePage));
419             f.setAllowableValues(subTypes);
420             fields.insert(QContactUrl::FieldSubType, f);
421             newUrlDef.setFields(fields);
422             newUrlDef.setUnique(true);
423             newUrlDef.setName(QContactUrl::DefinitionName);
424             d->m_definitions.insert(QContactUrl::DefinitionName, newUrlDef);
425         }
426
427         // QContactOnlineAccount custom fields
428         {
429             const QContactDetailDefinition accDef = d->m_definitions.value(QContactOnlineAccount::DefinitionName);
430             QContactDetailDefinition newAccountDefinition;
431
432             QMap<QString, QContactDetailFieldDefinition> accountFieldName = accDef.fields();
433             QMap<QString, QContactDetailFieldDefinition> &fields(accountFieldName);
434             QContactDetailFieldDefinition f;
435
436             f.setDataType(QVariant::String);
437             fields.insert("Account", f);
438             fields.insert("AccountPath", f);
439             newAccountDefinition.setFields(fields);
440             newAccountDefinition.setName(QContactOnlineAccount::DefinitionName);
441             d->m_definitions.insert(QContactOnlineAccount::DefinitionName, newAccountDefinition);
442         }
443     }
444
445     error = QContactManager::NoError;
446     return d->m_definitions;
447 }
448
449 /*!
450  * \reimp
451  */
452 bool QContactTrackerEngine::hasFeature(QContactManager::ManagerFeature feature, const QString& contactType) const
453 {
454     if (!supportedContactTypes().contains(contactType)) {
455         return false;
456     }
457
458     switch (feature) {
459         case QContactManager::Groups:
460         case QContactManager::ActionPreferences:
461         case QContactManager::Relationships:
462             return true;
463         case QContactManager::ArbitraryRelationshipTypes:
464             return true;
465         case QContactManager::MutableDefinitions:
466             return true;
467         case QContactManager::ChangeLogs:
468             return true;
469         default:
470             return false;
471     }
472 }
473
474
475 /*!
476  * \reimp
477  */
478 /*!
479  * Definition identifiers which are natively (fast) filterable
480  * on the default backend store managed by the manager from which the capabilities object was accessed
481  */
482 bool QContactTrackerEngine::isFilterSupported(const QContactFilter& filter) const
483 {
484     switch (filter.type()) {
485         case QContactFilter::InvalidFilter:
486         case QContactFilter::DefaultFilter:
487         case QContactFilter::LocalIdFilter:
488         case QContactFilter::ContactDetailFilter:
489         case QContactFilter::ContactDetailRangeFilter:
490         case QContactFilter::ActionFilter:
491         case QContactFilter::ChangeLogFilter:
492         case QContactFilter::RelationshipFilter:
493
494 // not yet done
495 //        case QContactFilter::IntersectionFilter:
496 //        case QContactFilter::UnionFilter:
497             return true;
498         default:
499             return false;
500     }
501 }
502
503 /*!
504  * Returns the list of data types supported by the Tracker engine
505  */
506 QList<QVariant::Type> QContactTrackerEngine::supportedDataTypes() const
507 {
508     // TODO: Check supported datatypes for Tracker backend.
509     QList<QVariant::Type> st;
510     st.append(QVariant::String);
511     st.append(QVariant::Date);
512     st.append(QVariant::DateTime);
513     return st;
514 }
515
516 /*!
517  * Returns the name of the Tracker engine
518  */
519 QString QContactTrackerEngine::managerName() const
520 {
521     return d->m_engineName;
522 }
523
524 /*!
525  * Returns the manager version of this engine
526  */
527 int QContactTrackerEngine::managerVersion() const
528 {
529     return d->m_engineVersion;
530 }
531
532 RDFVariable QContactTrackerEngine::contactDetail2Rdf(const RDFVariable& rdfContact, const QString& definitionName,
533                                                       const QString& fieldName) const
534 {
535     if (definitionName == QContactName::DefinitionName) {
536         if (fieldName == QContactName::FieldFirst) {
537             return rdfContact.property<nco::nameGiven>();
538         }
539         else if (fieldName == QContactName::FieldLast) {
540             return rdfContact.property<nco::nameFamily>();
541         }
542         else if (fieldName == QContactName::FieldMiddle) {
543             return rdfContact.property<nco::nameAdditional>();
544         }
545         else if (fieldName == QContactName::FieldPrefix) {
546             return rdfContact.property<nco::nameHonorificPrefix>();
547         }
548         else if (fieldName == QContactName::FieldSuffix) {
549             return rdfContact.property<nco::nameHonorificSuffix>();
550         }
551         else if (fieldName == QContactNickname::FieldNickname) {
552             return rdfContact.property<nco::nickname>();
553         }
554     }
555     return RDFVariable();
556 }
557
558 /*! \reimp */
559 void QContactTrackerEngine::requestDestroyed(QContactAbstractRequest* req)
560 {
561     if( d->m_requests.contains(req) )
562     {
563         QTrackerContactAsyncRequest *request = d->m_requests.take(req);
564         delete request;
565     }
566 }
567
568 /*! \reimp */
569 bool QContactTrackerEngine::startRequest(QContactAbstractRequest* req)
570 {
571     QTrackerContactAsyncRequest *request = 0;
572     switch (req->type())
573     {
574         case QContactAbstractRequest::ContactLocalIdFetchRequest:
575             request = new QTrackerContactIdFetchRequest(req, this);
576             break;
577         case QContactAbstractRequest::ContactFetchRequest:
578             request = new QTrackerContactFetchRequest(req, this);
579             break;
580         case QContactAbstractRequest::ContactSaveRequest:
581             request = new QTrackerContactSaveRequest(req, this);
582             break;
583         case QContactAbstractRequest::RelationshipFetchRequest:
584             request = new QTrackerRelationshipFetchRequest(req, this);
585             break;
586         case QContactAbstractRequest::RelationshipSaveRequest:
587             request = new QTrackerRelationshipSaveRequest(req, this);
588             break;
589         default:
590             return false;
591     }
592     d->m_requests[req] = request;
593     return true;
594 }
595
596 /*! \reimp */
597 QString QContactTrackerEngine::synthesizedDisplayLabel(const QContact& contact, QContactManager::Error& error) const
598 {
599     QString label = QContactManagerEngine::synthesizedDisplayLabel(contact, error);
600     if (label.isEmpty())
601         label = contact.detail<QContactNickname>().nickname();
602     if(label.isEmpty())
603         label = contact.detail<QContactOnlineAccount>().nickname();
604     return label;
605 }