summaryrefslogtreecommitdiffstats
path: root/src/organizer/qorganizeritemdetail.cpp
blob: c2ff7f4abc6bd027ee58d299407e9b0beb61b97f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOrganizer module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qorganizeritemdetail.h"
#include "qorganizeritemdetail_p.h"

#ifndef QT_NO_DATASTREAM
#include <QtCore/qdatastream.h>
#endif
#ifndef QT_NO_DEBUG_STREAM
#include <QtCore/qdebug.h>
#endif

#include "qorganizeritemrecurrence.h"

QT_BEGIN_NAMESPACE_ORGANIZER

/*!
    \class QOrganizerItemDetail

    \brief The QOrganizerItemDetail class represents a single, complete detail about an organizer item.
    \inmodule QtOrganizer
    \ingroup organizer-main

    All of the information for an organizer item is stored in one or more QOrganizerItemDetail objects.

    A detail is a group of logically related bits of data - for example, a QOrganizerItemTimestamp is a single
    detail that has multiple fields (timestamp of creation, timestamp of last update, etc). Different organizer
    managers may support different details for different item types, e.g. certain manager may not support the
    timestamp, while others do.

    In general, QOrganizerItemDetail and the built in subclasses (like \l QOrganizerEventTime) provide
    convenience and standardized access to values. For example, \l QOrganizerEventTime provides a
    convenient API for manipulating a QOrganizerItemDetail to describe the start and end time of an
    event. Subclasses also provide constants for the names of fields (like \l QOrganizerEventTime::FieldStartDateTime).
    Typically the constants for field names start with \c Field, and the constants for predefined values
    of a field start with the name of that field (e.g. \c TypeEvent is a predefined constant for \c FieldType).

    QOrganizerItemDetail objects act like type checked values.  In general, you can assign them
    to and fro and have reasonable behaviour, like the following example.

    \code
    QOrganizerItemDescription description;
    description.setDescription("Some descriptive text");
    // description.value(QOrganizerItemDescription::FieldDescription) == "Some descriptive text";
    // description.type() == QOrganizerItemDetail::TypeDescription

    QOrganizerItemDetail detail = description;
    // detail.value(QOrganizerItemDescription::FieldDescription) == "Some descriptive text";
    // detail.type() == QOrganizerItemDetail::TypeDescription

    QOrganizerItemDescription otherDescription = detail;
    // otherDescription.description() == "Some descriptive text";
    // otherDescription.type() == QOrganizerItemDetail::TypeDescription

    QOrganizerItemDisplayLabel label = detail;
    // label is now a default constructed QOrganizerItemDisplayLabel
    // label.value(QOrganizerItemDescription::FieldDescription) is empty
    // label.type() == QOrganizerItemDetail::TypeDisplayLabel

    QOrganizerItemDisplayLabel otherLabel = description;
    // otherLabel is now a default constructed QOrganizerItemDisplayLabel
    // otherLabel.value(QOrganizerItemDescription::FieldDescription) is empty
    // otherLabel.type() == QOrganizerItemDetail::TypeDisplayLabel
    \endcode

    \sa QOrganizerItem, QOrganizerItemDetailFilter, QOrganizerItemDetailFieldFilter, QOrganizerItemDetailRangeFilter
 */

/*!
    \enum QOrganizerItemDetail::DetailType

    This enumeration describes the type of the organizer item detail.

    \value TypeUndefined        This detail is of type undefined.
    \value TypeClassification   This detail is a classification.
    \value TypeComment          This detail is a comment
    \value TypeDescription      This detail is a description.
    \value TypeDisplayLabel     This detail is a display label.
    \value TypeItemType         This detail is an item type.
    \value TypeGuid             This detail is a GUID.
    \value TypeLocation         This detail is a location.
    \value TypeParent           This detail is a parent. Should not be used in parent items.
    \value TypePriority         This detail is a priority.
    \value TypeRecurrence       This detail is a recurrence. Should not be used in occurrences.
    \value TypeTag              This detail is a tag.
    \value TypeTimestamp        This detail is a timestamp.
    \value TypeVersion          This detail is a version.
    \value TypeReminder         This detail is a reminder. Should not be directly used.
    \value TypeAudibleReminder  This detail is an audible reminder.
    \value TypeEmailReminder    This detail is an email reminder.
    \value TypeVisualReminder   This detail is a visual reminder.
    \value TypeExtendedDetail   This detail is an extended detail.
    \value TypeEventAttendee    This detail is an event attendee.
    \value TypeEventRsvp        This detail is an event RSVP.
    \value TypeEventTime        This detail is an event time.
    \value TypeJournalTime      This detail is a journal time.
    \value TypeTodoTime         This detail is a TODO time.
    \value TypeTodoProgress     This detail is a TODO progress.
 */

