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 QtOrganizer 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 "qorganizeritemchangeset.h" |
35 | #include "qorganizeritemchangeset_p.h" |
36 | |
37 | #include "qorganizermanagerengine.h" |
38 | |
39 | QT_BEGIN_NAMESPACE_ORGANIZER |
40 | |
41 | /*! |
42 | \class QOrganizerItemChangeSet |
43 | \brief The QOrganizerItemChangeSet class provides a simple API to simplify the emission of |
44 | state-change signals for items from QOrganizerManagerEngine implementations. |
45 | \inmodule QtOrganizer |
46 | \ingroup organizer-backends |
47 | |
48 | This class should only be used by backend developers. |
49 | */ |
50 | |
51 | /*! |
52 | \typedef QOrganizerItemChangeSet::ItemChangeList |
53 | |
54 | This type describes a set of item changes, where each item whose |
55 | ID is listed in \c second is subject to a change that affects some or |
56 | all of the detail types listed in \c first. |
57 | |
58 | Note that change grouping is of items affected by equivalent changes, |
59 | rather than of multiple changes affecting the same item. |
60 | |
61 | \code |
62 | foreach (QOrganizerItemChangeSet::ItemChangeList changeList, set.changedItems()) { |
63 | if (changeList.first.contains(QOrganizerItemDetail::TypeDescription)) { |
64 | qDebug() << "Item IDs with description changes:" << changeList.second; |
65 | } |
66 | } |
67 | \endcode |
68 | |
69 | \sa QOrganizerItemChangeSet::changedItems() |
70 | */ |
71 | |
72 | /*! |
73 | Constructs a new change set. |
74 | */ |
75 | QOrganizerItemChangeSet::QOrganizerItemChangeSet() |
76 | : d(new QOrganizerItemChangeSetData) |
77 | { |
78 | } |
79 | |
80 | /*! |
81 | Constructs a copy of the \a other change set. |
82 | */ |
83 | QOrganizerItemChangeSet::QOrganizerItemChangeSet(const QOrganizerItemChangeSet &other) |
84 | : d(other.d) |
85 | { |
86 | } |
87 | |
88 | /*! |
89 | Frees the memory used by this change set. |
90 | */ |
91 | QOrganizerItemChangeSet::~QOrganizerItemChangeSet() |
92 | { |
93 | } |
94 | |
95 | /*! |
96 | Assigns this change set to be equal to \a other. |
97 | */ |
98 | QOrganizerItemChangeSet &QOrganizerItemChangeSet::operator=(const QOrganizerItemChangeSet &other) |
99 | { |
100 | d = other.d; |
101 | return *this; |
102 | } |
103 | |
104 | /*! |
105 | Sets the data changed flag to \a dataChanged. |
106 | |
107 | If this is set to true prior to calling emitSignals(), only the QOrganizerManagerEngine::dataChanged() |
108 | signal will be emitted; otherwise, the appropriate finer-grained signals will be emitted. |
109 | */ |
110 | void QOrganizerItemChangeSet::setDataChanged(bool dataChanged) |
111 | { |
112 | d->m_dataChanged = dataChanged; |
113 | } |
114 | |
115 | /*! |
116 | Returns the value of the data changed flag. |
117 | */ |
118 | bool QOrganizerItemChangeSet::dataChanged() const |
119 | { |
120 | return d->m_dataChanged; |
121 | } |
122 | |
123 | /*! |
124 | Returns the set of IDs of organizer items which have been added to the database. |
125 | */ |
126 | QSet<QOrganizerItemId> QOrganizerItemChangeSet::addedItems() const |
127 | { |
128 | return d->m_addedItems; |
129 | } |
130 | |
131 | /*! |
132 | Inserts the given \a itemId into the set of ids of organizer items which have been added to the |
133 | database. |
134 | */ |
135 | void QOrganizerItemChangeSet::insertAddedItem(const QOrganizerItemId &itemId) |
136 | { |
137 | d->m_addedItems.insert(value: itemId); |
138 | d->m_modifiedItems.append(t: QPair<QOrganizerItemId, QOrganizerManager::Operation>(itemId, QOrganizerManager::Add)); |
139 | } |
140 | |
141 | /*! |
142 | Inserts each of the given \a itemIds into the set of IDs of organizer items which have been added |
143 | to the database. |
144 | */ |
145 | void QOrganizerItemChangeSet::insertAddedItems(const QList<QOrganizerItemId> &itemIds) |
146 | { |
147 | foreach (const QOrganizerItemId &id, itemIds) { |
148 | d->m_addedItems.insert(value: id); |
149 | d->m_modifiedItems.append(t: QPair<QOrganizerItemId, QOrganizerManager::Operation>(id, QOrganizerManager::Add)); |
150 | } |
151 | } |
152 | |
153 | /*! |
154 | Clears the set of IDs of organizer items which have been added to the database. |
155 | */ |
156 | void QOrganizerItemChangeSet::clearAddedItems() |
157 | { |
158 | d->m_addedItems.clear(); |
159 | } |
160 | |
161 | /*! |
162 | Returns a list of ItemChangeLists describing which items have been |
163 | changed in the database, and what details of those items have changed. |
164 | |
165 | */ |
166 | QList<QOrganizerItemChangeSet::ItemChangeList> QOrganizerItemChangeSet::changedItems() const |
167 | { |
168 | return d->m_changedItems; |
169 | } |
170 | |
171 | /*! |
172 | Inserts the given item ID \a itemId into the set of IDs of organizer items which have been changed in |
173 | the database, with the changes described by \a typesChanged. |
174 | */ |
175 | void QOrganizerItemChangeSet::insertChangedItem(const QOrganizerItemId &itemId, const QList<QOrganizerItemDetail::DetailType> &typesChanged) |
176 | { |
177 | insertChangedItems(itemIds: QList<QOrganizerItemId>() << itemId, typesChanged); |
178 | } |
179 | |
180 | /*! |
181 | Inserts each of the itemIDs listed in \a itemIds into the set of IDs of organizer items which have been |
182 | changed in the database, with the changes described by \a typesChanged. |
183 | */ |
184 | void QOrganizerItemChangeSet::insertChangedItems(const QList<QOrganizerItemId> &changedItemIds, const QList<QOrganizerItemDetail::DetailType> &typesChanged) |
185 | { |
186 | // Sort and de-duplicate the IDs and change types |
187 | QList<QOrganizerItemId> itemIds(changedItemIds); |
188 | std::sort(first: itemIds.begin(), last: itemIds.end()); |
189 | { |
190 | QList<QOrganizerItemId>::iterator iit = std::unique(first: itemIds.begin(), last: itemIds.end()); |
191 | while (iit != itemIds.end()) { |
192 | iit = itemIds.erase(it: iit); |
193 | } |
194 | } |
195 | |
196 | QList<QOrganizerItemDetail::DetailType> changeSet(typesChanged); |
197 | std::sort(first: changeSet.begin(), last: changeSet.end()); |
198 | { |
199 | QList<QOrganizerItemDetail::DetailType>::iterator cit = std::unique(first: changeSet.begin(), last: changeSet.end()); |
200 | while (cit != changeSet.end()) { |
201 | cit = changeSet.erase(it: cit); |
202 | } |
203 | } |
204 | |
205 | // Add these items to the list of items that match this change set |
206 | QList<ItemChangeList>::iterator it = d->m_changedItems.begin(), end = d->m_changedItems.end(); |
207 | for ( ; it != end; ++it) { |
208 | if ((*it).first == changeSet) { |
209 | break; |
210 | } |
211 | } |
212 | if (it == end) { |
213 | // Add a list for this set of changes |
214 | d->m_changedItems.append(t: qMakePair(x: changeSet, y: itemIds)); |
215 | } else { |
216 | QList<QOrganizerItemId> &changedIds((*it).second); |
217 | QList<QOrganizerItemId>::iterator iit = changedIds.begin(); |
218 | |
219 | foreach (const QOrganizerItemId &itemId, itemIds) { |
220 | // Add this ID if not yet present |
221 | iit = std::lower_bound(first: iit, last: changedIds.end(), val: itemId); |
222 | if (iit == changedIds.end() || *iit != itemId) { |
223 | iit = changedIds.insert(before: iit, t: itemId); |
224 | } |
225 | } |
226 | } |
227 | |
228 | // These items are all now modified |
229 | foreach (const QOrganizerItemId &id, itemIds) |
230 | d->m_modifiedItems.append(t: QPair<QOrganizerItemId, QOrganizerManager::Operation>(id, QOrganizerManager::Change)); |
231 | } |
232 | |
233 | /*! |
234 | Clears the set of IDs of organizer items which have been changed in the database. |
235 | */ |
236 | void QOrganizerItemChangeSet::clearChangedItems() |
237 | { |
238 | d->m_changedItems.clear(); |
239 | } |
240 | |
241 | /*! |
242 | Returns the set of IDs of organizer items which have been removed from the database. |
243 | */ |
244 | QSet<QOrganizerItemId> QOrganizerItemChangeSet::removedItems() const |
245 | { |
246 | return d->m_removedItems; |
247 | } |
248 | |
249 | /*! |
250 | Inserts the given \a itemId into the set of IDs of organizer items which have been removed from |
251 | the database. |
252 | */ |
253 | void QOrganizerItemChangeSet::insertRemovedItem(const QOrganizerItemId &itemId) |
254 | { |
255 | d->m_removedItems.insert(value: itemId); |
256 | d->m_modifiedItems.append(t: QPair<QOrganizerItemId, QOrganizerManager::Operation>(itemId, QOrganizerManager::Remove)); |
257 | } |
258 | |
259 | /*! |
260 | Inserts each of the given \a itemIds into the set of IDs of organizer items which have been |
261 | removed from the database. |
262 | */ |
263 | void QOrganizerItemChangeSet::insertRemovedItems(const QList<QOrganizerItemId> &itemIds) |
264 | { |
265 | foreach (const QOrganizerItemId &id, itemIds) { |
266 | d->m_removedItems.insert(value: id); |
267 | d->m_modifiedItems.append(t: QPair<QOrganizerItemId, QOrganizerManager::Operation>(id, QOrganizerManager::Remove)); |
268 | } |
269 | } |
270 | |
271 | /*! |
272 | Clears the set of IDs of organizer items which have been removed from the database. |
273 | */ |
274 | void QOrganizerItemChangeSet::clearRemovedItems() |
275 | { |
276 | d->m_removedItems.clear(); |
277 | } |
278 | |
279 | /*! |
280 | Returns the list of ids of organizer items which have been added, changed or removed from |
281 | the database. The list includes information about which database operation was done. The ids and |
282 | operations are ordered so that the first operation is first in the list. |
283 | */ |
284 | QList<QPair<QOrganizerItemId, QOrganizerManager::Operation> > QOrganizerItemChangeSet::modifiedItems() const |
285 | { |
286 | return d->m_modifiedItems; |
287 | } |
288 | |
289 | /*! |
290 | Clears the list of ids of organizer items which have been added, changed or removed from the database |
291 | */ |
292 | void QOrganizerItemChangeSet::clearModifiedItems() |
293 | { |
294 | d->m_modifiedItems.clear(); |
295 | } |
296 | |
297 | /*! |
298 | Clears all flags and sets of IDs in this change set. |
299 | */ |
300 | void QOrganizerItemChangeSet::clearAll() |
301 | { |
302 | d->m_dataChanged = false; |
303 | d->m_addedItems.clear(); |
304 | d->m_changedItems.clear(); |
305 | d->m_removedItems.clear(); |
306 | d->m_modifiedItems.clear(); |
307 | } |
308 | |
309 | /*! |
310 | Emits the appropriate signals from the given \a engine given the state of the change set. Note |
311 | that the flags and sets of IDs are not cleared after signals are emitted. |
312 | */ |
313 | void QOrganizerItemChangeSet::emitSignals(QOrganizerManagerEngine *engine) const |
314 | { |
315 | if (!engine) |
316 | return; |
317 | |
318 | if (d->m_dataChanged) { |
319 | emit engine->dataChanged(); |
320 | } else { |
321 | if (!d->m_addedItems.isEmpty()) |
322 | emit engine->itemsAdded(itemIds: d->m_addedItems.toList()); |
323 | if (!d->m_changedItems.isEmpty()) { |
324 | QList<ItemChangeList>::const_iterator it = d->m_changedItems.constBegin(), end = d->m_changedItems.constEnd(); |
325 | for ( ; it != end; ++it) |
326 | emit engine->itemsChanged(itemIds: (*it).second, typesChanged: (*it).first); |
327 | } |
328 | if (!d->m_removedItems.isEmpty()) |
329 | emit engine->itemsRemoved(itemIds: d->m_removedItems.toList()); |
330 | if (!d->m_modifiedItems.isEmpty()) |
331 | emit engine->itemsModified(itemIds: d->m_modifiedItems); |
332 | } |
333 | } |
334 | |
335 | QT_END_NAMESPACE_ORGANIZER |
336 | |