Rename QRangeCollection to QPageRanges, make it a proper value type

The type is specific about printing, so give it a name in line with
QPageLayout and QPageSize.

As per API review comment, it's not clear why this type should not be a
regular, copyable and movable value type. It stores a list of intervals.
Give it value-type semantics, as an implicitly shared class.

Convert the parse method into a static factory function.

Add a Range type and use it instead of the semantic-free QPair.
Move QPrinter getter into QPagedPainteDevice, make it return a copy
rather than a pointer, and add a setter.

Extend test case to cover all members and more merge cases. Fix bugs
found that way.

Fixes: QTBUG-88113
Change-Id: If17ea4d410d49f16b097e88b7979db5d72add820
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
bb10
Volker Hilsheimer 2020-11-02 21:39:34 +01:00
parent 8bf36025f5
commit b14b1c99f8
21 changed files with 674 additions and 448 deletions

View File

@ -124,6 +124,7 @@ qt_internal_add_module(Gui
painting/qoutlinemapper.cpp painting/qoutlinemapper_p.h
painting/qpagedpaintdevice.cpp painting/qpagedpaintdevice.h painting/qpagedpaintdevice_p.h
painting/qpagelayout.cpp painting/qpagelayout.h
painting/qpageranges.cpp painting/qpageranges.h painting/qpageranges_p.h
painting/qpagesize.cpp painting/qpagesize.h
painting/qpaintdevice.cpp painting/qpaintdevice.h
painting/qpaintengine.cpp painting/qpaintengine.h painting/qpaintengine_p.h
@ -140,7 +141,6 @@ qt_internal_add_module(Gui
painting/qpixellayout.cpp painting/qpixellayout_p.h
painting/qplatformbackingstore.cpp painting/qplatformbackingstore.h
painting/qpolygon.cpp painting/qpolygon.h
painting/qrangecollection.cpp painting/qrangecollection.h painting/qrangecollection_p.h
painting/qrasterdefs_p.h
painting/qrasterizer.cpp painting/qrasterizer_p.h
painting/qrbtree_p.h

View File

@ -175,6 +175,7 @@ qt_internal_add_module(Gui
painting/qoutlinemapper.cpp painting/qoutlinemapper_p.h
painting/qpagedpaintdevice.cpp painting/qpagedpaintdevice.h painting/qpagedpaintdevice_p.h
painting/qpagelayout.cpp painting/qpagelayout.h
painting/qpageranges.cpp painting/qpageranges.h painting/qpageranges_p.h
painting/qpagesize.cpp painting/qpagesize.h
painting/qpaintdevice.cpp painting/qpaintdevice.h
painting/qpaintengine.cpp painting/qpaintengine.h painting/qpaintengine_p.h
@ -191,7 +192,6 @@ qt_internal_add_module(Gui
painting/qpixellayout.cpp painting/qpixellayout_p.h
painting/qplatformbackingstore.cpp painting/qplatformbackingstore.h
painting/qpolygon.cpp painting/qpolygon.h
painting/qrangecollection.cpp painting/qrangecollection.h painting/qrangecollection_p.h
painting/qrasterdefs_p.h
painting/qrasterizer.cpp painting/qrasterizer_p.h
painting/qrbtree_p.h

View File

@ -31,6 +31,8 @@ HEADERS += \
painting/qpagedpaintdevice.h \
painting/qpagedpaintdevice_p.h \
painting/qpagelayout.h \
painting/qpageranges.h \
painting/qpageranges_p.h \
painting/qpagesize.h \
painting/qpaintdevice.h \
painting/qpaintengine.h \
@ -49,8 +51,6 @@ HEADERS += \
painting/qpen.h \
painting/qpixellayout_p.h \
painting/qpolygon.h \
painting/qrangecollection.h \
painting/qrangecollection_p.h \
painting/qrasterdefs_p.h \
painting/qrasterizer_p.h \
painting/qrbtree_p.h \
@ -88,6 +88,7 @@ SOURCES += \
painting/qoutlinemapper.cpp \
painting/qpagedpaintdevice.cpp \
painting/qpagelayout.cpp \
painting/qpageranges.cpp \
painting/qpagesize.cpp \
painting/qpaintdevice.cpp \
painting/qpaintengine.cpp \
@ -102,7 +103,6 @@ SOURCES += \
painting/qpen.cpp \
painting/qpixellayout.cpp \
painting/qpolygon.cpp \
painting/qrangecollection.cpp \
painting/qrasterizer.cpp \
painting/qregion.cpp \
painting/qstroker.cpp \

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@ -42,10 +42,8 @@
QT_BEGIN_NAMESPACE
QPagedPaintDevicePrivate::~QPagedPaintDevicePrivate()
{
delete rangeCollection;
}
QPagedPaintDevicePrivate::~QPagedPaintDevicePrivate() = default;
/*!
\class QPagedPaintDevice
@ -213,4 +211,26 @@ QPageLayout QPagedPaintDevice::pageLayout() const
return d->pageLayout();
}
/*!
\since 6.0
Returns the page ranges associated with this device.
\sa QPageRanges, QPrinter::fromPage(), QPrinter::toPage()
*/
QPageRanges QPagedPaintDevice::pageRanges() const
{
return d->pageRanges;
}
/*!
\since 6.0
Sets the page ranges for this device to \a ranges.
*/
void QPagedPaintDevice::setPageRanges(const QPageRanges &ranges)
{
d->pageRanges = ranges;
}
QT_END_NAMESPACE

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@ -43,6 +43,7 @@
#include <QtGui/qtguiglobal.h>
#include <QtGui/qpaintdevice.h>
#include <QtGui/qpagelayout.h>
#include <QtGui/qpageranges.h>
QT_BEGIN_NAMESPACE
@ -68,6 +69,9 @@ public:
virtual bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units = QPageLayout::Millimeter);
QPageLayout pageLayout() const;
virtual void setPageRanges(const QPageRanges &ranges);
QPageRanges pageRanges() const;
protected:
QPagedPaintDevice(QPagedPaintDevicePrivate *dd);
QPagedPaintDevicePrivate *dd();

View File

@ -53,7 +53,6 @@
#include <QtGui/private/qtguiglobal_p.h>
#include <qpagedpaintdevice.h>
#include <qrangecollection.h>
QT_BEGIN_NAMESPACE
@ -61,8 +60,7 @@ class Q_GUI_EXPORT QPagedPaintDevicePrivate
{
public:
QPagedPaintDevicePrivate()
: rangeCollection(new QRangeCollection),
pageOrderAscending(true),
: pageOrderAscending(true),
printSelectionOnly(false)
{
}
@ -83,7 +81,7 @@ public:
static inline QPagedPaintDevicePrivate *get(QPagedPaintDevice *pd) { return pd->d; }
// These are currently required to keep QPrinter functionality working in QTextDocument::print()
QRangeCollection *rangeCollection;
QPageRanges pageRanges;
bool pageOrderAscending;
bool printSelectionOnly;
};

View File

@ -0,0 +1,365 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui 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 "qpageranges.h"
#include "qpageranges_p.h"
#include <QtCore/qstack.h>
#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
void QPageRangesPrivate::mergeIntervals()
{
const int count = intervals.count();
if (count <= 1)
return;
std::sort(intervals.begin(), intervals.end());
QStack<QPageRanges::Range> stack;
stack.push(intervals[0]);
for (int i = 1; i < count; ++i) {
QPageRanges::Range &top = stack.top();
if (top.to < intervals[i].from - 1)
stack.push(intervals[i]);
else if (top.to < intervals[i].to)
top.to = intervals[i].to;
}
intervals = stack;
}
QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QPageRangesPrivate)
/*!
\class QPageRanges
\brief The QPageRanges class represents a collection of page ranges.
\inmodule QtGui
\ingroup painting
\ingroup printing
\ingroup shared
\since 6.0
Use QPagedPaintDevice::pageRanges() to access the collection of page ranges
associated with a paged device.
*/
/*!
Constructs an empty QPageRanges object.
*/
QPageRanges::QPageRanges() = default;
/*!
Constructs a QPageRanges object by copying \a other.
*/
QPageRanges::QPageRanges(const QPageRanges &other) noexcept = default;
/*!
\fn QPageRanges::QPageRanges(QPageRanges &&other)
Constructs a QPageRanges object by moving from \a other.
*/
/*!
Destroys the page ranges.
*/
QPageRanges::~QPageRanges() = default;
/*!
Assigns \a other to this QPageRanges object.
*/
QPageRanges &QPageRanges::operator=(const QPageRanges &other) noexcept = default;
/*!
\fn QPageRanges &QPageRanges::operator=(QPageRanges &&other)
Moves \a other into this QPageRanges object.
*/
/*!
Adds the single page \a pageNumber to the ranges.
\note Page numbers start with 1. Attempts to add page numbers
smaller than 1 will be ignored with a warning.
*/
void QPageRanges::addPage(int pageNumber)
{
if (pageNumber <= 0) {
qWarning("QPageRanges::addPage: 'pageNumber' must be greater than 0");
return;
}
detach();
d->intervals.append({ pageNumber, pageNumber });
d->mergeIntervals();
}
/*!
Adds the range specified with \a from and \a to to the ranges.
\note Page numbers start with 1. Attempts to add page numbers
smaller than 1 will be ignored with a warning.
*/
void QPageRanges::addRange(int from, int to)
{
if (from <= 0 || to <= 0) {
qWarning("QPageRanges::addRange: 'from' and 'to' must be greater than 0");
return;
}
if (to < from)
std::swap(from, to);
detach();
d->intervals.append({from, to});
d->mergeIntervals();
}
/*!
Returns a list with the values of the ranges.
*/
QList<QPageRanges::Range> QPageRanges::toRangeList() const
{
if (d)
return d->intervals;
return QList<QPageRanges::Range>{};
}
/*!
Removes all page ranges.
*/
void QPageRanges::clear()
{
d.reset();
}
/*!
Constructs and returns a QPageRanges object populated with the
\a ranges from the string representation.
\code
QPrinter printer;
QPageRanges ranges = QPageRanges::fromString("1-3,6-7");
printer.setPageRanges(ranges);
\endcode
In case of parsing error, returns an empty QPageRanges object.
\sa isEmpty()
*/
QPageRanges QPageRanges::fromString(const QString &ranges)
{
QList<Range> intervals;
const QStringList items = ranges.split(u',');
for (const QString &item : items) {
if (item.isEmpty())
return QPageRanges();
if (item.contains(QLatin1Char('-'))) {
const QStringList rangeItems = item.split(u'-');
if (rangeItems.count() != 2)
return QPageRanges();
bool ok;
const int number1 = rangeItems[0].toInt(&ok);
if (!ok)
return QPageRanges();
const int number2 = rangeItems[1].toInt(&ok);
if (!ok)
return QPageRanges();
if (number1 < 1 || number2 < 1 || number2 < number1)
return QPageRanges();
intervals.append({number1, number2});
} else {
bool ok;
const int number = item.toInt(&ok);
if (!ok)
return QPageRanges();
if (number < 1)
return QPageRanges();
intervals.append({number, number});
}
}
QPageRanges newRanges;
newRanges.d.reset(new QPageRangesPrivate);
newRanges.d->intervals = intervals;
newRanges.d->mergeIntervals();
return newRanges;
}
/*!
Returns the string representation of the page ranges.
*/
QString QPageRanges::toString() const
{
if (!d)
return QString();
QString result;
for (const Range &range : d->intervals) {
if (!result.isEmpty())
result += QLatin1Char(',');
if (range.from == range.to)
result += QString::number(range.from);
else
result += QStringLiteral("%1-%2").arg(range.from).arg(range.to);
}
return result;
}
/*!
\fn bool QPageRanges::contains(int pageNumber) const
Returns \c true if the ranges include the page \a pageNumber;
otherwise returns \c false.
*/
bool QPageRanges::contains(int pageNumber) const
{
if (!d)
return false;
for (const Range &range : d->intervals) {
if (range.from <= pageNumber && range.to >= pageNumber)
return true;
}
return false;
}
/*!
Returns \c true if the ranges are empty; otherwise returns \c false.
*/
bool QPageRanges::isEmpty() const
{
return !d || d->intervals.isEmpty();
}
/*!
Returns the index of the first page covered by the page ranges,
or 0 if the page ranges are empty.
*/
int QPageRanges::firstPage() const
{
if (isEmpty())
return 0;
return d->intervals.first().from;
}
/*!
Returns the index of the last page covered by the page ranges,
or 0 if the page ranges are empty.
*/
int QPageRanges::lastPage() const
{
if (isEmpty())
return 0;
return d->intervals.last().to;
}
/*!
\internal
*/
bool QPageRanges::isEqual(const QPageRanges &other) const noexcept
{
if (d == other.d)
return true;
if (!d || !other.d)
return false;
return d->intervals == other.d->intervals;
}
/*!
\internal
*/
void QPageRanges::detach()
{
if (d)
d.detach();
else
d.reset(new QPageRangesPrivate);
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QPageRanges &pageRanges)
{
QDebugStateSaver saver(dbg);
dbg.nospace();
dbg.noquote();
dbg << "QPageRanges(" << pageRanges.toString() << ")";
return dbg;
}
#endif
/*!
\struct QPageRanges::Range
\brief The QPageRanges::Range struct holds the \c from and \c to endpoints of a range.
\sa QPageRanges::toRangeList()
*/
/*!
\variable QPageRanges::Range::from
\brief the lower endpoint of the range
*/
/*!
\variable QPageRanges::Range::to
\brief the upper endpoint of the range
*/
/*!
\fn bool QPageRanges::Range::contains(int pageNumber) const
Returns \c true if \a pageNumber is within the interval \c{[from, to]};
otherwise returns \c false.
*/
QT_END_NAMESPACE

View File

@ -37,42 +37,82 @@
**
****************************************************************************/
#ifndef QRANGECOLLECTION_H
#define QRANGECOLLECTION_H
#ifndef QPAGERANGES_H
#define QPAGERANGES_H
#include <QtGui/qtguiglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
#include <QtCore/qpair.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qmetatype.h>
QT_BEGIN_NAMESPACE
class QRangeCollectionPrivate;
class QDebug;
class QPageRangesPrivate;
QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QPageRangesPrivate, Q_GUI_EXPORT)
class Q_GUI_EXPORT QRangeCollection
class Q_GUI_EXPORT QPageRanges
{
Q_DECLARE_PRIVATE(QRangeCollection)
public:
explicit QRangeCollection();
~QRangeCollection();
QPageRanges();
~QPageRanges();
QPageRanges(const QPageRanges &other) noexcept;
QPageRanges &operator=(const QPageRanges &other) noexcept;
QPageRanges(QPageRanges &&other) noexcept = default;
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QPageRanges)
void swap(QPageRanges &other) noexcept
{ qSwap(d, other.d); }
friend bool operator==(const QPageRanges &lhs, const QPageRanges &rhs) noexcept
{ return lhs.isEqual(rhs); }
friend bool operator!=(const QPageRanges &lhs, const QPageRanges &rhs) noexcept
{ return !lhs.isEqual(rhs); }
struct Range {
int from = -1;
int to = -1;
bool contains(int pageNumber) const noexcept
{ return from <= pageNumber && to >= pageNumber; }
friend bool operator==(Range lhs, Range rhs) noexcept
{ return lhs.from == rhs.from && lhs.to == rhs.to; }
friend bool operator!=(Range lhs, Range rhs) noexcept
{ return !(lhs == rhs); }
friend bool operator<(Range lhs, Range rhs) noexcept
{ return lhs.from < rhs.from || (!(rhs.from < lhs.from) && lhs.to < rhs.to); }
};
void addPage(int pageNumber);
void addRange(int from, int to);
QList<QPair<int, int>> toList() const;
QList<Range> toRangeList() const;
void clear();
bool parse(const QString &ranges);
QString toString() const;
static QPageRanges fromString(const QString &ranges);
bool contains(const int pageNumber) const;
bool contains(int pageNumber) const;
bool isEmpty() const;
int firstPage() const;
int lastPage() const;
private:
QScopedPointer<QRangeCollectionPrivate> d_ptr;
bool isEqual(const QPageRanges &other) const noexcept;
void detach();
QExplicitlySharedDataPointer<QPageRangesPrivate> d;
};
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QPageRanges &pageRanges);
#endif
Q_DECLARE_SHARED(QPageRanges)
Q_DECLARE_TYPEINFO(QPageRanges::Range, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
#endif // QRANGECOLLECTION_H
Q_DECLARE_METATYPE(QPageRanges)
#endif // QPAGERANGES_H

View File

@ -37,8 +37,8 @@
**
****************************************************************************/
#ifndef QRANGECOLLECTION_P_H
#define QRANGECOLLECTION_P_H
#ifndef QPAGERANGES_P_H
#define QPAGERANGES_P_H
//
// W A R N I N G
@ -56,21 +56,14 @@
QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QRangeCollectionPrivate
class QPageRangesPrivate : public QSharedData
{
Q_DECLARE_PUBLIC(QRangeCollection)
public:
QRangeCollectionPrivate(QRangeCollection *rangeCollection)
: q_ptr(rangeCollection)
{
}
void mergeIntervals();
QList<QPair<int, int>> intervals;
QRangeCollection *q_ptr;
QList<QPageRanges::Range> intervals;
};
QT_END_NAMESPACE
#endif // QRANGECOLLECTION_P_H
#endif // QPAGERANGES_P_H

View File

@ -1,285 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui 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 "qrangecollection.h"
#include "qrangecollection_p.h"
#include <QtCore/qstack.h>
QT_BEGIN_NAMESPACE
void QRangeCollectionPrivate::mergeIntervals()
{
const int count = intervals.count();
if (count <= 0)
return;
std::sort(intervals.begin(), intervals.end());
QStack<QPair<int, int>> stack;
stack.push(intervals[0]);
for (int i = 1; i < count; i++) {
QPair<int, int> &top = stack.top();
if (top.second < intervals[i].first)
stack.push(intervals[i]);
else if (top.second < intervals[i].second)
top.second = intervals[i].second;
}
std::sort(intervals.begin(), intervals.end());
intervals = stack;
}
/*!
\class QRangeCollection
\brief The QRangeCollection class represents a collection of decimal intervals.
\inmodule QtGui
\ingroup painting
\since 6.0
QRangeCollection manages a set of decimal intervals.
Use QPrinter::rangeCollection() to access the collection of page ranges
associated with a QPrinter.
*/
QRangeCollection::QRangeCollection()
: d_ptr(new QRangeCollectionPrivate(this))
{
}
/*!
Destroys the collection.
*/
QRangeCollection::~QRangeCollection()
{
}
/*!
Inserts a single number \a pageNumber into the collection.
*/
void QRangeCollection::addPage(int pageNumber)
{
Q_D(QRangeCollection);
if (pageNumber <= 0) {
qWarning("QRangeCollection::addPage: 'pageNumber' must be greater than 0");
return;
}
d->intervals.append(qMakePair(pageNumber, pageNumber));
d->mergeIntervals();
}
/*!
Inserts a range specified with \a from and \a to into the collection.
*/
void QRangeCollection::addRange(int from, int to)
{
Q_D(QRangeCollection);
if (from <= 0 || to <= 0) {
qWarning("QRangeCollection::addRange: 'from' and 'to' must be greater than 0");
return;
}
if (to < from) {
qWarning("QRangeCollection::addRange: 'from' must be less than or equal to 'to'");
std::swap(from, to);
}
d->intervals.append(qMakePair(from, to));
d->mergeIntervals();
}
/*!
Returns a list with the values of the ranges used in this collection.
*/
QList<QPair<int, int>> QRangeCollection::toList() const
{
Q_D(const QRangeCollection);
return d->intervals.toList();
}
/*!
* Removes all ranges from this collection.
*/
void QRangeCollection::clear()
{
Q_D(QRangeCollection);
d->intervals.clear();
}
/*!
Constructs the range collection from a string representation of \a ranges.
\code
QPrinter printer;
printer->rangeCollection()->parse("1-3,6-7");
\endcode
Returns \c true on success.
*/
bool QRangeCollection::parse(const QString &ranges)
{
Q_D(QRangeCollection);
const QStringList items = ranges.split(u',');
for (const QString &item : items) {
if (item.isEmpty()) {
d->intervals.clear();
return false;
}
if (item.contains(QLatin1Char('-'))) {
const QStringList rangeItems = item.split(u'-');
if (rangeItems.count() != 2) {
d->intervals.clear();
return false;
}
bool ok;
const int number1 = rangeItems[0].toInt(&ok);
if (!ok) {
d->intervals.clear();
return false;
}
const int number2 = rangeItems[1].toInt(&ok);
if (!ok) {
d->intervals.clear();
return false;
}
if (number1 < 1 || number2 < 1 || number2 < number1) {
d->intervals.clear();
return false;
}
d->intervals.append(qMakePair(number1, number2));
} else {
bool ok;
const int number = item.toInt(&ok);
if (!ok) {
d->intervals.clear();
return false;
}
if (number < 1) {
d->intervals.clear();
return false;
}
d->intervals.append(qMakePair(number, number));
}
}
d->mergeIntervals();
return true;
}
/*!
Returns the string representation of the ranges in the collection.
*/
QString QRangeCollection::toString() const
{
Q_D(const QRangeCollection);
QString result;
for (const QPair<int, int> &pair : d->intervals) {
if (!result.isEmpty())
result += QLatin1Char(',');
if (pair.first == pair.second)
result += QString::number(pair.first);
else
result += QStringLiteral("%1-%2").arg(pair.first).arg(pair.second);
}
return result;
}
/*!
\fn bool QRangeCollection::contains(const int pageNumber) const
Returns \c true if the collection contains an occurrence
or a bounding range of \a pageNumber; otherwise returns
\c false.
*/
bool QRangeCollection::contains(int pageNumber) const
{
Q_D(const QRangeCollection);
for (const QPair<int, int> &pair : d->intervals) {
if (pair.first <= pageNumber && pair.second >= pageNumber)
return true;
}
return false;
}
/*!
Returns \c true if the collection is empty; otherwise returns \c false.
*/
bool QRangeCollection::isEmpty() const
{
Q_D(const QRangeCollection);
return d->intervals.isEmpty();
}
/*!
Returns the index of the first page covered by the range collection.
*/
int QRangeCollection::firstPage() const
{
Q_D(const QRangeCollection);
if (d->intervals.isEmpty())
return 0;
return d->intervals.first().first;
}
/*!
Returns the index of the last page covered by the range collection.
*/
int QRangeCollection::lastPage() const
{
Q_D(const QRangeCollection);
if (d->intervals.isEmpty())
return 0;
return d->intervals.last().second;
}
QT_END_NAMESPACE

View File

@ -1916,8 +1916,6 @@ void QTextDocument::print(QPagedPaintDevice *printer) const
bool documentPaginated = d->pageSize.isValid() && !d->pageSize.isNull()
&& d->pageSize.height() != INT_MAX;
QPagedPaintDevicePrivate *pd = QPagedPaintDevicePrivate::get(printer);
// ### set page size to paginated size?
QMarginsF m = printer->pageLayout().margins(QPageLayout::Millimeter);
if (!documentPaginated && m.left() == 0. && m.right() == 0. && m.top() == 0. && m.bottom() == 0.) {
@ -2003,9 +2001,9 @@ void QTextDocument::print(QPagedPaintDevice *printer) const
clonedDoc->setPageSize(body.size());
}
QRangeCollection *rangeCollection = pd->rangeCollection;
int fromPage = rangeCollection->firstPage();
int toPage = rangeCollection->lastPage();
const QPageRanges pageRanges = printer->pageRanges();
int fromPage = pageRanges.firstPage();
int toPage = pageRanges.lastPage();
if (fromPage == 0 && toPage == 0) {
fromPage = 1;
@ -2031,7 +2029,7 @@ void QTextDocument::print(QPagedPaintDevice *printer) const
int page = fromPage;
while (true) {
if (rangeCollection->isEmpty() || rangeCollection->contains(page))
if (pageRanges.isEmpty() || pageRanges.contains(page))
printPage(page, &p, doc, body, pageNumberPos);
if (page == toPage)

View File

@ -59,7 +59,6 @@
#include <QtWidgets/qstyleditemdelegate.h>
#include <QtWidgets/qformlayout.h>
#include <QtPrintSupport/qprinter.h>
#include <QtGui/qrangecollection.h>
#include <qpa/qplatformprintplugin.h>
#include <qpa/qplatformprintersupport.h>
@ -818,11 +817,14 @@ void QPrintDialogPrivate::setupPrinter()
#if QT_CONFIG(cups)
if (options.pagesRadioButton->isChecked()) {
p->setPrintRange(QPrinter::PageRange);
p->rangeCollection()->parse(options.pagesLineEdit->text());
const QPageRanges ranges = QPageRanges::fromString(options.pagesLineEdit->text());
if (!ranges.isEmpty()) {
p->setPrintRange(QPrinter::PageRange);
p->setPageRanges(ranges);
}
// server-side page filtering
QCUPSSupport::setPageRange(p, p->rangeCollection()->toString());
QCUPSSupport::setPageRange(p, ranges.toString());
}
// page set
@ -1022,7 +1024,7 @@ void QPrintDialog::accept()
{
Q_D(QPrintDialog);
#if QT_CONFIG(cups)
if (d->options.pagesRadioButton->isChecked() && printer()->rangeCollection()->isEmpty()) {
if (d->options.pagesRadioButton->isChecked() && printer()->pageRanges().isEmpty()) {
QMessageBox::critical(this, tr("Invalid Pages Definition"),
tr("%1 does not follow the correct syntax. Please use ',' to separate "
"ranges and pages, '-' to define ranges and make sure ranges do "

View File

@ -49,7 +49,6 @@
#include "qlist.h"
#include <qcoreapplication.h>
#include <qfileinfo.h>
#include <QtGui/qrangecollection.h>
#include <private/qpagedpaintdevice_p.h>
@ -1393,12 +1392,12 @@ void QPrinter::setPrinterSelectionOption(const QString &option)
\note If fromPage() and toPage() both return 0, this indicates that
\e{the whole document will be printed}.
\sa setFromTo(), toPage(), rangeCollection()
\sa setFromTo(), toPage(), pageRanges()
*/
int QPrinter::fromPage() const
{
return d->rangeCollection->firstPage();
return d->pageRanges.firstPage();
}
/*!
@ -1417,12 +1416,12 @@ int QPrinter::fromPage() const
The programmer is responsible for reading this setting and
printing accordingly.
\sa setFromTo(), fromPage(), rangeCollection()
\sa setFromTo(), fromPage(), pageRanges()
*/
int QPrinter::toPage() const
{
return d->rangeCollection->lastPage();
return d->pageRanges.lastPage();
}
/*!
@ -1439,25 +1438,13 @@ int QPrinter::toPage() const
This function is mostly used to set a default value that the user can
override in the print dialog when you call setup().
\sa fromPage(), toPage(), rangeCollection()
\sa fromPage(), toPage(), pageRanges()
*/
void QPrinter::setFromTo(int from, int to)
{
d->rangeCollection->clear();
d->rangeCollection->addRange(from, to);
}
/*!
\since 6.0
Returns the range collection associated with this device.
\sa QRangeCollection, fromPage(), toPage()
*/
QRangeCollection *QPrinter::rangeCollection()
{
return d->rangeCollection;
d->pageRanges.clear();
d->pageRanges.addRange(from, to);
}
/*!

View File

@ -44,7 +44,6 @@
#include <QtCore/qstring.h>
#include <QtCore/qscopedpointer.h>
#include <QtGui/qpagedpaintdevice.h>
#include <QtGui/qpagelayout.h>
QT_BEGIN_NAMESPACE
@ -56,7 +55,6 @@ QT_BEGIN_NAMESPACE
#endif
class QPrinterPrivate;
class QRangeCollection;
class QPaintEngine;
class QPrintEngine;
class QPrinterInfo;
@ -201,8 +199,6 @@ public:
int fromPage() const;
int toPage() const;
QRangeCollection *rangeCollection();
void setPrintRange(PrintRange range);
PrintRange printRange() const;

View File

@ -6,12 +6,12 @@ add_subdirectory(qcolor)
add_subdirectory(qbrush)
add_subdirectory(qregion)
add_subdirectory(qpagelayout)
add_subdirectory(qpageranges)
add_subdirectory(qpagesize)
add_subdirectory(qpainter)
add_subdirectory(qpdfwriter)
add_subdirectory(qpen)
add_subdirectory(qpaintengine)
add_subdirectory(qrangecollection)
add_subdirectory(qtransform)
add_subdirectory(qpolygon)
# QTBUG-87669 # special case

View File

@ -7,13 +7,13 @@ SUBDIRS=\
qbrush \
qregion \
qpagelayout \
qpageranges \
qpagesize \
qpainter \
qpathclipper \
qpdfwriter \
qpen \
qpaintengine \
qrangecollection \
qtransform \
qpolygon \

View File

@ -1,12 +1,12 @@
# Generated from qrangecollection.pro.
# Generated from qpageranges.pro.
#####################################################################
## tst_qrangecollection Test:
## tst_qpageranges Test:
#####################################################################
qt_internal_add_test(tst_qrangecollection
qt_internal_add_test(tst_qpageranges
SOURCES
tst_qrangecollection.cpp
tst_qpageranges.cpp
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui

View File

@ -0,0 +1,6 @@
CONFIG += testcase
TARGET = tst_qpageranges
QT += testlib gui-private core-private
SOURCES += tst_qpageranges.cpp

View File

@ -0,0 +1,183 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** 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 General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** 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-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <qpageranges.h>
typedef QList<QPageRanges::Range> PageRangeList;
class tst_QPageRanges : public QObject
{
Q_OBJECT
private slots:
void basics();
void addPage_data();
void addPage();
void addRange_data();
void addRange();
void fromToString_data();
void fromToString();
};
void tst_QPageRanges::basics()
{
QPageRanges empty;
QVERIFY(empty.isEmpty());
QVERIFY(!empty.contains(0));
QCOMPARE(empty.firstPage(), 0);
QCOMPARE(empty.lastPage(), 0);
QPageRanges single;
single.addPage(1);
QVERIFY(!single.isEmpty());
QVERIFY(single.contains(1));
QCOMPARE(single.firstPage(), 1);
QCOMPARE(single.firstPage(), 1);
QPageRanges copy(single);
QCOMPARE(copy, single);
QPageRanges moved(std::move(copy));
QCOMPARE(moved, single);
QVERIFY(copy.isEmpty());
single.clear();
QVERIFY(single.isEmpty());
QVERIFY(!moved.isEmpty());
}
void tst_QPageRanges::addPage_data()
{
QTest::addColumn<QList<int>>("pageNumbers");
QTest::addColumn<PageRangeList>("expected");
QTest::newRow("single") << QList<int>{5} << PageRangeList{{5, 5}};
QTest::newRow("duplicate") << QList<int>{5, 5} << PageRangeList{{5, 5}};
QTest::newRow("adjacent") << QList<int>{5, 6, 7} << PageRangeList{{5, 7}};
QTest::newRow("separate") << QList<int>{1, 3, 5} << PageRangeList{{1, 1}, {3, 3}, {5, 5}};
QTest::newRow("unsorted") << QList<int>{5, 3, 4, 1} << PageRangeList{{1, 1}, {3, 5}};
QTest::newRow("invalid") << QList<int>{-1} << PageRangeList{};
}
void tst_QPageRanges::addPage()
{
QFETCH(QList<int>, pageNumbers);
QFETCH(PageRangeList, expected);
QPageRanges result;
for (int pageNumber : qAsConst(pageNumbers)) {
if (QByteArrayView(QTest::currentDataTag()) == "invalid")
QTest::ignoreMessage(QtWarningMsg, "QPageRanges::addPage: 'pageNumber' must be greater than 0");
result.addPage(pageNumber);
}
QCOMPARE(result.toRangeList(), expected);
}
void tst_QPageRanges::addRange_data()
{
QTest::addColumn<PageRangeList>("ranges");
QTest::addColumn<PageRangeList>("expected");
QTest::newRow("single") << PageRangeList{{5, 5}}
<< PageRangeList{{5, 5}};
QTest::newRow("duplicate") << PageRangeList{{5, 5}, {5, 5}}
<< PageRangeList{{5, 5}};
QTest::newRow("adjacent") << PageRangeList{{1, 3}, {4, 6}, {7, 10}}
<< PageRangeList{{1, 10}};
QTest::newRow("separate") << PageRangeList{{1, 2}, {4, 5}, {7, 8}}
<< PageRangeList{{1, 2}, {4, 5}, {7, 8}};
QTest::newRow("overlap") << PageRangeList{{1, 5}, {4, 8}, {8, 10}}
<< PageRangeList{{1, 10}};
QTest::newRow("included") << PageRangeList{{1, 5}, {2, 3}, {8, 9}, {7, 10}}
<< PageRangeList{{1, 5}, {7, 10}};
QTest::newRow("unsorted") << PageRangeList{{7, 8}, {1, 4}, {9, 10}}
<< PageRangeList{{1, 4}, {7, 10}};
QTest::newRow("flipped") << PageRangeList{{5, 1}}
<< PageRangeList{{1, 5}};
QTest::newRow("invalid1") << PageRangeList{{-1, 2}}
<< PageRangeList{};
QTest::newRow("invalid2") << PageRangeList{{0, -1}}
<< PageRangeList{};
}
void tst_QPageRanges::addRange()
{
QFETCH(PageRangeList, ranges);
QFETCH(PageRangeList, expected);
QPageRanges result;
for (const auto &range : qAsConst(ranges)) {
const QByteArrayView testdata(QTest::currentDataTag());
if (testdata.startsWith("invalid"))
QTest::ignoreMessage(QtWarningMsg, "QPageRanges::addRange: 'from' and 'to' must be greater than 0");
result.addRange(range.from, range.to);
}
QCOMPARE(result.toRangeList(), expected);
}
void tst_QPageRanges::fromToString_data()
{
QTest::addColumn<QString>("fromString");
QTest::addColumn<PageRangeList>("rangeList");
QTest::addColumn<QString>("toString");
QTest::newRow("invalid") << QString(",-8")
<< PageRangeList{}
<< QString();
QTest::newRow("overlapping") << QString("1-3,5-9,6-7,8-11")
<< PageRangeList{{1, 3}, {5, 11}}
<< QString("1-3,5-11");
QTest::newRow("spacy") << QString("1 -2, 3- 4 ,\t5-6\t,7 - 8 ,\n9 - 10")
<< PageRangeList{{1, 10}}
<< QString("1-10");
}
void tst_QPageRanges::fromToString()
{
QFETCH(QString, fromString);
QFETCH(PageRangeList, rangeList);
QFETCH(QString, toString);
QPageRanges ranges = QPageRanges::fromString(fromString);
QCOMPARE(ranges.toRangeList(), rangeList);
QCOMPARE(ranges.toString(), toString);
}
QTEST_APPLESS_MAIN(tst_QPageRanges)
#include "tst_qpageranges.moc"

View File

@ -1,6 +0,0 @@
CONFIG += testcase
TARGET = tst_qrangecollection
QT += testlib gui-private core-private
SOURCES += tst_qrangecollection.cpp

View File

@ -1,75 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** 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 General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** 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-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <qrangecollection.h>
typedef QList<QPair<int, int>> PageRangeList;
class tst_QRangeCollection : public QObject
{
Q_OBJECT
private slots:
void parseFromString_data();
void parseFromString();
};
void tst_QRangeCollection::parseFromString_data()
{
QTest::addColumn<QString>("rangeString");
QTest::addColumn<QList<QPair<int, int>>>("rangeList");
QList<QPair<int, int>> invalid;
QTest::newRow("invalid") << QString(",-8")
<< invalid;
QList<QPair<int, int>> overlapping;
overlapping << qMakePair(1, 3)
<< qMakePair(5, 11);
QTest::newRow("overlapping") << QString("1-3,5-9,6-7,8-11")
<< overlapping;
}
void tst_QRangeCollection::parseFromString()
{
QFETCH(QString, rangeString);
QFETCH(PageRangeList, rangeList);
QRangeCollection rangeCollection;
rangeCollection.parse(rangeString);
QList<QPair<int, int>> result = rangeCollection.toList();
QCOMPARE(result.length(), rangeList.length());
for (const QPair<int, int> &pair : result) {
QVERIFY(rangeList.contains(pair));
}
}
QTEST_APPLESS_MAIN(tst_QRangeCollection)
#include "tst_qrangecollection.moc"