/*!
    \internal
    \macro Q_DECLARE_CUSTOM_ORGANIZER_DETAIL
    \relates QOrganizerItemDetail

    Macro for simplifying declaring leaf detail classes.

    The first argument is the name of the class, and the second argument is the
    detail definition name.

    If you are creating a leaf detail class for a type of QOrganizerItemDetail,
    you should use this macro when declaring your class to ensure that
    it interoperates with other organizer item functionality.
 */


/*!
    \fn bool QOrganizerItemDetail::operator!=(const QOrganizerItemDetail &other) const

    Returns true if the values or id of this detail is different to those of the \a other detail
 */

/*!
    Constructs a new, empty detail of the \a detailType.
 */
QOrganizerItemDetail::QOrganizerItemDetail(DetailType detailType)
    : d(new QOrganizerItemDetailPrivate(detailType))
{
}

/*!
    Constructs a detail that is a copy of \a other.
 */
QOrganizerItemDetail::QOrganizerItemDetail(const QOrganizerItemDetail &other)
    : d(other.d)
{
}

/*!
    \internal

    Constructs a detail that is a copy of \a other if \a other is of the type
    identified by \a expectedDetailType, else constructs a new, empty detail of the
    type identified by the \a expectedDetailType.
*/
QOrganizerItemDetail::QOrganizerItemDetail(const QOrganizerItemDetail &other, DetailType expectedDetailType)
{
    if (other.d->m_detailType == expectedDetailType)
        d = other.d;
    else
        d = new QOrganizerItemDetailPrivate(expectedDetailType);
}

/*!
    Assigns this detail to \a other.
 */
QOrganizerItemDetail &QOrganizerItemDetail::operator=(const QOrganizerItemDetail &other)
{
    d = other.d;
    return *this;
}

/*!
    \internal

    Assigns this detail to \a other if the type of \a other is that identified
    by the given \a expectedDetailType, else assigns this detail to be a new, empty
    detail of the type identified by the given \a expectedDetailType.
 */
QOrganizerItemDetail &QOrganizerItemDetail::assign(const QOrganizerItemDetail &other, DetailType expectedDetailType)
{
    if (d != other.d) {
        if (other.d->m_detailType == expectedDetailType)
            d = other.d;
        else
            d = new QOrganizerItemDetailPrivate(expectedDetailType);
    }
    return *this;
}

/*!
    Frees the memory used by this detail.
 */
QOrganizerItemDetail::~QOrganizerItemDetail()
{
}

/*!
    Returns the detail type.
 */
QOrganizerItemDetail::DetailType QOrganizerItemDetail::type() const
{
    return d->m_detailType;
}

/*!
    Compares this detail to \a other.  Returns true if the type and values of \a other are equal to those of this detail.
    The keys of each detail are not considered during the comparison, in order to allow details from different organizer items to
    be compared according to their values.
 */
bool QOrganizerItemDetail::operator==(const QOrganizerItemDetail &other) const
{
    if (d == other.d)
        return true;

    // note: id is auto-generated and should not be compared here
    if (d->m_detailType != other.d->m_detailType)
        return false;

    // QVariant doesn't support == on QOrganizerItemRecurrence - do it manually
    if (d->m_detailType == QOrganizerItemDetail::TypeRecurrence)
        return static_cast<QOrganizerItemRecurrence>(*this) == static_cast<QOrganizerItemRecurrence>(other);

    return d->m_values == other.d->m_values;
}

/*!
    \relates QOrganizerItemDetail
    Returns the hash value for \a key.
 */
Q_ORGANIZER_EXPORT size_t qHash(const QOrganizerItemDetail &key)
{
    size_t hash = QT_PREPEND_NAMESPACE(qHash)(key.d->m_detailType);
    QMap<int, QVariant>::const_iterator it = key.d->m_values.constBegin();
    while (it != key.d->m_values.constEnd()) {
        hash += QT_PREPEND_NAMESPACE(qHash)(it.key()) + QT_PREPEND_NAMESPACE(qHash)(it.value().toString());
        ++it;
    }
    return hash;
}

