1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2015 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQml module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL21$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 or version 3 as published by the Free |
20 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and |
21 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the |
22 | ** following information to ensure the GNU Lesser General Public License |
23 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and |
24 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
25 | ** |
26 | ** As a special exception, The Qt Company gives you certain additional |
27 | ** rights. These rights are described in The Qt Company LGPL Exception |
28 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
29 | ** |
30 | ** $QT_END_LICENSE$ |
31 | ** |
32 | ****************************************************************************/ |
33 | |
34 | #include "qdeclarativecontactrelationshipmodel_p.h" |
35 | |
36 | #include <QtGui/qpixmap.h> |
37 | |
38 | #include <QtQml/qqmlinfo.h> |
39 | |
40 | #include <QtContacts/qcontactmanager.h> |
41 | #include <QtContacts/qcontactrequests.h> |
42 | |
43 | QTCONTACTS_USE_NAMESPACE |
44 | |
45 | QT_BEGIN_NAMESPACE |
46 | |
47 | /*! |
48 | \qmltype RelationshipModel |
49 | \instantiates QDeclarativeContactRelationshipModel |
50 | \brief The RelationshipModel provides a model of contact relationships from the contacts store. |
51 | |
52 | \ingroup qml-contacts-main |
53 | \inqmlmodule QtContacts |
54 | |
55 | This element is part of the \b{QtContacts} module. |
56 | |
57 | The contents of the model can be specified with \l participantId, \l role and \l relationshipType properties. |
58 | Whether the model is automatically updated when the store or filter changes, can be controlled |
59 | with \l RelationshipModel::autoUpdate property. |
60 | |
61 | There are two ways of accessing the relationship data: through model by using views and delegates, |
62 | or alternatively via \l relationships list property. |
63 | |
64 | At the moment only data role provided by the model is \c relationship (\l Relationship). |
65 | Through that one can access any data provided by the Relationship element. |
66 | |
67 | \sa Relationship, {QContactRelationship} |
68 | */ |
69 | |
70 | class QDeclarativeContactRelationshipModelPrivate |
71 | { |
72 | public: |
73 | QDeclarativeContactRelationshipModelPrivate() |
74 | : m_manager(0) |
75 | , m_participant(0) |
76 | , m_role(QDeclarativeContactRelationship::Either) |
77 | { |
78 | } |
79 | |
80 | ~QDeclarativeContactRelationshipModelPrivate() |
81 | { |
82 | delete m_manager; |
83 | } |
84 | |
85 | QContactManager *m_manager; |
86 | QDeclarativeContactRelationship m_relationshipTypeHolder; |
87 | QDeclarativeContact* m_participant; |
88 | QDeclarativeContactRelationship::RelationshipRole m_role; |
89 | QList<QContactRelationship> m_relationships; |
90 | QList<QDeclarativeContactRelationship *> m_declarativeRelationships; |
91 | }; |
92 | |
93 | QDeclarativeContactRelationshipModel::QDeclarativeContactRelationshipModel(QObject *parent) |
94 | : QAbstractListModel(parent) |
95 | , d(new QDeclarativeContactRelationshipModelPrivate) |
96 | { |
97 | QHash<int, QByteArray> roleNames; |
98 | roleNames = QAbstractItemModel::roleNames(); |
99 | roleNames.insert(akey: RelationshipRole, avalue: "relationship" ); |
100 | setRoleNames(roleNames); |
101 | connect(asender: this, SIGNAL(managerChanged()), SLOT(fetchAgain())); |
102 | connect(asender: this, SIGNAL(participantChanged()), SLOT(fetchAgain())); |
103 | connect(asender: this, SIGNAL(relationshipTypeChanged()), SLOT(fetchAgain())); |
104 | connect(asender: this, SIGNAL(roleChanged()), SLOT(fetchAgain())); |
105 | } |
106 | |
107 | QDeclarativeContactRelationshipModel::~QDeclarativeContactRelationshipModel() |
108 | { |
109 | delete d; |
110 | } |
111 | |
112 | /*! |
113 | \qmlproperty string RelationshipModel::manager |
114 | |
115 | This property holds the manager uri of the contact backend engine. |
116 | */ |
117 | QString QDeclarativeContactRelationshipModel::manager() const |
118 | { |
119 | if (d->m_manager) |
120 | return d->m_manager->managerName(); |
121 | return QString(); |
122 | } |
123 | |
124 | |
125 | /*! |
126 | \qmlproperty string RelationshipModel::error |
127 | |
128 | This property holds the latest error code returned by the contact manager. |
129 | |
130 | This property is read only. |
131 | */ |
132 | QString QDeclarativeContactRelationshipModel::error() const |
133 | { |
134 | switch (d->m_manager->error()) { |
135 | case QContactManager::DoesNotExistError: |
136 | return QStringLiteral("DoesNotExist" ); |
137 | case QContactManager::AlreadyExistsError: |
138 | return QStringLiteral("AlreadyExists" ); |
139 | case QContactManager::InvalidDetailError: |
140 | return QStringLiteral("InvalidDetail" ); |
141 | case QContactManager::InvalidRelationshipError: |
142 | return QStringLiteral("InvalidRelationship" ); |
143 | case QContactManager::LockedError: |
144 | return QStringLiteral("LockedError" ); |
145 | case QContactManager::DetailAccessError: |
146 | return QStringLiteral("DetailAccessError" ); |
147 | case QContactManager::PermissionsError: |
148 | return QStringLiteral("PermissionsError" ); |
149 | case QContactManager::OutOfMemoryError: |
150 | return QStringLiteral("OutOfMemory" ); |
151 | case QContactManager::NotSupportedError: |
152 | return QStringLiteral("NotSupported" ); |
153 | case QContactManager::BadArgumentError: |
154 | return QStringLiteral("BadArgument" ); |
155 | case QContactManager::UnspecifiedError: |
156 | return QStringLiteral("UnspecifiedError" ); |
157 | case QContactManager::VersionMismatchError: |
158 | return QStringLiteral("VersionMismatch" ); |
159 | case QContactManager::LimitReachedError: |
160 | return QStringLiteral("LimitReached" ); |
161 | case QContactManager::InvalidContactTypeError: |
162 | return QStringLiteral("InvalidContactType" ); |
163 | default: |
164 | break; |
165 | } |
166 | return QStringLiteral("NoError" ); |
167 | } |
168 | void QDeclarativeContactRelationshipModel::setManager(const QString& manager) |
169 | { |
170 | if (d->m_manager == 0 || manager != d->m_manager->managerName() ) { |
171 | d->m_manager = new QContactManager(manager,QMap<QString,QString>(), this); |
172 | connect(sender: d->m_manager,SIGNAL(relationshipsAdded(QList<QContactId>)), receiver: this, SLOT(fetchAgain())); |
173 | connect(sender: d->m_manager,SIGNAL(relationshipsRemoved(QList<QContactId>)), receiver: this, SLOT(fetchAgain())); |
174 | emit managerChanged(); |
175 | } |
176 | } |
177 | |
178 | |
179 | /*! |
180 | \qmlproperty int RelationshipModel::participantId |
181 | |
182 | This property holds the participant which the list of relationships returned by RelationshipModel should contain. |
183 | |
184 | \sa RelationshipFilter::relatedContactId |
185 | \sa RelationshipModel::role |
186 | */ |
187 | QDeclarativeContact* QDeclarativeContactRelationshipModel::participant() const |
188 | { |
189 | return d->m_participant; |
190 | } |
191 | void QDeclarativeContactRelationshipModel::setParticipant(QDeclarativeContact* participant) |
192 | { |
193 | if (d->m_participant != participant) { |
194 | d->m_participant = participant; |
195 | emit participantChanged(); |
196 | } |
197 | } |
198 | |
199 | /*! |
200 | \qmlproperty variant RelationshipModel::relationshipType |
201 | |
202 | This property holds the relationship type which the list of relationships returned by RelationshipModel should contain. |
203 | |
204 | \sa Relationship::type |
205 | */ |
206 | QVariant QDeclarativeContactRelationshipModel::relationshipType() const |
207 | { |
208 | return d->m_relationshipTypeHolder.relationshipType(); |
209 | } |
210 | void QDeclarativeContactRelationshipModel::setRelationshipType(const QVariant& type) |
211 | { |
212 | if (type != relationshipType()) { |
213 | d->m_relationshipTypeHolder.setRelationshipType(type); |
214 | emit relationshipTypeChanged(); |
215 | } |
216 | } |
217 | |
218 | /*! |
219 | \qmlproperty enumeration RelationshipModel::role |
220 | |
221 | This property holds the relationship role which the list of relationships returned by RelationshipModel should contain. |
222 | |
223 | \sa RelationshipFilter::relatedContactRole |
224 | */ |
225 | QDeclarativeContactRelationship::RelationshipRole QDeclarativeContactRelationshipModel::role() const |
226 | { |
227 | return d->m_role; |
228 | } |
229 | void QDeclarativeContactRelationshipModel::setRole(QDeclarativeContactRelationship::RelationshipRole role) |
230 | { |
231 | if (d->m_role != role) { |
232 | d->m_role = role; |
233 | emit roleChanged(); |
234 | } |
235 | } |
236 | |
237 | /*! |
238 | \qmlproperty bool RelationshipModel::autoUpdate |
239 | |
240 | This property indicates whether or not the relationship model should be updated automatically, default value is true. |
241 | */ |
242 | bool QDeclarativeContactRelationshipModel::autoUpdate() const |
243 | { |
244 | //TODO |
245 | return true; |
246 | } |
247 | void QDeclarativeContactRelationshipModel::setAutoUpdate(bool autoUpdate) |
248 | { |
249 | Q_UNUSED(autoUpdate); |
250 | //TODO |
251 | } |
252 | |
253 | /*! |
254 | \qmlproperty list<Relationship> RelationshipModel::relationships |
255 | |
256 | This property holds a list of relationships. |
257 | |
258 | \sa Relationship |
259 | */ |
260 | QQmlListProperty<QDeclarativeContactRelationship> QDeclarativeContactRelationshipModel::relationships() |
261 | { |
262 | return QQmlListProperty<QDeclarativeContactRelationship>(this, d->m_declarativeRelationships); |
263 | } |
264 | |
265 | int QDeclarativeContactRelationshipModel::rowCount(const QModelIndex &parent) const |
266 | { |
267 | Q_UNUSED(parent); |
268 | return d->m_declarativeRelationships.count(); |
269 | } |
270 | |
271 | QVariant QDeclarativeContactRelationshipModel::data(const QModelIndex &index, int role) const |
272 | { |
273 | QDeclarativeContactRelationship* dcr = d->m_declarativeRelationships.value(i: index.row()); |
274 | if (role == RelationshipRole) { |
275 | return QVariant::fromValue(value: dcr); |
276 | } else if (role == Qt::DisplayRole) { |
277 | return QString(QStringLiteral("%1 %2 %3" )).arg(a: dcr->relationship().first().toString()).arg(a: dcr->relationship().relationshipType()).arg(a: dcr->relationship().second().toString()); |
278 | } |
279 | return QVariant(); |
280 | } |
281 | |
282 | void QDeclarativeContactRelationshipModel::fetchAgain() |
283 | { |
284 | if (d->m_manager) { |
285 | QContactRelationshipFetchRequest* req = new QContactRelationshipFetchRequest(this); |
286 | req->setManager(d->m_manager); |
287 | if (d->m_participant) { |
288 | QContact contact (d->m_participant->contact()); |
289 | if (d->m_role == QDeclarativeContactRelationship::First || d->m_role == QDeclarativeContactRelationship::Either) |
290 | req->setFirst(contact.id()); |
291 | if (d->m_role == QDeclarativeContactRelationship::Second || d->m_role == QDeclarativeContactRelationship::Either) |
292 | req->setSecond(contact.id()); |
293 | req->setRelationshipType(d->m_relationshipTypeHolder.relationship().relationshipType()); |
294 | connect(sender: req,SIGNAL(stateChanged(QContactAbstractRequest::State)), receiver: this, SLOT(requestUpdated())); |
295 | req->start(); |
296 | } |
297 | } |
298 | } |
299 | |
300 | /*! |
301 | \qmlmethod RelationshipModel::addRelationship(relationship) |
302 | Addes the given \a relationship to the backend store. |
303 | */ |
304 | void QDeclarativeContactRelationshipModel::addRelationship(QDeclarativeContactRelationship* dcr) |
305 | { |
306 | if (dcr) { |
307 | QContactRelationship cr = dcr->relationship(); |
308 | QContactRelationshipSaveRequest* req = new QContactRelationshipSaveRequest(this); |
309 | req->setManager(d->m_manager); |
310 | req->setRelationship(cr); |
311 | connect(sender: req, SIGNAL(stateChanged(QContactAbstractRequest::State)), receiver: this, SLOT(relationshipsSaved())); |
312 | req->start(); |
313 | } |
314 | } |
315 | |
316 | /*! |
317 | \qmlmethod RelationshipModel::removeRelationship(relationship) |
318 | Removes the given \a relationship from the backend store. |
319 | */ |
320 | void QDeclarativeContactRelationshipModel::removeRelationship(QDeclarativeContactRelationship* dcr) |
321 | { |
322 | if (dcr) { |
323 | QContactRelationship cr = dcr->relationship(); |
324 | QContactRelationshipRemoveRequest* req = new QContactRelationshipRemoveRequest(this); |
325 | req->setManager(d->m_manager); |
326 | req->setRelationship(cr); |
327 | connect(sender: req,SIGNAL(stateChanged(QContactAbstractRequest::State)), receiver: this, SLOT(relationshipsRemoved())); |
328 | req->start(); |
329 | } |
330 | } |
331 | |
332 | void QDeclarativeContactRelationshipModel::requestUpdated() |
333 | { |
334 | QContactRelationshipFetchRequest* req = qobject_cast<QContactRelationshipFetchRequest*>(object: sender()); |
335 | Q_ASSERT(req); |
336 | if (req->isFinished() && req->error() == QContactManager::NoError) { |
337 | |
338 | QList<QContactRelationship> relationships = req->relationships(); |
339 | |
340 | reset(); |
341 | beginInsertRows(parent: QModelIndex(), first: 0, last: relationships.count()); |
342 | |
343 | foreach(QDeclarativeContactRelationship* dcr, d->m_declarativeRelationships) { |
344 | dcr->deleteLater(); |
345 | } |
346 | d->m_declarativeRelationships.clear(); |
347 | d->m_relationships.clear(); |
348 | |
349 | foreach (const QContactRelationship& cr, relationships) { |
350 | QDeclarativeContactRelationship* dcr = new QDeclarativeContactRelationship(this); |
351 | dcr->setRelationship(cr); |
352 | d->m_declarativeRelationships.append(t: dcr); |
353 | d->m_relationships.append(t: cr); |
354 | } |
355 | endInsertRows(); |
356 | req->deleteLater(); |
357 | emit relationshipsChanged(); |
358 | } |
359 | } |
360 | |
361 | void QDeclarativeContactRelationshipModel::relationshipsSaved() |
362 | { |
363 | QContactRelationshipSaveRequest* req = qobject_cast<QContactRelationshipSaveRequest*>(object: sender()); |
364 | Q_ASSERT(req); |
365 | if (req->isFinished()) { |
366 | QList<QContactRelationship> rs = req->relationships(); |
367 | QList<int> errorIds = req->errorMap().keys(); |
368 | |
369 | for( int i = 0; i < rs.count(); i++) { |
370 | if (!errorIds.contains(t: i)) { |
371 | //saved |
372 | QContactRelationship r = rs.at(i); |
373 | |
374 | if (!d->m_relationships.contains(t: r)) { |
375 | //new relationship saved |
376 | QDeclarativeContactRelationship* dcr = new QDeclarativeContactRelationship(this); |
377 | dcr->setRelationship(r); |
378 | beginInsertRows(parent: QModelIndex(), first: d->m_declarativeRelationships.count(), last: d->m_declarativeRelationships.count()); |
379 | d->m_declarativeRelationships.append(t: dcr); |
380 | d->m_relationships.append(t: r); |
381 | endInsertRows(); |
382 | } |
383 | } |
384 | } |
385 | req->deleteLater(); |
386 | } |
387 | } |
388 | |
389 | void QDeclarativeContactRelationshipModel::relationshipsRemoved() |
390 | { |
391 | QContactRelationshipRemoveRequest* req = qobject_cast<QContactRelationshipRemoveRequest*>(object: sender()); |
392 | Q_ASSERT(req); |
393 | if (req->isFinished()) { |
394 | QList<QContactRelationship> rs = req->relationships(); |
395 | QList<int> errorIds = req->errorMap().keys(); |
396 | |
397 | |
398 | for( int i = 0; i < rs.count(); i++) { |
399 | if (!errorIds.contains(t: i)) { |
400 | int row = 0; |
401 | QContactRelationship r = rs.at(i); |
402 | for (; row < d->m_relationships.count(); row++) { |
403 | if (d->m_relationships.at(i: row) == r) |
404 | break; |
405 | } |
406 | if (row < d->m_relationships.count()) { |
407 | beginRemoveRows(parent: QModelIndex(), first: row, last: row); |
408 | d->m_declarativeRelationships.removeAt(i: row); |
409 | d->m_relationships.removeAt(i: row); |
410 | endRemoveRows(); |
411 | } else { |
412 | //impossible? |
413 | qmlInfo(me: this) << tr(s: "this relationship '" ) << row << tr(s: "' was already removed!" ); |
414 | } |
415 | } |
416 | } |
417 | req->deleteLater(); |
418 | } |
419 | } |
420 | |
421 | #include "moc_qdeclarativecontactrelationshipmodel_p.cpp" |
422 | |
423 | QT_END_NAMESPACE |
424 | |