summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2022-05-30 17:36:55 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2023-02-16 06:57:23 +0100
commitb8419577eb99c1589768d55ddfdc136818df87ae (patch)
tree64c90b32d6d6aea84f01c2300f90e38b42bc5b3c
parentb385e76b1fc60ce1f48d2b805a4a2d2a2b23d1bd (diff)
Add QPdfPageSelector
This is a QSpinBox subclass that shows PDF page "labels" rather than a 1-based or 0-based page index. If a book starts with Roman numerals in the preface, and then page 1 is the first page of Chapter 1, the spinbox should be in sync with the page numbers as printed on the pages, and with the labels that will eventually be shown under the thumbnails on the Pages sidebar tab. On the other hand, the user probably needs to see the 1-based page index somewhere, at least to be able to make sense of the print dialog, because there the range of pages to print will be 1-based. So we put the page index into the title bar: title, page label, index, count. Task-number: QTBUG-102271 Change-Id: Ic461094ba4caae3067409f7f436bd4e7504a4bdb Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
-rw-r--r--examples/pdfwidgets/pdfviewer/mainwindow.cpp17
-rw-r--r--examples/pdfwidgets/pdfviewer/mainwindow.h3
-rw-r--r--src/pdf/qpdfdocument.cpp17
-rw-r--r--src/pdf/qpdfdocument.h1
-rw-r--r--src/pdfwidgets/CMakeLists.txt1
-rw-r--r--src/pdfwidgets/qpdfpageselector.cpp105
-rw-r--r--src/pdfwidgets/qpdfpageselector.h44
-rw-r--r--src/pdfwidgets/qpdfpageselector_p.h42
8 files changed, 222 insertions, 8 deletions
diff --git a/examples/pdfwidgets/pdfviewer/mainwindow.cpp b/examples/pdfwidgets/pdfviewer/mainwindow.cpp
index 02caffa48..d7527a8d5 100644
--- a/examples/pdfwidgets/pdfviewer/mainwindow.cpp
+++ b/examples/pdfwidgets/pdfviewer/mainwindow.cpp
@@ -8,10 +8,10 @@
#include <QFileDialog>
#include <QMessageBox>
-#include <QSpinBox>
#include <QPdfBookmarkModel>
#include <QPdfDocument>
#include <QPdfPageNavigator>
+#include <QPdfPageSelector>
#include <QStandardPaths>
#include <QtMath>
@@ -23,7 +23,7 @@ MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, m_zoomSelector(new ZoomSelector(this))
- , m_pageSelector(new QSpinBox(this))
+ , m_pageSelector(new QPdfPageSelector(this))
, m_document(new QPdfDocument(this))
{
ui->setupUi(this);
@@ -32,9 +32,10 @@ MainWindow::MainWindow(QWidget *parent)
ui->mainToolBar->insertWidget(ui->actionZoom_In, m_zoomSelector);
ui->mainToolBar->insertWidget(ui->actionForward, m_pageSelector);
- connect(m_pageSelector, &QSpinBox::valueChanged, this, &MainWindow::pageSelected);
+ connect(m_pageSelector, &QPdfPageSelector::valueChanged, this, &MainWindow::pageSelected);
+ m_pageSelector->setDocument(m_document);
auto nav = ui->pdfView->pageNavigator();
- connect(nav, &QPdfPageNavigator::currentPageChanged, m_pageSelector, &QSpinBox::setValue);
+ connect(nav, &QPdfPageNavigator::currentPageChanged, m_pageSelector, &QPdfPageSelector::setValue);
connect(nav, &QPdfPageNavigator::backAvailableChanged, ui->actionBack, &QAction::setEnabled);
connect(nav, &QPdfPageNavigator::forwardAvailableChanged, ui->actionForward, &QAction::setEnabled);
@@ -65,10 +66,7 @@ void MainWindow::open(const QUrl &docLocation)
{
if (docLocation.isLocalFile()) {
m_document->load(docLocation.toLocalFile());
- const auto documentTitle = m_document->metaData(QPdfDocument::MetaDataField::Title).toString();
- setWindowTitle(!documentTitle.isEmpty() ? documentTitle : QStringLiteral("PDF Viewer"));
pageSelected(0);
- m_pageSelector->setMaximum(m_document->pageCount() - 1);
} else {
const QString message = tr("%1 is not a valid local file").arg(docLocation.toString());
qCDebug(lcExample).noquote() << message;
@@ -91,6 +89,11 @@ void MainWindow::pageSelected(int page)
{
auto nav = ui->pdfView->pageNavigator();
nav->jump(page, {}, nav->currentZoom());
+ const auto documentTitle = m_document->metaData(QPdfDocument::MetaDataField::Title).toString();
+ setWindowTitle(!documentTitle.isEmpty() ? documentTitle : QStringLiteral("PDF Viewer"));
+ setWindowTitle(tr("%1: page %2 (%3 of %4)")
+ .arg(documentTitle.isEmpty() ? u"PDF Viewer"_qs : documentTitle,
+ m_pageSelector->text(), QString::number(page + 1), QString::number(m_document->pageCount())));
}
void MainWindow::on_actionOpen_triggered()
diff --git a/examples/pdfwidgets/pdfviewer/mainwindow.h b/examples/pdfwidgets/pdfviewer/mainwindow.h
index 958e11061..2827fb2b6 100644
--- a/examples/pdfwidgets/pdfviewer/mainwindow.h
+++ b/examples/pdfwidgets/pdfviewer/mainwindow.h
@@ -16,6 +16,7 @@ class MainWindow;
class QFileDialog;
class QPdfDocument;
+class QPdfPageSelector;
class QPdfView;
class QSpinBox;
QT_END_NAMESPACE
@@ -53,7 +54,7 @@ private slots:
private:
Ui::MainWindow *ui;
ZoomSelector *m_zoomSelector;
- QSpinBox *m_pageSelector;
+ QPdfPageSelector *m_pageSelector;
QFileDialog *m_fileDialog = nullptr;
QPdfDocument *m_document;
diff --git a/src/pdf/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp
index 268389f4a..a6aed4bfe 100644
--- a/src/pdf/qpdfdocument.cpp
+++ b/src/pdf/qpdfdocument.cpp
@@ -783,6 +783,8 @@ QAbstractListModel *QPdfDocument::pageModel()
If the document does not have custom page numbering, this function returns
\c {page + 1}.
+
+ \sa pageIndexForLabel()
*/
QString QPdfDocument::pageLabel(int page)
{
@@ -797,6 +799,21 @@ QString QPdfDocument::pageLabel(int page)
}
/*!
+ Returns the index of the page that has the \a label, or \c -1 if not found.
+
+ \sa pageLabel()
+*/
+int QPdfDocument::pageIndexForLabel(const QString &label)
+{
+ const auto trimmed = label.trimmed();
+ for (int i = 0; i < d->pageCount; ++i) {
+ if (pageLabel(i) == trimmed)
+ return i;
+ }
+ return -1;
+}
+
+/*!
Renders the \a page into a QImage of size \a imageSize according to the
provided \a renderOptions.
diff --git a/src/pdf/qpdfdocument.h b/src/pdf/qpdfdocument.h
index 5f55ed29c..8355246ae 100644
--- a/src/pdf/qpdfdocument.h
+++ b/src/pdf/qpdfdocument.h
@@ -89,6 +89,7 @@ public:
Q_INVOKABLE QSizeF pagePointSize(int page) const;
Q_INVOKABLE QString pageLabel(int page);
+ Q_INVOKABLE int pageIndexForLabel(const QString &label);
QAbstractListModel *pageModel();
diff --git a/src/pdfwidgets/CMakeLists.txt b/src/pdfwidgets/CMakeLists.txt
index d374315e3..592409b66 100644
--- a/src/pdfwidgets/CMakeLists.txt
+++ b/src/pdfwidgets/CMakeLists.txt
@@ -5,6 +5,7 @@ find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Core Gui Widgets)
qt_internal_add_module(PdfWidgets
SOURCES
+ qpdfpageselector.cpp qpdfpageselector.h qpdfpageselector_p.h
qpdfview.cpp qpdfview.h qpdfview_p.h
qtpdfwidgetsglobal.h
LIBRARIES
diff --git a/src/pdfwidgets/qpdfpageselector.cpp b/src/pdfwidgets/qpdfpageselector.cpp
new file mode 100644
index 000000000..72ab28355
--- /dev/null
+++ b/src/pdfwidgets/qpdfpageselector.cpp
@@ -0,0 +1,105 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qpdfpageselector.h"
+#include "qpdfpageselector_p.h"
+
+#include <QPdfDocument>
+
+QT_BEGIN_NAMESPACE
+
+QPdfPageSelectorPrivate::QPdfPageSelectorPrivate(QPdfPageSelector *q)
+ : q_ptr(q)
+{
+}
+
+void QPdfPageSelectorPrivate::documentStatusChanged()
+{
+ Q_Q(QPdfPageSelector);
+ if (!document.isNull() && document->status() == QPdfDocument::Status::Ready) {
+ q->setMaximum(document->pageCount());
+ q->setValue(0);
+ }
+}
+
+/*!
+ \class QPdfPageSelector
+ \inmodule QtPdf
+ \brief A QSpinBox for selecting a PDF page.
+
+ QPdfPageSelector is a QSpinBox specialized for selecting a page label
+ from a QPdfDocument.
+
+ \sa QPdfDocument::pageLabel()
+*/
+
+/*!
+ Constructs a PDF page selector with parent widget \a parent.
+*/
+QPdfPageSelector::QPdfPageSelector(QWidget *parent)
+ : QSpinBox(parent)
+ , d_ptr(new QPdfPageSelectorPrivate(this))
+{
+}
+
+/*!
+ Destroys the page selector.
+*/
+QPdfPageSelector::~QPdfPageSelector()
+{
+}
+
+/*!
+ \property QPdfPageSelector::document
+
+ This property holds the document to be viewed.
+*/
+void QPdfPageSelector::setDocument(QPdfDocument *document)
+{
+ Q_D(QPdfPageSelector);
+
+ if (d->document == document)
+ return;
+
+ if (d->document)
+ disconnect(d->documentStatusChangedConnection);
+
+ d->document = document;
+ emit documentChanged(d->document);
+
+ if (d->document)
+ d->documentStatusChangedConnection =
+ connect(d->document.data(), &QPdfDocument::statusChanged, this,
+ [d](){ d->documentStatusChanged(); });
+
+ d->documentStatusChanged();
+}
+
+QPdfDocument *QPdfPageSelector::document() const
+{
+ Q_D(const QPdfPageSelector);
+
+ return d->document;
+}
+
+int QPdfPageSelector::valueFromText(const QString &text) const
+{
+ Q_D(const QPdfPageSelector);
+ if (d->document.isNull())
+ return 0;
+
+ return d->document->pageIndexForLabel(text);
+}
+
+QString QPdfPageSelector::textFromValue(int value) const
+{
+ Q_D(const QPdfPageSelector);
+ if (d->document.isNull())
+ return {};
+
+ return d->document->pageLabel(value);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qpdfpageselector.cpp"
diff --git a/src/pdfwidgets/qpdfpageselector.h b/src/pdfwidgets/qpdfpageselector.h
new file mode 100644
index 000000000..bc2e352f7
--- /dev/null
+++ b/src/pdfwidgets/qpdfpageselector.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPDFPAGESELECTOR_H
+#define QPDFPAGESELECTOR_H
+
+#include <QtPdfWidgets/qtpdfwidgetsglobal.h>
+#include <QtWidgets/qspinbox.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfDocument;
+class QPdfPageNavigator;
+class QPdfPageSelectorPrivate;
+
+class Q_PDF_WIDGETS_EXPORT QPdfPageSelector : public QSpinBox
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged)
+
+public:
+ QPdfPageSelector() : QPdfPageSelector(nullptr) {}
+ explicit QPdfPageSelector(QWidget *parent);
+ ~QPdfPageSelector();
+
+ void setDocument(QPdfDocument *document);
+ QPdfDocument *document() const;
+
+Q_SIGNALS:
+ void documentChanged(QPdfDocument *document);
+
+protected:
+ int valueFromText(const QString &text) const override;
+ QString textFromValue(int value) const override;
+
+private:
+ Q_DECLARE_PRIVATE(QPdfPageSelector)
+ QScopedPointer<QPdfPageSelectorPrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFPAGESELECTOR_H
diff --git a/src/pdfwidgets/qpdfpageselector_p.h b/src/pdfwidgets/qpdfpageselector_p.h
new file mode 100644
index 000000000..b2cd6ecf7
--- /dev/null
+++ b/src/pdfwidgets/qpdfpageselector_p.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPDFPAGESELECTOR_P_H
+#define QPDFPAGESELECTOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qpdfpageselector.h"
+
+#include <QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfPageRenderer;
+
+class QPdfPageSelectorPrivate
+{
+ Q_DECLARE_PUBLIC(QPdfPageSelector)
+
+public:
+ QPdfPageSelectorPrivate(QPdfPageSelector *q);
+
+ void documentStatusChanged();
+
+ QPdfPageSelector *q_ptr;
+ QPointer<QPdfDocument> document;
+ QMetaObject::Connection documentStatusChangedConnection;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFPAGESELECTOR_P_H