#ifndef QT_NO_DEBUG_STREAM
/*!
    \relates QOrganizerItemDetail
    Streams the \a detail to the given debug stream \a dbg, and returns the stream.
 */
Q_ORGANIZER_EXPORT QDebug operator<<(QDebug dbg, const QOrganizerItemDetail &detail)
{
    dbg.nospace() << "QOrganizerItemDetail(name=" << detail.type() << ", key=" << detail.key();
    QMap<int, QVariant> fields = detail.values();
    QMap<int, QVariant>::const_iterator it;
    for (it = fields.constBegin(); it != fields.constEnd(); ++it)
        dbg.nospace() << ", " << it.key() << '=' << it.value();
    dbg.nospace() << ')';
    return dbg.maybeSpace();
}
#endif // QT_NO_DEBUG_STREAM

#ifndef QT_NO_DATASTREAM
/*!
    \relates QOrganizerItemDetail
    Writes \a detail to the stream \a out.
 */
Q_ORGANIZER_EXPORT QDataStream &operator<<(QDataStream &out, const QOrganizerItemDetail &detail)
{
    quint8 formatVersion = 1; // Version of QDataStream format for QOrganizerItemDetail
    return out << formatVersion
               << static_cast<quint32>(detail.type())
               << detail.values();
}

/*!
    \relates QOrganizerItemDetail
    Reads an organizer item detail from stream \a in into \a detail.
 */
Q_ORGANIZER_EXPORT QDataStream &operator>>(QDataStream &in, QOrganizerItemDetail &detail)
{
    quint8 formatVersion;
    in >> formatVersion;
    if (formatVersion == 1) {
        quint32 detailType;
        QMap<int, QVariant> values;
        in >> detailType >> values;

        detail = QOrganizerItemDetail(static_cast<QOrganizerItemDetail::DetailType>(detailType));

        for (auto it = values.cbegin(), end = values.cend(); it != end; ++it)
            detail.setValue(it.key(), it.value());
    } else {
        in.setStatus(QDataStream::ReadCorruptData);
    }
    return in;
}
#endif // QT_NO_DATASTREAM

/*!
    Returns true if no values are contained in this detail.
 */
bool QOrganizerItemDetail::isEmpty() const
{
    return (d->m_values.isEmpty());
}

/*!
    Returns the key of this detail.
 */
int QOrganizerItemDetail::key() const
{
    return d->m_id;
}

/*!
    Causes the implicitly-shared detail to be detached from any other copies, and generates a new key for it.
    This ensures that calling QOrganizerItem::saveDetail() will result in a new detail being saved, rather than
    another detail being updated.
 */
void QOrganizerItemDetail::resetKey()
{
    d->m_id = QOrganizerItemDetailPrivate::lastDetailKey().fetchAndAddOrdered(1);
}

/*!
    Returns the value stored in this detail for the given \a field. An invalid QVariant is returned if the
    value of \a field is not set.
 */
QVariant QOrganizerItemDetail::value(int field) const
{
    return d->m_values.value(field);
}

/*!
    Returns true if the value of the given \a field has been set, or false otherwise.
 */
bool QOrganizerItemDetail::hasValue(int field) const
{
    return d->m_values.contains(field);
}

/*!
    Sets the value of the given \a field to be \a value. If the given \a value is invalid or null,
    removes the given \a field from the detail. Returns true on success, or false otherwise.
 */
bool QOrganizerItemDetail::setValue(int field, const QVariant &value)
{
    if (!value.isValid() || value.isNull())
        return removeValue(field);

    d->m_values.insert(field, value);
    return true;
}

/*!
    Removes the value stored in this detail for the given \a field.  Returns true if a value was stored
    for the given \a field and the removing succeeds, or false otherwise.
 */
bool QOrganizerItemDetail::removeValue(int field)
{
    return d->m_values.remove(field);
}

/*!
    Returns the values stored in this detail as a field-to-value map.
 */
QMap<int, QVariant> QOrganizerItemDetail::values() const
{
    return d->m_values;
}

/*!
    \fn template <typename T> T QOrganizerItemDetail::value(int field) const
    Returns the value of the template type associated with the given \a field.
 */

QT_END_NAMESPACE_ORGANIZER