Changes: add QTrackerContactDetail::implementations(QTrackerContactDetailSchema)
[qtcontacts-tracker:hasselmms-qtcontacts-tracker.git] / src / dao / contactdetail.cpp
1 /*********************************************************************************
2  ** This file is part of QtContacts tracker storage plugin
3  **
4  ** Copyright (c) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
5  **
6  ** Contact:  Nokia Corporation (info@qt.nokia.com)
7  **
8  ** GNU Lesser General Public License Usage
9  ** This file may be used under the terms of the GNU Lesser General Public License
10  ** version 2.1 as published by the Free Software Foundation and appearing in the
11  ** file LICENSE.LGPL included in the packaging of this file.  Please review the
12  ** following information to ensure the GNU Lesser General Public License version
13  ** 2.1 requirements will be met:
14  ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
15  **
16  ** In addition, as a special exception, Nokia gives you certain additional rights.
17  ** These rights are described in the Nokia Qt LGPL Exception version 1.1, included
18  ** in the file LGPL_EXCEPTION.txt in this package.
19  **
20  ** Other Usage
21  ** Alternatively, this file may be used in accordance with the terms and
22  ** conditions contained in a signed written agreement between you and Nokia.
23  *********************************************************************************/
24
25 #include "contactdetail_p.h"
26 #include "contactdetailfield.h"
27 #include "support.h"
28
29 ///////////////////////////////////////////////////////////////////////////////////////////////////
30
31 QTrackerContactDetail::QTrackerContactDetail(const QString &name)
32     : d(new QTrackerContactDetailData(name))
33 {
34 }
35
36 QTrackerContactDetail::QTrackerContactDetail(QTrackerContactDetailData *data)
37     : d(data)
38 {
39 }
40
41 QTrackerContactDetail::~QTrackerContactDetail()
42 {
43 }
44
45 ///////////////////////////////////////////////////////////////////////////////////////////////////
46
47 QTrackerContactDetail::QTrackerContactDetail(const QTrackerContactDetail &other)
48     : d(other.d)
49 {
50 }
51
52 QTrackerContactDetail &
53 QTrackerContactDetail::operator=(const QTrackerContactDetail &other)
54 {
55     return d = other.d, *this;
56 }
57
58 ///////////////////////////////////////////////////////////////////////////////////////////////////
59
60 const QString &
61 QTrackerContactDetail::name() const
62 {
63     return d->m_name;
64 }
65
66 void
67 QTrackerContactDetail::setHasContext(bool flag)
68 {
69     d->m_hasContext = flag;
70 }
71
72 bool
73 QTrackerContactDetail::hasContext() const
74 {
75     return d->m_hasContext;
76 }
77
78 void
79 QTrackerContactDetail::setUnique(bool flag)
80 {
81     d->m_isUnique = flag;
82 }
83
84 bool
85 QTrackerContactDetail::isUnique() const
86 {
87     return d->m_isUnique;
88 }
89
90 void
91 QTrackerContactDetail::setInternal(bool flag)
92 {
93     d->m_isInternal = flag;
94 }
95
96 bool
97 QTrackerContactDetail::isInternal() const
98 {
99     return d->m_isInternal;
100 }
101
102 void
103 QTrackerContactDetail::addField(const QTrackerContactDetailField &field)
104 {
105     d->m_fields.append(field);
106     d->m_chainsDirty = true;
107 }
108
109 const QList<QTrackerContactDetailField> &
110 QTrackerContactDetail::fields() const
111 {
112     return d->m_fields;
113 }
114
115 bool
116 QTrackerContactDetailData::isPossessedChain(const PropertyInfoList &chain) const
117 {
118     foreach(const PropertyInfoList &foreignKeyChain, m_foreignKeyChains) {
119         if (chain.startsWith(foreignKeyChain)) {
120             return false;
121         }
122     }
123
124     return true;
125 }
126
127 static PropertyInfoList::ConstIterator
128 endOfPredicateChain(const PropertyInfoList &chain)
129 {
130     PropertyInfoList::ConstIterator pi = chain.constBegin();
131
132     for(; pi != chain.constEnd(); ++pi) {
133         if (pi->isInverse()) {
134             break;
135         }
136     }
137
138     return pi - 1;
139 }
140
141 void
142 QTrackerContactDetailData::computePredicateChains()
143 {
144     m_predicateChains.clear();
145     m_foreignKeyChains.clear();
146     m_possessedChains.clear();
147
148     // Collect predicate chains from detail fields.
149     // Also identify chains that lead to foreign keys.
150     foreach(const QTrackerContactDetailField &field, m_fields) {
151         if (not field.hasPropertyChain()) {
152             continue;
153         }
154
155         PropertyInfoList fieldPredicates(field.propertyChain().constBegin(),
156                                          endOfPredicateChain(field.propertyChain()));
157
158         if (not fieldPredicates.isEmpty()) {
159             if (field.isForeignKey()) {
160                 m_foreignKeyChains += fieldPredicates;
161             }
162
163             m_predicateChains += fieldPredicates;
164         }
165     }
166
167     // Figure out which predicate chains are fully possessed,
168     // e.g. don't lead to some shared resources identified by foreign keys.
169     foreach(const PropertyInfoList &chain, m_predicateChains) {
170         if (isPossessedChain(chain)) {
171             m_possessedChains += chain;
172         }
173     }
174
175     m_chainsDirty = false;
176 }
177
178 const QSet<PropertyInfoList> &
179 QTrackerContactDetail::predicateChains() const
180 {
181     if (d->m_chainsDirty) {
182         d->computePredicateChains();
183     }
184
185     return d->m_predicateChains;
186 }
187
188 const QSet<PropertyInfoList> &
189 QTrackerContactDetail::foreignKeyChains() const
190 {
191     if (d->m_chainsDirty) {
192         d->computePredicateChains();
193     }
194
195     return d->m_foreignKeyChains;
196 }
197
198 const QSet<PropertyInfoList> &
199 QTrackerContactDetail::possessedChains() const
200 {
201     if (d->m_chainsDirty) {
202         d->computePredicateChains();
203     }
204
205     return d->m_possessedChains;
206 }
207
208 const QSet<PropertyInfoList> &
209 QTrackerContactDetail::customValueChains() const
210 {
211     if (d->m_customValueChains.isEmpty()) {
212         foreach(const QTrackerContactDetailField &field, fields()) {
213             if (not field.permitsCustomValues() || not field.hasPropertyChain()) {
214                 // skip fields that don't permit custom values
215                 continue;
216             }
217
218             PropertyInfoList::ConstIterator begin = field.propertyChain().constBegin();
219             PropertyInfoList::ConstIterator end = field.propertyChain().constEnd();
220
221             if (not field.hasSubTypeClasses() && not field.isWithoutMapping()) {
222                 // find relevant end of the property chain
223                 end -= 1;
224             }
225
226             // build and store predicate chain
227             PropertyInfoList fieldPredicates(begin, end);
228
229             if (not fieldPredicates.isEmpty()) {
230                 d->m_customValueChains += fieldPredicates;
231             }
232         }
233     }
234
235     return d->m_customValueChains;
236 }
237
238 void
239 QTrackerContactDetail::addDependency(const QString &detail)
240 {
241     d->m_dependencies.insert(detail);
242 }
243
244 const QSet<QString> &
245 QTrackerContactDetail::dependencies() const
246 {
247     return d->m_dependencies;
248 }
249
250 const QTrackerContactDetailField *
251 QTrackerContactDetail::field(const QString &name) const
252 {
253     foreach(const QTrackerContactDetailField &f, fields()) {
254         if (f.name() == name) {
255             return &f;
256         }
257     }
258
259     if (QContactDetail::FieldDetailUri == name) {
260         return detailUriField();
261     }
262
263     return 0;
264 }
265
266 const QTrackerContactDetailField *
267 QTrackerContactDetail::resourceIriField() const
268 {
269     foreach(const QTrackerContactDetailField &f, fields()) {
270         if (f.hasDetailUri()) {
271             return &f;
272         }
273     }
274
275     return 0;
276 }
277
278 const QTrackerContactDetailField *
279 QTrackerContactDetail::detailUriField() const
280 {
281     if (d->m_detailUriField.isNull()) {
282         // collect RDF properties which lead to the detail's URI
283         const QTrackerContactDetailField *const subject = resourceIriField();
284         PropertyInfoList::ConstIterator i = subject->propertyChain().constBegin();
285         PropertyInfoList::ConstIterator end = subject->propertyChain().constEnd();
286         PropertyInfoList uriPropertyChain;
287
288         if (subject->propertyChain().count() > 1) {
289             --end;
290         }
291
292         while (i != end) {
293             uriPropertyChain.append(*i++);
294         }
295
296         // synthesize the detail URI field
297         QScopedPointer<QTrackerContactDetailField> field
298                 (new QTrackerContactDetailField(QContactDetail::FieldDetailUri));
299
300         field->setPropertyChain(uriPropertyChain);
301         field->setDataType(QVariant::Url);
302
303         d->m_detailUriField.reset(field.take());
304     }
305
306     return d->m_detailUriField.data();
307 }
308
309 const QTrackerContactDetailField *
310 QTrackerContactDetail::subTypeField() const
311 {
312     foreach(const QTrackerContactDetailField &f, fields()) {
313         if (f.hasSubTypes()) {
314             return &f;
315         }
316     }
317
318     return 0;
319 }
320
321 void
322 QTrackerContactDetail::setDetailUriScheme(QTrackerContactSubject::Scheme scheme)
323 {
324     d->m_detailUriScheme = scheme;
325 }
326
327 QTrackerContactSubject::Scheme
328 QTrackerContactDetail::detailUriScheme() const
329 {
330     if (QTrackerContactSubject::None != d->m_detailUriScheme) {
331         return d->m_detailUriScheme;
332     }
333
334     return resourceIriScheme();
335 }
336
337 QTrackerContactSubject::Scheme
338 QTrackerContactDetail::resourceIriScheme() const
339 {
340     foreach(const QTrackerContactDetailField &f, fields()) {
341         PropertyInfoList::ConstIterator detailUriProperty = f.detailUriProperty();
342
343         if (detailUriProperty != f.propertyChain().constEnd()) {
344             return detailUriProperty->resourceIriScheme();
345         }
346     }
347
348     return QTrackerContactSubject::None;
349 }
350
351 bool
352 QTrackerContactDetail::hasDetailUri() const
353 {
354     foreach(const QTrackerContactDetailField &f, fields()) {
355         if (f.hasDetailUri()) {
356             return true;
357         }
358     }
359
360     return false;
361 }
362
363 QContactDetailDefinition
364 QTrackerContactDetail::describe() const
365 {
366     QContactDetailDefinition schema;
367
368     schema.setName(name());
369     schema.setUnique(isUnique());
370
371     if (hasContext()) {
372         static const QString contextHome = QContactDetail::ContextHome;
373         static const QString contextWork = QContactDetail::ContextWork;
374
375         QContactDetailFieldDefinition f;
376         f.setDataType(QVariant::StringList);
377         f.setAllowableValues(QVariantList() << contextHome << contextWork);
378         schema.insertField(QContactDetail::FieldContext, f);
379     }
380
381     foreach(const QTrackerContactDetailField &f, fields()) {
382         schema.insertField(f.name(), f.describe());
383     }
384
385     return schema;
386 }
387
388 const QTrackerContactDetail *
389 QTrackerContactDetail::findImplementation(const QTrackerContactDetailSchema &schema,
390                                           const QMap<QString, QContactDetail> &otherDetails,
391                                           const QContactDetail &actualDetail) const
392 {
393     const QTrackerContactDetail *const implementation =
394             d->findImplementation(schema, otherDetails, actualDetail);
395     return implementation ? implementation : this;
396 }
397
398 QList<const QTrackerContactDetail *>
399 QTrackerContactDetail::implementations(const QTrackerContactDetailSchema &schema) const
400 {
401     QList<const QTrackerContactDetail *> implementations = d->implementations(schema);
402
403     if (implementations.isEmpty()) {
404         implementations << this;
405     }
406
407     return implementations;
408 }