Coverage Report

Created: 2026-06-07 08:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/painting/qpageranges.cpp
Line
Count
Source
1
// Copyright (C) 2020 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
#include "qpageranges.h"
6
#include "qpageranges_p.h"
7
8
#include <QtCore/qstack.h>
9
#include <QtCore/qdebug.h>
10
#include <QtCore/qdatastream.h>
11
12
QT_BEGIN_NAMESPACE
13
14
QT_IMPL_METATYPE_EXTERN(QPageRanges)
15
16
void QPageRangesPrivate::mergeIntervals()
17
0
{
18
0
    const int count = intervals.size();
19
20
0
    if (count <= 1)
21
0
        return;
22
23
0
    std::sort(intervals.begin(), intervals.end());
24
25
0
    QStack<QPageRanges::Range> stack;
26
0
    stack.push(intervals[0]);
27
28
0
    for (int i = 1; i < count; ++i) {
29
0
        QPageRanges::Range &top = stack.top();
30
31
0
        if (top.to < intervals[i].from - 1)
32
0
            stack.push(intervals[i]);
33
0
        else if (top.to < intervals[i].to)
34
0
            top.to = intervals[i].to;
35
0
    }
36
37
0
    intervals = stack;
38
0
}
39
40
QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QPageRangesPrivate)
41
42
/*!
43
    \class QPageRanges
44
    \brief The QPageRanges class represents a collection of page ranges.
45
    \inmodule QtGui
46
    \ingroup painting
47
    \ingroup printing
48
    \ingroup shared
49
    \since 6.0
50
51
    Use QPagedPaintDevice::pageRanges() to access the collection of page ranges
52
    associated with a paged device.
53
*/
54
55
/*!
56
    Constructs an empty QPageRanges object.
57
*/
58
0
QPageRanges::QPageRanges() = default;
59
60
/*!
61
    Constructs a QPageRanges object by copying \a other.
62
*/
63
0
QPageRanges::QPageRanges(const QPageRanges &other) noexcept = default;
64
65
/*!
66
    \fn QPageRanges::QPageRanges(QPageRanges &&other)
67
68
    Constructs a QPageRanges object by moving from \a other.
69
*/
70
71
/*!
72
    Destroys the page ranges.
73
*/
74
0
QPageRanges::~QPageRanges() = default;
75
76
/*!
77
    Assigns \a other to this QPageRanges object.
78
*/
79
0
QPageRanges &QPageRanges::operator=(const QPageRanges &other) noexcept = default;
80
81
/*!
82
    \fn QPageRanges &QPageRanges::operator=(QPageRanges &&other)
83
    Moves \a other into this QPageRanges object.
84
*/
85
86
/*!
87
    Adds the single page \a pageNumber to the ranges.
88
89
    \note Page numbers start with 1. Attempts to add page numbers
90
    smaller than 1 will be ignored with a warning.
91
*/
92
void QPageRanges::addPage(int pageNumber)
93
0
{
94
0
    if (pageNumber <= 0) {
95
0
        qWarning("QPageRanges::addPage: 'pageNumber' must be greater than 0");
96
0
        return;
97
0
    }
98
99
0
    detach();
100
0
    d->intervals.append({ pageNumber, pageNumber });
101
0
    d->mergeIntervals();
102
0
}
103
104
/*!
105
    Adds the range specified with \a from and \a to to the ranges.
106
107
    \note Page numbers start with 1. Attempts to add page numbers
108
    smaller than 1 will be ignored with a warning.
109
*/
110
void QPageRanges::addRange(int from, int to)
111
0
{
112
0
    if (from <= 0 || to <= 0) {
113
0
        qWarning("QPageRanges::addRange: 'from' and 'to' must be greater than 0");
114
0
        return;
115
0
    }
116
0
    if (to < from)
117
0
        std::swap(from, to);
118
119
0
    detach();
120
0
    d->intervals.append({from, to});
121
0
    d->mergeIntervals();
122
0
}
123
124
/*!
125
    Returns a list with the values of the ranges.
126
*/
127
QList<QPageRanges::Range> QPageRanges::toRangeList() const
128
0
{
129
0
    if (d)
130
0
        return d->intervals;
131
0
    return QList<QPageRanges::Range>{};
132
0
}
133
134
/*!
135
    Removes all page ranges.
136
*/
137
void QPageRanges::clear()
138
0
{
139
0
    d.reset();
140
0
}
141
142
/*!
143
    Constructs and returns a QPageRanges object populated with the
144
    \a ranges from the string representation.
145
146
    \code
147
    QPrinter printer;
148
    QPageRanges ranges = QPageRanges::fromString("1-3,6-7");
149
    printer.setPageRanges(ranges);
150
    \endcode
151
152
    In case of parsing error, returns an empty QPageRanges object.
153
154
    \sa isEmpty()
155
*/
156
QPageRanges QPageRanges::fromString(const QString &ranges)
157
0
{
158
0
    QList<Range> intervals;
159
0
    const QStringList items = ranges.split(u',');
160
0
    for (const QString &item : items) {
161
0
        if (item.isEmpty())
162
0
            return QPageRanges();
163
164
0
        if (item.contains(u'-')) {
165
0
            const QStringList rangeItems = item.split(u'-');
166
0
            if (rangeItems.size() != 2)
167
0
                return QPageRanges();
168
169
0
            bool ok;
170
0
            const int number1 = rangeItems[0].toInt(&ok);
171
0
            if (!ok)
172
0
                return QPageRanges();
173
174
0
            const int number2 = rangeItems[1].toInt(&ok);
175
0
            if (!ok)
176
0
                return QPageRanges();
177
178
0
            if (number1 < 1 || number2 < 1 || number2 < number1)
179
0
                return QPageRanges();
180
181
0
            intervals.append({number1, number2});
182
183
0
        } else {
184
0
            bool ok;
185
0
            const int number = item.toInt(&ok);
186
0
            if (!ok)
187
0
                return QPageRanges();
188
189
0
            if (number < 1)
190
0
                return QPageRanges();
191
192
0
            intervals.append({number, number});
193
0
        }
194
0
    }
195
196
0
    QPageRanges newRanges;
197
0
    newRanges.d.reset(new QPageRangesPrivate);
198
0
    newRanges.d->intervals = intervals;
199
0
    newRanges.d->mergeIntervals();
200
0
    return newRanges;
201
0
}
202
203
/*!
204
    Returns the string representation of the page ranges.
205
*/
206
QString QPageRanges::toString() const
207
0
{
208
0
    if (!d)
209
0
        return QString();
210
211
0
    QString result;
212
0
    for (const Range &range : d->intervals) {
213
0
        if (!result.isEmpty())
214
0
            result += u',';
215
216
0
        if (range.from == range.to)
217
0
            result += QString::number(range.from);
218
0
        else
219
0
            result += QStringLiteral("%1-%2").arg(range.from).arg(range.to);
220
0
    }
221
222
0
    return result;
223
0
}
224
225
/*!
226
    \fn bool QPageRanges::contains(int pageNumber) const
227
228
    Returns \c true if the ranges include the page \a pageNumber;
229
    otherwise returns \c false.
230
*/
231
bool QPageRanges::contains(int pageNumber) const
232
0
{
233
0
    if (!d)
234
0
        return false;
235
236
0
    for (const Range &range : d->intervals) {
237
0
        if (range.from <= pageNumber && range.to >= pageNumber)
238
0
            return true;
239
0
    }
240
0
    return false;
241
0
}
242
243
/*!
244
    Returns \c true if the ranges are empty; otherwise returns \c false.
245
*/
246
bool QPageRanges::isEmpty() const
247
0
{
248
0
    return !d || d->intervals.isEmpty();
249
0
}
250
251
/*!
252
    Returns the index of the first page covered by the page ranges,
253
    or 0 if the page ranges are empty.
254
*/
255
int QPageRanges::firstPage() const
256
0
{
257
0
    if (isEmpty())
258
0
        return 0;
259
0
    return d->intervals.constFirst().from;
260
0
}
261
262
/*!
263
    Returns the index of the last page covered by the page ranges,
264
    or 0 if the page ranges are empty.
265
*/
266
int QPageRanges::lastPage() const
267
0
{
268
0
    if (isEmpty())
269
0
        return 0;
270
0
    return d->intervals.constLast().to;
271
0
}
272
273
/*!
274
    \internal
275
*/
276
bool QPageRanges::isEqual(const QPageRanges &other) const noexcept
277
0
{
278
0
    if (d == other.d)
279
0
        return true;
280
0
    if (!d || !other.d)
281
0
        return false;
282
0
    return d->intervals == other.d->intervals;
283
0
}
284
285
/*!
286
    \internal
287
*/
288
void QPageRanges::detach()
289
0
{
290
0
    if (d)
291
0
        d.detach();
292
0
    else
293
0
        d.reset(new QPageRangesPrivate);
294
0
}
295
296
#if !defined(QT_NO_DATASTREAM)
297
/*!
298
    \fn QDataStream &operator<<(QDataStream &stream, const QPageRanges &pageRanges)
299
    \relates QPageRanges
300
301
    Writes \a pageRanges to \a stream as a range string.
302
303
    \sa QPageRanges::toString
304
*/
305
306
QDataStream &operator<<(QDataStream &s, const QPageRanges &pageRanges)
307
0
{
308
0
    s << pageRanges.toString();
309
0
    return s;
310
0
}
311
312
/*!
313
    \fn QDataStream &operator>>(QDataStream &stream, QPageRanges &pageRanges)
314
    \relates QPageRanges
315
316
    Reads a page ranges string from \a stream and stores it in \a pageRanges.
317
318
    \sa QPageRanges::fromString
319
*/
320
321
QDataStream &operator>>(QDataStream &s, QPageRanges &pageRanges)
322
0
{
323
0
    QString rangesString;
324
0
    s >> rangesString;
325
0
    pageRanges = QPageRanges::fromString(rangesString);
326
0
    return s;
327
0
}
328
#endif // QT_NO_DATASTREAM
329
330
#ifndef QT_NO_DEBUG_STREAM
331
QDebug operator<<(QDebug dbg, const QPageRanges &pageRanges)
332
0
{
333
0
    QDebugStateSaver saver(dbg);
334
0
    dbg.nospace();
335
0
    dbg.noquote();
336
0
    dbg << "QPageRanges(" << pageRanges.toString() << ")";
337
338
0
    return dbg;
339
0
}
340
#endif
341
342
/*!
343
    \struct QPageRanges::Range
344
    \inmodule QtGui
345
    \brief The QPageRanges::Range struct holds the \c from and \c to endpoints of a range.
346
347
    \sa QPageRanges::toRangeList()
348
*/
349
350
/*!
351
    \variable QPageRanges::Range::from
352
    \brief the lower endpoint of the range
353
*/
354
355
/*!
356
    \variable QPageRanges::Range::to
357
    \brief the upper endpoint of the range
358
*/
359
360
/*!
361
    \fn bool QPageRanges::Range::contains(int pageNumber) const
362
363
    Returns \c true if \a pageNumber is within the interval \c{[from, to]};
364
    otherwise returns \c false.
365
*/
366
367
368
QT_END_NAMESPACE