1
/****************************************************************************
2
**
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
**
7
** This file is part of the QtGui module of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** GNU Lesser General Public License Usage
11
** This file may be used under the terms of the GNU Lesser General Public
12
** License version 2.1 as published by the Free Software Foundation and
13
** appearing in the file LICENSE.LGPL included in the packaging of this
14
** file. Please review the following information to ensure the GNU Lesser
15
** General Public License version 2.1 requirements will be met:
16
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
**
18
** In addition, as a special exception, Nokia gives you certain additional
19
** rights. These rights are described in the Nokia Qt LGPL Exception
20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
**
22
** GNU General Public License Usage
23
** Alternatively, this file may be used under the terms of the GNU General
24
** Public License version 3.0 as published by the Free Software Foundation
25
** and appearing in the file LICENSE.GPL included in the packaging of this
26
** file. Please review the following information to ensure the GNU General
27
** Public License version 3.0 requirements will be met:
28
** http://www.gnu.org/copyleft/gpl.html.
29
**
30
** Other Usage
31
** Alternatively, this file may be used in accordance with the terms and
32
** conditions contained in a signed written agreement between you and Nokia.
33
**
34
**
35
**
36
**
37
**
38
** $QT_END_LICENSE$
39
**
40
****************************************************************************/
41
42
43
#include "qtextlist.h"
44
#include "qtextobject_p.h"
45
#include "qtextcursor.h"
46
#include "qtextdocument_p.h"
47
#include <qdebug.h>
48
49
QT_BEGIN_NAMESPACE
50
51
class QTextListPrivate : public QTextBlockGroupPrivate
52
{
53
public:
54
    QTextListPrivate(QTextDocument *doc)
55
        : QTextBlockGroupPrivate(doc)
56
    {
57
    }
58
};
59
60
/*!
61
    \class QTextList
62
    \reentrant
63
64
    \brief The QTextList class provides a decorated list of items in a QTextDocument.
65
66
    \ingroup richtext-processing
67
68
    A list contains a sequence of text blocks, each of which is marked with a
69
    bullet point or other symbol. Multiple levels of lists can be used, and
70
    the automatic numbering feature provides support for ordered numeric and
71
    alphabetical lists.
72
73
    Lists are created by using a text cursor to insert an empty list at the
74
    current position or by moving existing text into a new list.
75
    The \l{QTextCursor::insertList()} function inserts an empty block into the
76
    document at the cursor position, and makes it the first item in a list.
77
78
    \snippet doc/src/snippets/textdocument-lists/mainwindow.cpp 0
79
80
    The \l{QTextCursor::createList()} function takes the contents of the
81
    cursor's current block and turns it into the first item of a new list.
82
83
    The cursor's current list is found with \l{QTextCursor::currentList()}.
84
85
    The number of items in a list is given by count(). Each item can be
86
    obtained by its index in the list with the item() function. Similarly,
87
    the index of a given item can be found with itemNumber(). The text of
88
    each item can be found with the itemText() function.
89
90
    Note that the items in the list may not be adjacent elements in the
91
    document. For example, the top-level items in a multi-level list will
92
    be separated by the items in lower levels of the list.
93
94
    List items can be deleted by index with the removeItem() function.
95
    remove() deletes the specified item in the list.
96
97
    The list's format is set with setFormat() and read with format().
98
    The format describes the decoration of the list itself, and not the
99
    individual items.
100
101
    \sa QTextBlock, QTextListFormat, QTextCursor
102
*/
103
104
/*!
105
    \fn bool QTextList::isEmpty() const
106
    \obsolete
107
108
    Returns true if the list has no items; otherwise returns false.
109
110
    \bold{Note:} Empty lists are automatically deleted by the QTextDocument that owns
111
    them.
112
113
    \sa count()
114
*/
115
116
/*! \internal
117
 */
118
QTextList::QTextList(QTextDocument *doc)
119
    : QTextBlockGroup(*new QTextListPrivate(doc), doc)
