| 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 |  |