/**************************************************************************** ** ** 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 #include #include QT_BEGIN_NAMESPACE void QPageRangesPrivate::mergeIntervals() { const int count = intervals.count(); if (count <= 1) return; std::sort(intervals.begin(), intervals.end()); QStack 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::toRangeList() const { if (d) return d->intervals; return QList{}; } /*! 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 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); } #if !defined(QT_NO_DATASTREAM) /*! \fn QDataStream &operator<<(QDataStream &stream, const QPageRanges &pageRanges) \relates QPageRanges Writes \a pageRanges to \a stream as a range string. \sa QPageRanges::toString */ QDataStream &operator<<(QDataStream &s, const QPageRanges &pageRanges) { s << pageRanges.toString(); return s; } /*! \fn QDataStream &operator>>(QDataStream &stream, QPageRanges &pageRanges) \relates QPageRanges Reads a page ranges string from \a stream and stores it in \a pageRanges. \sa QPageRanges::fromString */ QDataStream &operator>>(QDataStream &s, QPageRanges &pageRanges) { QString rangesString; s >> rangesString; pageRanges = QPageRanges::fromString(rangesString); return s; } #endif // QT_NO_DATASTREAM #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