1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtOrganizer module of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
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 Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
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 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include <qorganizeritem.h>
43
#include <private/qorganizeritem_p.h>
44
#include <private/qorganizeritemdetail_p.h>
45
#include <qorganizeritemdetails.h>
48
#include <qdatastream.h>
50
QT_BEGIN_NAMESPACE_ORGANIZER
53
\macro Q_DECLARE_CUSTOM_ORGANIZER_ITEM
54
\relates QOrganizerItem
56
Macro for simplifying declaring convenience leaf classes for QOrganizerItem.
58
The first argument is the name of the class, and the second argument is the
64
\brief The QOrganizerItem class is the base class of an event, todo, note, or journal entry.
66
\ingroup organizer-main
68
A QOrganizerItem object has an id and a collection of details (like a start date and location), as
69
well as a collection id which identifies which QOrganizerCollection the item is part of in a manager.
70
Each detail (which can have multiple fields) is stored in an appropriate subclass of QOrganizerItemDetail,
71
and the QOrganizerItem allows retrieving these details in various ways. QOrganizerItemExtendedDetail is
72
supposed to be used to store user specific details that are not pre-defined in the detal leaf classes.
74
Most clients will want to use the convenient subclasses of QOrganizerItem (i.e., QOrganizerEvent
75
(and QOrganizerEventOccurence), QOrganizerTodo (and QOrganizerTodoOccurence), QOrganizerJournal and
76
QOrganizerNote) instead of manipulating instances of QOrganizerItem directly.
78
A QOrganizerItem instance represents the in-memory version of an organizer item.
79
It is possible for the contents of a QOrganizerItem to change independently of the contents
80
that are stored persistently in a QOrganizerManager. A QOrganizerItem has an id associated
81
with it when it is first retrieved from a QOrganizerManager, or after it has been first saved,
82
and this allows clients to track changes using the signals in QOrganizerManager. When saved
83
in a manager, every item is placed into a QOrganizerCollection in that manager, according
84
to the collection id set in the item prior to save (or the default collection if no
85
collection id was set in the item).
87
Different QOrganizerManagers may require an item to have certain details saved in it before
88
it can be stored in that manager. By default, every item must have a QOrganizerItemType
89
detail which identifies the type of the item. Different subclasses of QOrganizerItem
90
(i.e., QOrganizerEvent (and QOrganizerEventOccurence), QOrganizerTodo (and QOrganizerTodoOccurence),
91
QOrganizerJournal and QOrganizerNote) may have other mandatory details, depending on the manager.
93
\sa QOrganizerManager, QOrganizerItemDetail
97
\fn QOrganizerItem::operator!=(const QOrganizerItem &other) const
99
Returns true if this organizer item's id or details are different to those of the \a other organizer item.
103
Construct an empty organizer item.
105
The organizer item will have an empty item ID, and an empty collection ID. It's of type \l QOrganizerItemType::TypeUndefined.
107
QOrganizerItem::QOrganizerItem()
108
: d(new QOrganizerItemData)
110
QOrganizerItemType organizeritemType;
111
organizeritemType.setType(QOrganizerItemType::TypeUndefined);
112
d->m_details.append(organizeritemType);
116
Constructs an item that is a copy of \a other.
118
QOrganizerItem::QOrganizerItem(const QOrganizerItem &other)
126
Constructs a new, empty item of the given type \a type.
128
QOrganizerItem::QOrganizerItem(QOrganizerItemType::ItemType type)
129
: d(new QOrganizerItemData)
131
QOrganizerItemType organizeritemType;
132
organizeritemType.setType(type);
133
d->m_details.append(organizeritemType);
139
Constructs an item that is a copy of \a other if \a other is of the expected type
140
identified by \a expectedType, else constructs a new, empty item of the
141
type identified by the \a expectedType.
143
The \a expectedType pointer must be valid for the lifetime of the program.
145
QOrganizerItem::QOrganizerItem(const QOrganizerItem &other, QOrganizerItemType::ItemType expectedType)
147
if (other.type() == expectedType) {
150
d = new QOrganizerItemData;
151
setType(expectedType);
158
Assigns this item to \a other if the type of \a other is that identified
159
by the given \a expectedType, else assigns this item to be a new, empty
160
item of the type identified by the given \a expectedType
162
QOrganizerItem &QOrganizerItem::assign(const QOrganizerItem &other, QOrganizerItemType::ItemType expectedType)
164
if (this != &other) {
165
if (other.type() == expectedType) {
168
d = new QOrganizerItemData;
169
setType(expectedType);
177
Returns true if this QOrganizerItem is empty, false if not.
179
Note that the type detail of the organizer item is irrelevant.
181
bool QOrganizerItem::isEmpty() const
183
return (d->m_details.count() == 1);
187
Removes all details of the organizer item, and resets the type to be \l QOrganizerItemType::TypeUndefined.
189
void QOrganizerItem::clearDetails()
191
d->m_details.clear();
193
QOrganizerItemType organizeritemType;
194
organizeritemType.setType(QOrganizerItemType::TypeUndefined);
195
d->m_details.append(organizeritemType);
199
Replace the contents of this organizer item with the \a other.
201
QOrganizerItem &QOrganizerItem::operator=(const QOrganizerItem &other)
208
Frees the memory used by this item.
210
QOrganizerItem::~QOrganizerItem()
215
Returns the QOrganizerItemId that identifies this organizer item.
217
This may have been set when the organizer item was retrieved from
218
a particular manager, or when the organizer item was first saved
219
in a manager. The QOrganizerItemId is only valid within a specific
220
manager. See \l QOrganizerManager::saveItem() for more
223
QOrganizerItemId QOrganizerItem::id() const
229
Returns the id of the collection which this item is part of, in the manager
230
in which the item has been saved, if the item has previously been saved in
231
a manager. If the item has not previously been saved in a manager, this function
232
will return the id of the collection into which the client wishes the item to be
233
saved when \l QOrganizerManager::saveItem() is called, which is set by calling
234
\l setId(); otherwise, returns a null id.
236
An item always belongs to exactly one collection in a particular manager after it
237
has been saved in the manager. If the item has previously been saved in the manager,
238
in a particular collection, and the client sets the collection id of the item to
239
the id of a different collection within that manager and then resaves the item,
240
the item will be moved from its original collection into the specified collection
241
if the move operation is supported by the manager; otherwise, the
242
\l QOrganizerManager::saveItem() operation will fail and calling
243
\l QOrganizerManager::error() will return \c QOrganizerManager::NotSupportedError.
245
QOrganizerCollectionId QOrganizerItem::collectionId() const
247
return d->m_collectionId;
251
Sets the id of the collection into which the client wishes the item to be saved
252
to the given \a collectionId.
254
If the given \a collectionId is the null collection id, the client is specifying
255
that the item should be saved into the collection in which the item is already
256
saved (if the item has previously been saved in the manager, without having been
257
removed since), or into the default collection of the manager (if the item has
258
not previously been saved in the manager, or has been removed since the last time
261
If the item has previously been saved in a particular manager, and the given
262
\a collectionId is the id of a different collection than the one which the
263
item is currently a part of in that manager, saving the item with
264
\l QOrganizerManager::saveItem() will move the item from its original
265
collection to the collection whose id is \a collectionId, if \a collectionId
266
identifies a valid collection and the operation is supported by the manager.
268
void QOrganizerItem::setCollectionId(const QOrganizerCollectionId &collectionId)
270
d->m_collectionId = collectionId;
274
Sets the id of this organizer item to \a id.
276
Note that this only affects this object, not any corresponding structures stored
277
by a QOrganizerManager.
279
If you change the id of a organizer item and save the organizer item
280
in a manager, the previously existing organizer item will still
281
exist. You can do this to create copies (possibly modified)
282
of an existing organizer item, or to save a organizer item in a different manager.
284
\sa QOrganizerManager::saveItem()
286
void QOrganizerItem::setId(const QOrganizerItemId &id)
289
// TODO - reset collection id?
293
Returns the first detail stored in the organizer item with the given \a detailType. If the
294
given \a detailType is TypeUndefined, it returns the first detail found.
296
QOrganizerItemDetail QOrganizerItem::detail(QOrganizerItemDetail::DetailType detailType) const
298
if (detailType == QOrganizerItemDetail::TypeUndefined)
299
return d->m_details.first();
301
for (int i = 0; i < d->m_details.size(); i++) {
302
const QOrganizerItemDetail &existing = d->m_details.at(i);
303
if (existing.d->m_detailType == detailType)
307
return QOrganizerItemDetail();
311
Returns a list of details with the given \a detailType. If the given \a detailType is of TypeUndefined,
312
it returns all the details.
314
QList<QOrganizerItemDetail> QOrganizerItem::details(QOrganizerItemDetail::DetailType detailType) const
316
if (detailType == QOrganizerItemDetail::TypeUndefined)
319
QList<QOrganizerItemDetail> sublist;
320
for (int i = 0; i < d->m_details.size(); i++) {
321
const QOrganizerItemDetail &existing = d->m_details.at(i);
322
if (existing.d->m_detailType == detailType)
323
sublist.append(existing);
329
Saves the given \a detail in the list of stored details, and sets the detail's id.
330
If another detail of the same type and id has been previously saved in
331
this organizer item, that detail is overwritten. Otherwise, a new id is generated
332
and set in the detail, and the detail is added to the organizer item.
334
If \a detail is a QOrganizerItemType, the existing organizer item type will
335
be overwritten with \a detail. There is never more than one organizer item type
338
Returns true if the detail was saved successfully, otherwise returns false.
340
Note that the caller retains ownership of the detail.
342
bool QOrganizerItem::saveDetail(QOrganizerItemDetail *detail)
347
// we only allow one instance of these details per item
348
if (detail->d.constData()->m_detailType == QOrganizerItemDetail::TypeItemType
349
|| detail->d.constData()->m_detailType == QOrganizerItemDetail::TypeDescription
350
|| detail->d.constData()->m_detailType == QOrganizerItemDetail::TypeDisplayLabel
351
|| detail->d.constData()->m_detailType == QOrganizerItemDetail::TypeClassification
352
|| detail->d.constData()->m_detailType == QOrganizerItemDetail::TypeVersion) {
353
for (int i = 0; i < d.constData()->m_details.size(); i++) {
354
if (detail->d.constData()->m_detailType == d.constData()->m_details.at(i).d.constData()->m_detailType) {
355
d->m_details.replace(i, *detail);
359
// doesn't already exist; append it.
360
d->m_details.append(*detail);
364
// try to find the "old version" of this field
365
// ie, the one with the same type and id, but different value or attributes.
366
for (int i = 0; i < d.constData()->m_details.size(); i++) {
367
const QOrganizerItemDetail& curr = d.constData()->m_details.at(i);
368
if (detail->d.constData()->m_detailType == curr.d.constData()->m_detailType && detail->d.constData()->m_id == curr.d.constData()->m_id) {
369
// update the detail constraints of the supplied detail
370
// Found the old version. Replace it with this one.
371
d->m_details[i] = *detail;
375
// this is a new detail! add it to the organizer item.
376
d->m_details.append(*detail);
381
Removes the \a detail from the organizer item.
383
The detail in the organizer item which has the same key as that of the given \a detail
384
will be removed if it exists. Only the key is used for comparison - that is, the
385
information in the detail may be different.
387
Returns true if the detail was removed successfully, false if an error occurred.
389
Note that the caller retains ownership of the detail.
391
bool QOrganizerItem::removeDetail(QOrganizerItemDetail *detail)
396
// find the detail stored in the organizer item which has the same key as the detail argument
397
int removeIndex = -1;
398
for (int i = 0; i < d.constData()->m_details.size(); i++) {
399
if (d.constData()->m_details.at(i).key() == detail->key()) {
405
// make sure the detail exists (in some form) in the organizer item.
409
// Type -detail is specific case which cannot be deleted
410
if (QOrganizerItemDetail::TypeItemType == detail->d.constData()->m_detailType)
413
if (!d.constData()->m_details.contains(*detail))
416
// then remove the detail.
417
d->m_details.removeAt(removeIndex);
422
Returns true if this organizer item is equal to the \a other organizer item, false if either the
423
id, collection id or stored details are not the same.
425
bool QOrganizerItem::operator==(const QOrganizerItem &other) const
427
if (other.d->m_id != d->m_id
428
|| other.d->m_collectionId != d->m_collectionId
429
|| d->m_details.size() != other.d->m_details.size()) {
433
QList<QOrganizerItemDetail> searchList(d->m_details);
435
foreach (const QOrganizerItemDetail &detail, other.d->m_details) {
436
if (!searchList.removeOne(detail))
443
\relates QOrganizerItem
445
Returns the hash value for \a key.
447
uint qHash(const QOrganizerItem &key)
449
uint hash = qHash(key.id());
450
hash += qHash(key.collectionId());
451
foreach (const QOrganizerItemDetail &detail, key.details())
452
hash += qHash(detail);
456
#ifndef QT_NO_DEBUG_STREAM
458
\relates QOrganizerItem
459
Streams the \a item to the given debug stream \a dbg, and returns the stream.
461
QDebug operator<<(QDebug dbg, const QOrganizerItem &item)
463
dbg.nospace() << "QOrganizerItem(" << item.id() << ") in collection(" << item.collectionId() << ")";
464
foreach (const QOrganizerItemDetail& detail, item.details())
465
dbg.space() << '\n' << detail;
466
return dbg.maybeSpace();
468
#endif // QT_NO_DEBUG_STREAM
470
#ifndef QT_NO_DATASTREAM
472
\relates QOrganizerItem
473
Writes \a item to the stream \a out.
475
QDataStream &operator<<(QDataStream &out, const QOrganizerItem &item)
477
quint8 formatVersion = 1; // Version of QDataStream format for QOrganizerItem
479
<< item.id().toString()
480
<< item.collectionId().toString()
486
\relates QOrganizerItem
487
Reads an item from stream \a in into \a item.
489
QDataStream &operator>>(QDataStream &in, QOrganizerItem &item)
491
quint8 formatVersion;
493
if (formatVersion == 1) {
494
item = QOrganizerItem();
495
QString itemIdString;
496
QString collectionIdString;
497
QList<QOrganizerItemDetail> details;
498
in >> itemIdString >> collectionIdString >> details;
499
item.setId(QOrganizerItemId::fromString(itemIdString));
500
item.setCollectionId(QOrganizerCollectionId::fromString(collectionIdString));
501
item.d->m_details = details;
503
in.setStatus(QDataStream::ReadCorruptData);
507
#endif // QT_NO_DATASTREAM
510
Returns the type of the organizer item.
512
QOrganizerItemType::ItemType QOrganizerItem::type() const
514
// type is always the first detail
515
QOrganizerItemType type = static_cast<QOrganizerItemType>(d->m_details.at(0));
520
Sets the type of the organizer item to the given \a type.
522
void QOrganizerItem::setType(QOrganizerItemType::ItemType type)
524
if (d->m_details.isEmpty()) {
525
QOrganizerItemType organizeritemType;
526
organizeritemType.setType(type);
527
d->m_details.append(organizeritemType);
529
// type is always the first detail
530
d->m_details.first().setValue(QOrganizerItemType::FieldType, type);
535
Returns the display label of the item.
537
QString QOrganizerItem::displayLabel() const
539
QOrganizerItemDisplayLabel dl = detail(QOrganizerItemDetail::TypeDisplayLabel);
544
Sets the display label of the item to \a label.
546
void QOrganizerItem::setDisplayLabel(const QString &label)
548
QOrganizerItemDisplayLabel dl = detail(QOrganizerItemDetail::TypeDisplayLabel);
554
Returns the human-readable description of the item.
556
QString QOrganizerItem::description() const
558
QOrganizerItemDescription descr = detail(QOrganizerItemDetail::TypeDescription);
559
return descr.description();
563
Sets the human-readable description of the item to \a description.
565
void QOrganizerItem::setDescription(const QString &description)
567
QOrganizerItemDescription descr = detail(QOrganizerItemDetail::TypeDescription);
568
descr.setDescription(description);
573
Returns the list of comments of this item.
575
QStringList QOrganizerItem::comments() const
577
QStringList commentList;
578
for (int i = 0; i < d->m_details.size(); ++i) {
579
const QOrganizerItemDetail &detail = d->m_details.at(i);
580
if (detail.d->m_detailType == QOrganizerItemDetail::TypeComment)
581
commentList.append(detail.d->m_values.value(QOrganizerItemComment::FieldComment).toString());
587
Removes all comments of this item.
589
void QOrganizerItem::clearComments()
591
d->removeOnly(QOrganizerItemDetail::TypeComment);
595
Sets the list of comments associated with the item to \a comments.
597
void QOrganizerItem::setComments(const QStringList &comments)
599
d->removeOnly(QOrganizerItemDetail::TypeComment);
600
foreach (const QString &comment, comments)
605
Adds the \a comment to this item
607
void QOrganizerItem::addComment(const QString &comment)
609
QOrganizerItemComment detail;
610
detail.setComment(comment);
615
Returns the list of tags for this item.
617
QStringList QOrganizerItem::tags() const
620
for (int i = 0; i < d->m_details.size(); ++i) {
621
const QOrganizerItemDetail &detail = d->m_details.at(i);
622
if (detail.d->m_detailType == QOrganizerItemDetail::TypeTag)
623
tagList.append(detail.d->m_values.value(QOrganizerItemTag::FieldTag).toString());
629
Removes all tags associated with the item.
631
void QOrganizerItem::clearTags()
633
d->removeOnly(QOrganizerItemDetail::TypeTag);
637
Adds the \a tag to this item.
639
void QOrganizerItem::addTag(const QString &tag)
641
QOrganizerItemTag tagDetail;
642
tagDetail.setTag(tag);
643
saveDetail(&tagDetail);
647
Sets the list of tags associated with the item to \a tags.
649
void QOrganizerItem::setTags(const QStringList &tags)
651
d->removeOnly(QOrganizerItemDetail::TypeTag);
652
foreach (const QString &tag, tags)
657
Returns the globally unique identifier which identifies this item,
658
which is used for synchronization purposes.
660
QString QOrganizerItem::guid() const
662
QOrganizerItemGuid guid = detail(QOrganizerItemDetail::TypeGuid);
667
Sets the item's globally unique identifier to \a guid.
669
void QOrganizerItem::setGuid(const QString &guid)
671
QOrganizerItemGuid guidDetail = detail(QOrganizerItemDetail::TypeGuid);
672
guidDetail.setGuid(guid);
673
saveDetail(&guidDetail);
677
Returns the data of the extended detail with the given \a name.
679
QVariant QOrganizerItem::data(const QString &name) const
681
for (int i = 0; i < d->m_details.size(); ++i) {
682
const QOrganizerItemDetail &detail = d->m_details.at(i);
683
if (detail.d->m_detailType == QOrganizerItemDetail::TypeExtendedDetail
684
&& detail.d->m_values.value(QOrganizerItemExtendedDetail::FieldName).toString() == name) {
685
return detail.d->m_values.value(QOrganizerItemExtendedDetail::FieldData);
692
Sets the \a data of a extended detail with the given \a name.
694
void QOrganizerItem::setData(const QString &name, const QVariant &data)
696
for (int i = 0; i < d->m_details.size(); ++i) {
697
const QOrganizerItemDetail &detail = d->m_details.at(i);
698
if (detail.d->m_detailType == QOrganizerItemDetail::TypeExtendedDetail
699
&& detail.d->m_values.value(QOrganizerItemExtendedDetail::FieldName).toString() == name) {
700
QOrganizerItemDetail newDetail = d->m_details.at(i);
701
newDetail.d->m_values.insert(QOrganizerItemExtendedDetail::FieldData, data);
702
saveDetail(&newDetail);
707
QOrganizerItemExtendedDetail newDetail;
708
newDetail.setName(name);
709
newDetail.setData(data);
710
saveDetail(&newDetail);
716
void QOrganizerItemData::removeOnly(QOrganizerItemDetail::DetailType detailType)
718
QList<QOrganizerItemDetail>::iterator dit = m_details.begin();
719
while (dit != m_details.end()) {
720
// XXX this doesn't check type or display label
721
if (dit->type() == detailType)
722
dit = m_details.erase(dit);
731
void QOrganizerItemData::removeOnly(const QSet<QOrganizerItemDetail::DetailType> &detailTypes)
733
QList<QOrganizerItemDetail>::iterator dit = m_details.begin();
734
while (dit != m_details.end()) {
735
// XXX this doesn't check type or display label
736
if (detailTypes.contains(dit->type()))
737
dit = m_details.erase(dit);
743
QT_END_NAMESPACE_ORGANIZER