120
{
121
}
122
123
/*!
124
  \internal
125
*/
126
QTextList::~QTextList()
127
{
128
}
129
130
/*!
131
    Returns the number of items in the list.
132
*/
133
int QTextList::count() const
134
{
135
    Q_D(const QTextList);
136
    return d->blocks.count();
137
}
138
139
/*!
140
    Returns the \a{i}-th text block in the list.
141
142
    \sa count() itemText()
143
*/
144
QTextBlock QTextList::item(int i) const
145
{
146
    Q_D(const QTextList);
147
    if (i < 0 || i >= d->blocks.size())
148
        return QTextBlock();
149
    return d->blocks.at(i);
150
}
151
152
/*!
153
    \fn void QTextList::setFormat(const QTextListFormat &format)
154
155
    Sets the list's format to \a format.
156
*/
157
158
/*!
159
    \fn QTextListFormat QTextList::format() const
160
161
    Returns the list's format.
162
*/
163
164
/*!
165
    \fn int QTextList::itemNumber(const QTextBlock &block) const
166
167
    Returns the index of the list item that corresponds to the given \a block.
168
    Returns -1 if the block was not present in the list.
169
*/
170
int QTextList::itemNumber(const QTextBlock &blockIt) const
171
{
172
    Q_D(const QTextList);
173
    return d->blocks.indexOf(blockIt);
174
}
175
176
/*!
177
    \fn QString QTextList::itemText(const QTextBlock &block) const
178
179
    Returns the text of the list item that corresponds to the given \a block.
180
*/
181
QString QTextList::itemText(const QTextBlock &blockIt) const
182
{
183
    Q_D(const QTextList);
184
    int item = d->blocks.indexOf(blockIt) + 1;
185
    if (item <= 0)
186
        return QString();
187
188
    QTextBlock block = d->blocks.at(item-1);
189
    QTextBlockFormat blockFormat = block.blockFormat();
190
191
    QString result;
192
193
    const int style = format().style();
194
    QString numberPrefix;
195
    QString numberSuffix = QLatin1String(".");
196
197
    if (format().hasProperty(QTextFormat::ListNumberPrefix))
198
        numberPrefix = format().numberPrefix();
199
    if (format().hasProperty(QTextFormat::ListNumberSuffix))
200
        numberSuffix = format().numberSuffix();
201
202
    switch (style) {
203
        case QTextListFormat::ListDecimal:
204
            result = QString::number(item);
205
            break;
206
            // from the old richtext
207
        case QTextListFormat::ListLowerAlpha:
208
        case QTextListFormat::ListUpperAlpha:
209
            {
210
                const char baseChar = style == QTextListFormat::ListUpperAlpha ? 'A' : 'a';
211
212
                int c = item;
213
                while (c > 0) {
214
                    c--;
215
                    result.prepend(QChar(baseChar + (c % 26)));
216
                    c /= 26;
217
                }
218
            }
219
            break;
220
        case QTextListFormat::ListLowerRoman:
221
        case QTextListFormat::ListUpperRoman:
222
            {
223
                if (item < 5000) {
224
                    QByteArray romanNumeral;
225
226
                    // works for up to 4999 items
227
                    static const char romanSymbolsLower[] = "iiivixxxlxcccdcmmmm";
228
                    static const char romanSymbolsUpper[] = "IIIVIXXXLXCCCDCMMMM";
229
                    QByteArray romanSymbols; // wrap to have "mid"
230
                    if (style == QTextListFormat::ListLowerRoman)
231
                        romanSymbols = QByteArray::fromRawData(romanSymbolsLower, sizeof(romanSymbolsLower));
232
                    else
233
                        romanSymbols = QByteArray::fromRawData(romanSymbolsUpper, sizeof(romanSymbolsUpper));
234
235
                    int c[] = { 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000 };
236
                    int n = item;
237
                    for (int i = 12; i >= 0; n %= c[i], i--) {
238
                        int q = n / c[i];
239
                        if (q > 0) {
240
                            int startDigit = i + (i+3)/4;
241
                            int numDigits;
242
                            if (i % 4) {
243
                                // c[i] == 4|5|9|40|50|90|400|500|900
244
                                if ((i-2) % 4) {
245
                                    // c[i] == 4|9|40|90|400|900 => with subtraction (IV, IX, XL, XC, ...)
246
                                    numDigits = 2;
247
                                }
248
                                else {
249
                                    // c[i] == 5|50|500 (V, L, D)
250
                                    numDigits = 1;
251
                                }
252
                            }
253
                            else {
254
                                // c[i] == 1|10|100|1000 (I, II, III, X, XX, ...)
255
                                numDigits = q;
256
                            }
257
258
                            romanNumeral.append(romanSymbols.mid(startDigit, numDigits));
259
                        }
260
                    }
261
                    result = QString::fromLatin1(romanNumeral);
262
                }
263
                else {
264
                    result = QLatin1String("?");
265
                }
266
267
	    }
268
	    break;
269
        default:
270
            Q_ASSERT(false);
271
    }
272
    if (blockIt.textDirection() == Qt::RightToLeft)
273
        return numberSuffix + result + numberPrefix;
274
    else
275
        return numberPrefix + result + numberSuffix;
276
}
277
278
/*!
279
    Removes the item at item position \a i from the list. When the last item in the
280
    list is removed, the list is automatically deleted by the QTextDocument that owns
281
    it.
282
283
    \sa add(), remove()
284
*/
285
void QTextList::removeItem(int i)
286
{
287
    Q_D(QTextList);
288
    if (i < 0 || i >= d->blocks.size())
289
        return;
290
291
    QTextBlock block = d->blocks.at(i);
292
    remove(block);
293
}
294
295
296
/*!
297
    Removes the given \a block from the list.
298
299
    \sa add(), removeItem()
300
*/
301
void QTextList::remove(const QTextBlock &block)
302
{
303
    QTextBlockFormat fmt = block.blockFormat();
304
    fmt.setIndent(fmt.indent() + format().indent());
305
    fmt.setObjectIndex(-1);
306
    block.docHandle()->setBlockFormat(block, block, fmt, QTextDocumentPrivate::SetFormat);
307
}
308
309
/*!
310
    Makes the given \a block part of the list.
311
312
    \sa remove(), removeItem()
313
*/
314
void QTextList::add(const QTextBlock &block)
315
{
316
    QTextBlockFormat fmt = block.blockFormat();
317
    fmt.setObjectIndex(objectIndex());
318
    block.docHandle()->setBlockFormat(block, block, fmt, QTextDocumentPrivate::SetFormat);
319
}
320
321
QT_END_NAMESPACE