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 "qorganizerskeleton_p.h" |
35 | |
36 | #ifndef QT_NO_DEBUG_STREAM |
37 | #include <QtCore/qdebug.h> |
38 | #endif |
39 | |
40 | QT_BEGIN_NAMESPACE_ORGANIZER |
41 | |
42 | QOrganizerManagerEngine* QOrganizerItemSkeletonFactory::engine(const QMap<QString, QString>& parameters, QOrganizerManager::Error* error) |
43 | { |
44 | Q_UNUSED(parameters); |
45 | Q_UNUSED(error); |
46 | |
47 | /* TODO - if you understand any specific parameters. save them in the engine so that engine::managerParameters can return them */ |
48 | |
49 | QOrganizerItemSkeletonEngine* ret = new QOrganizerItemSkeletonEngine(); // manager takes ownership and will clean up. |
50 | return ret; |
51 | } |
52 | |
53 | QString QOrganizerItemSkeletonFactory::managerName() const |
54 | { |
55 | /* TODO - put your engine name here */ |
56 | return QStringLiteral("skeleton" ); |
57 | } |
58 | |
59 | |
60 | QOrganizerItemSkeletonEngine::~QOrganizerItemSkeletonEngine() |
61 | { |
62 | /* TODO clean up your stuff. Perhaps a QScopedPointer or QSharedDataPointer would be in order */ |
63 | } |
64 | |
65 | QString QOrganizerItemSkeletonEngine::managerName() const |
66 | { |
67 | /* TODO - put your engine name here */ |
68 | return QStringLiteral("skeleton" ); |
69 | } |
70 | |
71 | QMap<QString, QString> QOrganizerItemSkeletonEngine::managerParameters() const |
72 | { |
73 | /* TODO - in case you have any actual parameters that are relevant that you saved in the factory method, return them here */ |
74 | return QMap<QString, QString>(); |
75 | } |
76 | |
77 | QList<QOrganizerItem> QOrganizerItemSkeletonEngine::itemOccurrences(const QOrganizerItem &parentItem, |
78 | const QDateTime &startDateTime, |
79 | const QDateTime &endDateTime, int maxCount, |
80 | const QOrganizerItemFetchHint &fetchHint, |
81 | QOrganizerManager::Error *error) |
82 | { |
83 | /* |
84 | TODO |
85 | |
86 | This function should create a list of occurrences that occur in the time period from the supplied item, |
87 | generated from the parent item. |
88 | |
89 | The periodStart should always be valid, and either the periodEnd or the maxCount will be valid (if periodEnd is |
90 | valid, use that. Otherwise use the count). It's permissible to limit the number of items returned... |
91 | |
92 | Basically, if the parent item is an Event, a list of EventOccurrences should be returned. Similarly for |
93 | Todo/TodoOccurrence. |
94 | |
95 | If there are no instances, return an empty list. |
96 | |
97 | The returned items should have a QOrganizerItemParent detail that points to the parentItem and the |
98 | original instance that the event would have occurred on (e.g. with an exception). |
99 | |
100 | They should not have recurrence information details in them. |
101 | |
102 | We might change the signature to split up the periodStart + periodEnd / periodStart + maxCount cases. |
103 | */ |
104 | |
105 | return QOrganizerManagerEngine::itemOccurrences(parentItem, startDateTime, endDateTime, maxCount, fetchHint, error); |
106 | } |
107 | |
108 | QList<QOrganizerItem> QOrganizerItemSkeletonEngine::itemsForExport(const QDateTime &startDateTime, |
109 | const QDateTime &endDateTime, |
110 | const QOrganizerItemFilter &filter, |
111 | const QList<QOrganizerItemSortOrder> &sortOrders, |
112 | const QOrganizerItemFetchHint &fetchHint, |
113 | QOrganizerManager::Error *error) |
114 | { |
115 | return QOrganizerManagerEngine::itemsForExport(startDateTime, endDateTime, filter, sortOrders, fetchHint, error); |
116 | } |
117 | |
118 | QList<QOrganizerItemId> QOrganizerItemSkeletonEngine::itemIds(const QOrganizerItemFilter &filter, |
119 | const QDateTime &startDateTime, |
120 | const QDateTime &endDateTime, |
121 | const QList<QOrganizerItemSortOrder> &sortOrders, |
122 | QOrganizerManager::Error *error) |
123 | { |
124 | /* |
125 | TODO |
126 | |
127 | Given the supplied filter and sort order, fetch the list of items [not instances] that correspond, and return their ids. |
128 | |
129 | If you don't support the filter or sort orders, you can fetch a partially (or un-) filtered list and ask the helper |
130 | functions to filter and sort it for you. |
131 | |
132 | If you do have to fetch, consider setting a fetch hint that restricts the information to that needed for filtering/sorting. |
133 | */ |
134 | |
135 | *error = QOrganizerManager::NotSupportedError; // TODO <- remove this |
136 | |
137 | QList<QOrganizerItem> partiallyFilteredItems; // = ..., your code here.. [TODO] |
138 | QList<QOrganizerItem> ret; |
139 | |
140 | foreach(const QOrganizerItem& item, partiallyFilteredItems) { |
141 | if (QOrganizerManagerEngine::isItemBetweenDates(item, startPeriod: startDateTime, endPeriod: endDateTime) && QOrganizerManagerEngine::testFilter(filter, item)) { |
142 | QOrganizerManagerEngine::addSorted(sorted: &ret, toAdd: item, sortOrders); |
143 | } |
144 | } |
145 | |
146 | return QOrganizerManager::extractIds(items: ret); |
147 | } |
148 | |
149 | QList<QOrganizerItem> QOrganizerItemSkeletonEngine::items(const QOrganizerItemFilter &filter, const QDateTime &startDateTime, |
150 | const QDateTime &endDateTime, int maxCount, |
151 | const QList<QOrganizerItemSortOrder> &sortOrders, |
152 | const QOrganizerItemFetchHint &fetchHint, QOrganizerManager::Error *error) |
153 | { |
154 | /* |
155 | TODO |
156 | |
157 | Given the supplied filter and sort order, fetch the list of items [not instances] that correspond, and return them. |
158 | |
159 | If you don't support the filter or sort orders, you can fetch a partially (or un-) filtered list and ask the helper |
160 | functions to filter and sort it for you. |
161 | |
162 | The fetch hint suggests how much of the item to fetch. You can ignore the fetch hint and fetch everything (but you must |
163 | fetch at least what is mentioned in the fetch hint). |
164 | */ |
165 | |
166 | Q_UNUSED(startDateTime) |
167 | Q_UNUSED(endDateTime) |
168 | Q_UNUSED(maxCount) |
169 | Q_UNUSED(fetchHint) |
170 | |
171 | *error = QOrganizerManager::NotSupportedError; // TODO <- remove this |
172 | |
173 | QList<QOrganizerItem> partiallyFilteredItems; // = ..., your code here.. [TODO] |
174 | QList<QOrganizerItem> ret; |
175 | |
176 | foreach(const QOrganizerItem& item, partiallyFilteredItems) { |
177 | if (QOrganizerManagerEngine::isItemBetweenDates(item, startPeriod: startDateTime, endPeriod: endDateTime) && QOrganizerManagerEngine::testFilter(filter, item)) { |
178 | QOrganizerManagerEngine::addSorted(sorted: &ret, toAdd: item, sortOrders); |
179 | } |
180 | } |
181 | |
182 | /* An alternative formulation, depending on how your engine is implemented is just: |
183 | |
184 | foreach(const QOrganizerItemId& id, itemIds(filter, sortOrders, error)) { |
185 | ret.append(item(id, fetchHint, error); |
186 | } |
187 | */ |
188 | |
189 | return ret; |
190 | } |
191 | |
192 | QList<QOrganizerItem> QOrganizerItemSkeletonEngine::items(const QList<QOrganizerItemId> &itemIds, const QOrganizerItemFetchHint &fetchHint, |
193 | QMap<int, QOrganizerManager::Error> *errorMap, QOrganizerManager::Error* error) |
194 | { |
195 | /* |
196 | TODO |
197 | |
198 | Fetch a single item by id. |
199 | |
200 | The fetch hint suggests how much of the item to fetch. You can ignore the fetch hint and fetch everything (but you must |
201 | fetch at least what is mentioned in the fetch hint). |
202 | |
203 | */ |
204 | return QOrganizerManagerEngine::items(itemIds, fetchHint, errorMap, error); |
205 | } |
206 | |
207 | bool QOrganizerItemSkeletonEngine::saveItems(QList<QOrganizerItem> *items, const QList<QOrganizerItemDetail::DetailType> &detailMask, |
208 | QMap<int, QOrganizerManager::Error>* errorMap, QOrganizerManager::Error* error) |
209 | { |
210 | /* |
211 | TODO |
212 | |
213 | Save a list of items into the collection specified in each (or their current collection |
214 | if no collection is specified and they already exist, or the default collection |
215 | if no collection is specified and they do not exist). |
216 | |
217 | For each item, convert it to your type, assign an item id, and update the |
218 | QOrganizerItem's ID (in the list above - e.g. *items[idx] = updated item). |
219 | Then, examine the collection id specified in each item and save the item in that collection. |
220 | |
221 | If you encounter an error (e.g. converting to type, or saving), insert an entry into |
222 | the map above at the corresponding index (e.g. errorMap->insert(idx, QOIM::InvalidDetailError). |
223 | You should set the "error" variable as well (first, last, most serious error etc). |
224 | |
225 | The item passed in should be validated according to the schema. |
226 | */ |
227 | return QOrganizerManagerEngine::saveItems(items, detailMask, errorMap, error); |
228 | } |
229 | |
230 | bool QOrganizerItemSkeletonEngine::removeItems(const QList<QOrganizerItemId> &itemIds, QMap<int, QOrganizerManager::Error> *errorMap, |
231 | QOrganizerManager::Error *error) |
232 | { |
233 | /* |
234 | TODO |
235 | |
236 | Remove a list of items, given by their id. |
237 | |
238 | If you encounter an error, insert an error into the appropriate place in the error map, |
239 | and update the error variable as well. |
240 | |
241 | DoesNotExistError should be used if the id refers to a non existent item. |
242 | */ |
243 | return QOrganizerManagerEngine::removeItems(itemIds, errorMap, error); |
244 | } |
245 | |
246 | QOrganizerCollectionId QOrganizerItemSkeletonEngine::defaultCollectionId() const |
247 | { |
248 | /* |
249 | TODO |
250 | |
251 | This allows clients to determine which collection an item will be saved, |
252 | if the item is saved via saveItems() without specifying a collection id |
253 | of a collection in which to save the item, via item->setCollectionId(). |
254 | |
255 | There is always at least one collection in a manager, and all items are |
256 | saved in exactly one collection. |
257 | */ |
258 | return QOrganizerManagerEngine::defaultCollectionId(); |
259 | } |
260 | |
261 | QOrganizerCollection QOrganizerItemSkeletonEngine::collection(const QOrganizerCollectionId& collectionId, QOrganizerManager::Error* error) |
262 | { |
263 | /* |
264 | TODO |
265 | |
266 | This allows clients to retrieve a collection by (manager) id. |
267 | Prior to saving items, clients will set which collection the item will/should |
268 | be saved by calling item->setCollectionId(). |
269 | */ |
270 | return QOrganizerManagerEngine::collection(collectionId, error); |
271 | } |
272 | |
273 | QList<QOrganizerCollection> QOrganizerItemSkeletonEngine::collections(QOrganizerManager::Error* error) |
274 | { |
275 | /* |
276 | TODO |
277 | |
278 | This allows clients to retrieve a list of all of the collections currently |
279 | in this manager. Some backends will have a prepopulated list of valid |
280 | collections, others will not. A collection can have properties |
281 | like colour, description, perhaps a priority, etc etc. |
282 | */ |
283 | return QOrganizerManagerEngine::collections(error); |
284 | } |
285 | |
286 | bool QOrganizerItemSkeletonEngine::saveCollection(QOrganizerCollection* collection, QOrganizerManager::Error* error) |
287 | { |
288 | /* |
289 | TODO |
290 | |
291 | This allows clients to create or update collections if supported by the |
292 | backend. |
293 | */ |
294 | return QOrganizerManagerEngine::saveCollection(collection, error); |
295 | } |
296 | |
297 | bool QOrganizerItemSkeletonEngine::removeCollection(const QOrganizerCollectionId& collectionId, QOrganizerManager::Error* error) |
298 | { |
299 | /* |
300 | TODO |
301 | |
302 | This allows clients to remove collections if supported by the backend. |
303 | |
304 | When a collection is removed, all items in the collection are removed. |
305 | That is, they are _not_ transferred to another collection. |
306 | |
307 | If the user attempts to remove the collection which is the default collection, |
308 | the backend may decide whether to fail (with a permissions error) or to |
309 | succeed and arbitrarily choose another collection to be the default collection. |
310 | */ |
311 | return QOrganizerManagerEngine::removeCollection(collectionId, error); |
312 | } |
313 | |
314 | bool QOrganizerItemSkeletonEngine::startRequest(QOrganizerAbstractRequest* req) |
315 | { |
316 | /* |
317 | TODO |
318 | |
319 | This is the entry point to the async API. The request object describes the |
320 | type of request (switch on req->type()). Req will not be null when called |
321 | by the framework. |
322 | |
323 | Generally, you can queue the request and process them at some later time |
324 | (probably in another thread). |
325 | |
326 | Once you start a request, call the updateRequestState and/or the |
327 | specific updateXXXXXRequest functions to mark it in the active state. |
328 | |
329 | If your engine is particularly fast, or the operation involves only in |
330 | memory data, you can process and complete the request here. That is |
331 | probably not the case, though. |
332 | |
333 | Note that when the client is threaded, and the request might live on a |
334 | different thread, you might need to be careful with locking. In particular, |
335 | the request might be deleted while you are still working on it. In this case, |
336 | your requestDestroyed function will be called while the request is still valid, |
337 | and you should block in that function until your worker thread (etc) has been |
338 | notified not to touch that request any more. |
339 | |
340 | We plan to provide some boiler plate code that will allow you to: |
341 | |
342 | 1) implement the sync functions, and have the async versions call the sync |
343 | in another thread |
344 | |
345 | 2) or implement the async versions of the function, and have the sync versions |
346 | call the async versions. |
347 | |
348 | It's not ready yet, though. |
349 | |
350 | Return true if the request can be started, false otherwise. You can set an error |
351 | in the request if you like. |
352 | */ |
353 | return QOrganizerManagerEngine::startRequest(request: req); |
354 | } |
355 | |
356 | bool QOrganizerItemSkeletonEngine::cancelRequest(QOrganizerAbstractRequest* req) |
357 | { |
358 | /* |
359 | TODO |
360 | |
361 | Cancel an in progress async request. If not possible, return false from here. |
362 | */ |
363 | return QOrganizerManagerEngine::cancelRequest(request: req); |
364 | } |
365 | |
366 | bool QOrganizerItemSkeletonEngine::waitForRequestFinished(QOrganizerAbstractRequest* req, int msecs) |
367 | { |
368 | /* |
369 | TODO |
370 | |
371 | Wait for a request to complete (up to a max of msecs milliseconds). |
372 | |
373 | Return true if the request is finished (including if it was already). False otherwise. |
374 | |
375 | You should really implement this function, if nothing else than as a delay, since clients |
376 | may call this in a loop. |
377 | |
378 | It's best to avoid processing events, if you can, or at least only process non-UI events. |
379 | */ |
380 | return QOrganizerManagerEngine::waitForRequestFinished(request: req, msecs); |
381 | } |
382 | |
383 | void QOrganizerItemSkeletonEngine::requestDestroyed(QOrganizerAbstractRequest* req) |
384 | { |
385 | /* |
386 | TODO |
387 | |
388 | This is called when a request is being deleted. It lets you know: |
389 | |
390 | 1) the client doesn't care about the request any more. You can still complete it if |
391 | you feel like it. |
392 | 2) you can't reliably access any properties of the request pointer any more. The pointer will |
393 | be invalid once this function returns. |
394 | |
395 | This means that if you have a worker thread, you need to let that thread know that the |
396 | request object is not valid and block until that thread acknowledges it. One way to do this |
397 | is to have a QSet<QOIAR*> (or QMap<QOIAR, MyCustomRequestState>) that tracks active requests, and |
398 | insert into that set in startRequest, and remove in requestDestroyed (or when it finishes or is |
399 | cancelled). Protect that set/map with a mutex, and make sure you take the mutex in the worker |
400 | thread before calling any of the QOIAR::updateXXXXXXRequest functions. And be careful of lock |
401 | ordering problems :D |
402 | |
403 | */ |
404 | return QOrganizerManagerEngine::requestDestroyed(request: req); |
405 | } |
406 | |
407 | QList<QOrganizerItemFilter::FilterType> QOrganizerItemSkeletonEngine::supportedFilters() const |
408 | { |
409 | // TODO if you engine can natively support the filter, return true. Otherwise you should emulate support in the item{Ids} functions. |
410 | return QList<QOrganizerItemFilter::FilterType>(); |
411 | } |
412 | |
413 | QList<QOrganizerItemDetail::DetailType> QOrganizerItemSkeletonEngine::supportedItemDetails(QOrganizerItemType::ItemType itemType) const |
414 | { |
415 | // TODO - return which [predefined] details this engine supports for this item type |
416 | Q_UNUSED(itemType) |
417 | |
418 | return QList<QOrganizerItemDetail::DetailType>(); |
419 | } |
420 | |
421 | QList<QOrganizerItemType::ItemType> QOrganizerItemSkeletonEngine::supportedItemTypes() const |
422 | { |
423 | // TODO - return which [predefined] types this engine supports |
424 | QList<QOrganizerItemType::ItemType> ret; |
425 | |
426 | ret << QOrganizerItemType::TypeEvent; |
427 | ret << QOrganizerItemType::TypeEventOccurrence; |
428 | ret << QOrganizerItemType::TypeJournal; |
429 | ret << QOrganizerItemType::TypeNote; |
430 | ret << QOrganizerItemType::TypeTodo; |
431 | ret << QOrganizerItemType::TypeTodoOccurrence; |
432 | |
433 | return ret; |
434 | } |
435 | |
436 | #include "moc_qorganizerskeleton_p.cpp" |
437 | |
438 | QT_END_NAMESPACE_ORGANIZER |
439 | |