diff options
Diffstat (limited to 'src/pdf')
49 files changed, 1541 insertions, 2351 deletions
diff --git a/src/pdf/CMakeLists.txt b/src/pdf/CMakeLists.txt index cdc9e60cb..ed2da1032 100644 --- a/src/pdf/CMakeLists.txt +++ b/src/pdf/CMakeLists.txt @@ -15,17 +15,16 @@ set(buildDir "${CMAKE_CURRENT_BINARY_DIR}") qt_internal_add_module(Pdf SOURCES qpdfbookmarkmodel.cpp qpdfbookmarkmodel.h - qpdfdestination.cpp qpdfdestination.h qpdfdestination_p.h qpdfdocument.cpp qpdfdocument.h qpdfdocument_p.h qpdfdocumentrenderoptions.h + qpdffile.cpp qpdffile_p.h + qpdflink.cpp qpdflink.h qpdflink_p.h qpdflinkmodel.cpp qpdflinkmodel_p.h qpdflinkmodel_p_p.h - qpdfpagenavigation.cpp qpdfpagenavigation.h + qpdfpagenavigator.cpp qpdfpagenavigator.h qpdfpagerenderer.cpp qpdfpagerenderer.h qpdfsearchmodel.cpp qpdfsearchmodel.h qpdfsearchmodel_p.h - qpdfsearchresult.cpp qpdfsearchresult.h qpdfsearchresult_p.h qpdfselection.cpp qpdfselection.h qpdfselection_p.h qtpdfglobal.h - qpdfnamespace.h INCLUDE_DIRECTORIES ../3rdparty/chromium DEFINES @@ -113,11 +112,14 @@ foreach(arch ${archs}) ) if(LINUX) - list(APPEND gnArgArg - use_x11=false - is_cfi=false - ozone_auto_platforms=false - use_gnome_keyring=false) + list(APPEND gnArgArg + is_cfi=false + ozone_auto_platforms=false + use_gnome_keyring=false) + extend_gn_list(gnArgArg + ARGS use_system_icu + CONDITION QT_FEATURE_webengine_system_icu + ) endif() if(MACOS) list(APPEND gnArgArg angle_enable_vulkan=false) diff --git a/src/pdf/configure/BUILD.root.gn.in b/src/pdf/configure/BUILD.root.gn.in index 68089f8cf..5420e8581 100644 --- a/src/pdf/configure/BUILD.root.gn.in +++ b/src/pdf/configure/BUILD.root.gn.in @@ -16,6 +16,7 @@ config("qt_harfbuzz_config") { } config("qt_freetype_config") { visibility = [ + "//build/config/freetype:freetype", "//third_party:freetype_harfbuzz", "//third_party/harfbuzz-ng:harfbuzz_source", ] diff --git a/src/pdf/doc/images/search-results.png b/src/pdf/doc/images/search-results.png Binary files differnew file mode 100644 index 000000000..91ee53b83 --- /dev/null +++ b/src/pdf/doc/images/search-results.png diff --git a/src/pdf/doc/images/wrapping-search-result.png b/src/pdf/doc/images/wrapping-search-result.png Binary files differnew file mode 100644 index 000000000..108ec0444 --- /dev/null +++ b/src/pdf/doc/images/wrapping-search-result.png diff --git a/src/pdf/doc/qtpdf.qdocconf b/src/pdf/doc/qtpdf.qdocconf index 85d0a7c4d..d55f88a41 100644 --- a/src/pdf/doc/qtpdf.qdocconf +++ b/src/pdf/doc/qtpdf.qdocconf @@ -30,6 +30,8 @@ qhp.QtPdf.subprojects.examples.indexTitle = Qt PDF Examples qhp.QtPdf.subprojects.examples.selectors = doc:example qhp.QtPdf.subprojects.examples.sortPages = true +manifestmeta.highlighted.names += "QtPdf/PDF Multipage Viewer Example" + depends += qtcore \ qtwidgets \ qtgui \ @@ -37,12 +39,16 @@ depends += qtcore \ qmake \ qtdesigner \ qtquick \ - qtcmake + qtquickcontrols \ + qtcmake \ + qtsvg -headerdirs += ../ +headerdirs += ../ \ + ../../pdfwidgets sourcedirs += ../ \ - ../../pdfquick + ../../pdfquick \ + ../../pdfwidgets exampledirs += ../../../examples/pdfwidgets \ ../../../examples/pdf \ diff --git a/src/pdf/doc/snippets/multipageview.qml b/src/pdf/doc/snippets/multipageview.qml index ee695c03a..113444165 100644 --- a/src/pdf/doc/snippets/multipageview.qml +++ b/src/pdf/doc/snippets/multipageview.qml @@ -1,3 +1,6 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + //! [0] import QtQuick import QtQuick.Pdf diff --git a/src/pdf/doc/snippets/qtpdf_build_snippet.qdoc b/src/pdf/doc/snippets/qtpdf_build_snippet.qdoc index 25593b1ee..7d30ccdfd 100644 --- a/src/pdf/doc/snippets/qtpdf_build_snippet.qdoc +++ b/src/pdf/doc/snippets/qtpdf_build_snippet.qdoc @@ -1,35 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** 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 Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only //! [0] QT += pdf //! [0] - - -//! [1] -#include <QtPdf> -//! [1] diff --git a/src/pdf/doc/src/qtpdf-examples.qdoc b/src/pdf/doc/src/qtpdf-examples.qdoc index 9daa0e7f8..0ebad3c82 100644 --- a/src/pdf/doc/src/qtpdf-examples.qdoc +++ b/src/pdf/doc/src/qtpdf-examples.qdoc @@ -1,29 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** 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 Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! \group qtpdf-examples diff --git a/src/pdf/doc/src/qtpdf-index.qdoc b/src/pdf/doc/src/qtpdf-index.qdoc index 423a46873..07c151f47 100644 --- a/src/pdf/doc/src/qtpdf-index.qdoc +++ b/src/pdf/doc/src/qtpdf-index.qdoc @@ -1,29 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** 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 Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! \page qtpdf-index.html @@ -36,8 +12,34 @@ and renders pages from it according to the options provided by the \l QPdfDocumentRenderOptions class. The \l QPdfPageRenderer class manages a queue that collects all render requests. The - \l QPdfPageNavigation class handles the navigation through a - PDF document. + \l QPdfPageNavigator class handles the navigation through a + PDF document. The \l QPdfSearchModel class searches for a string + and holds the search results. The QPdfBookmarkModel class holds the + table of contents, if present. The QPdfLinkModel holds information + about hyperlinks on a page. The \l QPdfView widget is a complete + PDF viewer, and the \l {PDF Viewer Example} shows how to use it. + + For Qt Quick applications, three kinds of full-featured viewer + components are provided. \l PdfMultiPageView should be your + first choice for the most common user experience: flicking + through the pages in the entire document. + \l PdfScrollablePageView shows one page at a time, with scrolling; + and \l PdfPageView shows one full page at a time, without scrolling. + + The full-featured viewer components are composed of lower-level + QML components that can be used separately if you need to write a + more customized PDF viewing application: \l PdfDocument, + \l PdfPageImage, \l PdfPageNavigator, \l PdfSelection, + \l PdfSearchModel, \l PdfLinkModel, and \l PdfBookmarkModel. + + If you only need to render page images, without features such as + text selection, search and navigation, this module includes a + \l QImageIOHandler plugin that treats PDF as a scalable + \l {Qt Image Formats}{image format}, similar to \l {Qt SVG}{SVG}. + You can simply use \l Image, and set the + \l {Image::currentFrame}{currentFrame} property to the page index + that you wish to display. If the PDF file does not render its own + background, the image has a transparent background. \include module-use.qdocinc using qt module \quotefile qtpdf-build.cmake @@ -46,11 +48,6 @@ \section2 Building with qmake - To include the definitions of the module's classes, use the - following directive: - - \snippet qtpdf_build_snippet.qdoc 1 - To link against the module, add this line to your qmake project file: \snippet qtpdf_build_snippet.qdoc 0 diff --git a/src/pdf/doc/src/qtpdf-module.qdoc b/src/pdf/doc/src/qtpdf-module.qdoc index 4170deb38..e2ca8e4ce 100644 --- a/src/pdf/doc/src/qtpdf-module.qdoc +++ b/src/pdf/doc/src/qtpdf-module.qdoc @@ -1,29 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** 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 Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! @@ -37,11 +13,6 @@ The Qt PDF module contains classes and functions for rendering PDF documents. - To include the definitions of the module's classes, use the - following directive: - - \snippet qtpdf_build_snippet.qdoc 1 - \if !defined(qtforpython) To link against the module, add this line to your qmake project file: diff --git a/src/pdf/plugins/imageformats/pdf/main.cpp b/src/pdf/plugins/imageformats/pdf/main.cpp index c5ad4da0c..cb69c4ca1 100644 --- a/src/pdf/plugins/imageformats/pdf/main.cpp +++ b/src/pdf/plugins/imageformats/pdf/main.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2019 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 "qpdfiohandler_p.h" diff --git a/src/pdf/plugins/imageformats/pdf/qpdfiohandler.cpp b/src/pdf/plugins/imageformats/pdf/qpdfiohandler.cpp index 76b38ce82..195759028 100644 --- a/src/pdf/plugins/imageformats/pdf/qpdfiohandler.cpp +++ b/src/pdf/plugins/imageformats/pdf/qpdfiohandler.cpp @@ -1,45 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2019 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 "qpdfiohandler_p.h" #include <QLoggingCategory> #include <QPainter> +#include <QtPdf/private/qpdffile_p.h> QT_BEGIN_NAMESPACE @@ -49,6 +14,12 @@ QPdfIOHandler::QPdfIOHandler() { } +QPdfIOHandler::~QPdfIOHandler() +{ + if (m_ownsDocument) + delete m_doc; +} + bool QPdfIOHandler::canRead() const { if (!device()) @@ -76,27 +47,27 @@ int QPdfIOHandler::currentImageNumber() const QRect QPdfIOHandler::currentImageRect() const { - return QRect(QPoint(0, 0), m_doc.pageSize(m_page).toSize()); + return QRect(QPoint(0, 0), m_doc->pagePointSize(m_page).toSize()); } int QPdfIOHandler::imageCount() const { int ret = 0; if (const_cast<QPdfIOHandler *>(this)->load(device())) - ret = m_doc.pageCount(); - qCDebug(qLcPdf) << "imageCount" << ret; + ret = m_doc->pageCount(); + qCDebug(qLcPdf) << ret; return ret; } bool QPdfIOHandler::read(QImage *image) { if (load(device())) { - if (m_page >= m_doc.pageCount()) + if (m_page >= m_doc->pageCount()) return false; if (m_page < 0) m_page = 0; const bool xform = (m_clipRect.isValid() || m_scaledSize.isValid() || m_scaledClipRect.isValid()); - QSize pageSize = m_doc.pageSize(m_page).toSize(); + QSize pageSize = m_doc->pagePointSize(m_page).toSize(); QSize finalSize = pageSize; QRectF bounds; if (xform && !finalSize.isEmpty()) { @@ -123,7 +94,7 @@ bool QPdfIOHandler::read(QImage *image) t.translate(tr1.x(), tr1.y()); bounds = t.mapRect(bounds); } - qCDebug(qLcPdf) << Q_FUNC_INFO << m_page << finalSize; + qCDebug(qLcPdf) << m_page << finalSize; if (image->size() != finalSize || !image->reinterpretAsFormat(QImage::Format_ARGB32_Premultiplied)) { *image = QImage(finalSize, QImage::Format_ARGB32_Premultiplied); if (!finalSize.isEmpty() && image->isNull()) { @@ -139,7 +110,7 @@ bool QPdfIOHandler::read(QImage *image) options.setScaledSize(pageSize); image->fill(m_backColor.rgba()); QPainter p(image); - QImage pageImage = m_doc.render(m_page, finalSize, options); + QImage pageImage = m_doc->render(m_page, finalSize, options); p.drawImage(0, 0, pageImage); p.end(); } @@ -156,7 +127,7 @@ QVariant QPdfIOHandler::option(ImageOption option) const return QImage::Format_ARGB32_Premultiplied; case Size: const_cast<QPdfIOHandler *>(this)->load(device()); - return m_doc.pageSize(qMax(0, m_page)); + return m_doc->pagePointSize(qMax(0, m_page)); case ClipRect: return m_clipRect; case ScaledSize: @@ -166,7 +137,7 @@ QVariant QPdfIOHandler::option(ImageOption option) const case BackgroundColor: return m_backColor; case Name: - return m_doc.metaData(QPdfDocument::Title); + return m_doc->metaData(QPdfDocument::MetaDataField::Title); default: break; } @@ -213,7 +184,7 @@ bool QPdfIOHandler::supportsOption(ImageOption option) const bool QPdfIOHandler::jumpToImage(int frame) { - qCDebug(qLcPdf) << Q_FUNC_INFO << frame; + qCDebug(qLcPdf) << frame; if (frame < 0 || frame >= imageCount()) return false; m_page = frame; @@ -233,8 +204,18 @@ bool QPdfIOHandler::load(QIODevice *device) if (!canRead()) return false; - m_doc.load(device); - m_loaded = (m_doc.error() == QPdfDocument::DocumentError::NoError); + QPdfFile *pdfFile = qobject_cast<QPdfFile *>(device); + if (pdfFile) { + m_doc = pdfFile->document(); + m_ownsDocument = false; + qCDebug(qLcPdf) << "loading via QPdfFile, reusing document instance" << m_doc; + } else { + m_doc = new QPdfDocument(); + m_ownsDocument = true; + m_doc->load(device); + qCDebug(qLcPdf) << "loading via new document instance" << m_doc; + } + m_loaded = (m_doc->error() == QPdfDocument::Error::None); return m_loaded; } diff --git a/src/pdf/plugins/imageformats/pdf/qpdfiohandler_p.h b/src/pdf/plugins/imageformats/pdf/qpdfiohandler_p.h index 562909f06..5918c0328 100644 --- a/src/pdf/plugins/imageformats/pdf/qpdfiohandler_p.h +++ b/src/pdf/plugins/imageformats/pdf/qpdfiohandler_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2019 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 QPDFIOHANDLER_H #define QPDFIOHANDLER_H @@ -60,6 +24,7 @@ class QPdfIOHandler : public QImageIOHandler { public: QPdfIOHandler(); + ~QPdfIOHandler() override; bool canRead() const override; static bool canRead(QIODevice *device); int currentImageNumber() const override; @@ -76,7 +41,7 @@ private: bool load(QIODevice *device); private: - QPdfDocument m_doc; + QPdfDocument *m_doc = nullptr; int m_page = -1; QRect m_clipRect; @@ -84,6 +49,7 @@ private: QRect m_scaledClipRect; QColor m_backColor = Qt::transparent; bool m_loaded = false; + bool m_ownsDocument = false; }; QT_END_NAMESPACE diff --git a/src/pdf/qpdfbookmarkmodel.cpp b/src/pdf/qpdfbookmarkmodel.cpp index 8d8bb1973..7b984a300 100644 --- a/src/pdf/qpdfbookmarkmodel.cpp +++ b/src/pdf/qpdfbookmarkmodel.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2020 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 "qpdfbookmarkmodel.h" @@ -45,19 +9,21 @@ #include "third_party/pdfium/public/fpdf_doc.h" #include "third_party/pdfium/public/fpdfview.h" +#include <QLoggingCategory> +#include <QMetaEnum> #include <QPointer> #include <QScopedPointer> #include <private/qabstractitemmodel_p.h> QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(qLcBM, "qt.pdf.bookmarks") + class BookmarkNode { public: explicit BookmarkNode(BookmarkNode *parentNode = nullptr) : m_parentNode(parentNode) - , m_level(0) - , m_pageNumber(0) { } @@ -130,32 +96,49 @@ public: m_pageNumber = pageNumber; } + QPointF location() const + { + return m_location; + } + + void setLocation(qreal x, qreal y) + { + m_location = QPointF(x, y); + } + + qreal zoom() const + { + return m_zoom; + } + + void setZoom(qreal zoom) + { + m_zoom = zoom; + } + private: QList<BookmarkNode*> m_childNodes; BookmarkNode *m_parentNode; QString m_title; - int m_level; - int m_pageNumber; + int m_level = 0; + int m_pageNumber = 0; + QPointF m_location; + qreal m_zoom = 0; }; -class QPdfBookmarkModelPrivate : public QAbstractItemModelPrivate +struct QPdfBookmarkModelPrivate { -public: QPdfBookmarkModelPrivate() - : QAbstractItemModelPrivate() - , m_rootNode(new BookmarkNode(nullptr)) + : m_rootNode(new BookmarkNode(nullptr)) , m_document(nullptr) - , m_structureMode(QPdfBookmarkModel::TreeMode) { } void rebuild() { - Q_Q(QPdfBookmarkModel); - - const bool documentAvailable = (m_document && m_document->status() == QPdfDocument::Ready); + const bool documentAvailable = (m_document && m_document->status() == QPdfDocument::Status::Ready); if (documentAvailable) { q->beginResetModel(); @@ -182,13 +165,9 @@ public: while (bookmark) { BookmarkNode *childBookmarkNode = nullptr; - if (m_structureMode == QPdfBookmarkModel::TreeMode) { - childBookmarkNode = new BookmarkNode(parentBookmarkNode); - parentBookmarkNode->appendChild(childBookmarkNode); - } else if (m_structureMode == QPdfBookmarkModel::ListMode) { - childBookmarkNode = new BookmarkNode(m_rootNode.data()); - m_rootNode->appendChild(childBookmarkNode); - } + childBookmarkNode = new BookmarkNode(parentBookmarkNode); + parentBookmarkNode->appendChild(childBookmarkNode); + Q_ASSERT(childBookmarkNode); const int titleLength = int(FPDFBookmark_GetTitle(bookmark, nullptr, 0)); @@ -197,6 +176,28 @@ public: const FPDF_DEST dest = FPDFBookmark_GetDest(document, bookmark); const int pageNumber = FPDFDest_GetDestPageIndex(document, dest); + double pageHeight = 11.69 * 72; // A4 height + { + // get actual page height + const QPdfMutexLocker lock; + FPDF_PAGE pdfPage = FPDF_LoadPage(document, pageNumber); + if (pdfPage) + pageHeight = FPDF_GetPageHeight(pdfPage); + else + qCWarning(qLcBM) << "failed to load page" << pageNumber; + } + + FPDF_BOOL hasX, hasY, hasZoom; + FS_FLOAT x, y, zoom; + bool ok = FPDFDest_GetLocationInPage(dest, &hasX, &hasY, &hasZoom, &x, &y, &zoom); + if (ok) { + if (hasX && hasY) + childBookmarkNode->setLocation(x, pageHeight - y); + if (hasZoom) + childBookmarkNode->setZoom(zoom); + } else { + qCWarning(qLcBM) << "bookmark with invalid location and/or zoom" << x << y << zoom; + } childBookmarkNode->setTitle(QString::fromUtf16(titleBuffer.data())); childBookmarkNode->setLevel(level); @@ -214,32 +215,63 @@ public: rebuild(); } - Q_DECLARE_PUBLIC(QPdfBookmarkModel) + QPdfBookmarkModel *q = nullptr; QScopedPointer<BookmarkNode> m_rootNode; QPointer<QPdfDocument> m_document; - QPdfBookmarkModel::StructureMode m_structureMode; + QHash<int, QByteArray> m_roleNames; }; +/*! + \class QPdfBookmarkModel + \since 5.10 + \inmodule QtPdf + \inherits QAbstractItemModel + + \brief The QPdfBookmarkModel class holds a tree of of links (anchors) + within a PDF document, such as the table of contents. + + This is used in the \l {Model/View Programming} paradigm to display a + table of contents in the form of a tree or list. +*/ + +/*! + \enum QPdfBookmarkModel::Role + + \value Title The name of the bookmark for display. + \value Level The level of indentation. + \value Page The page number of the destination (int). + \value Location The position of the destination (QPointF). + \value Zoom The suggested zoom level (qreal). + \omitvalue NRoles +*/ + +/*! + Constructs a new bookmark model with parent object \a parent. +*/ QPdfBookmarkModel::QPdfBookmarkModel(QObject *parent) - : QAbstractItemModel(*new QPdfBookmarkModelPrivate, parent) + : QAbstractItemModel(parent), d(new QPdfBookmarkModelPrivate) { + d->q = this; + d->m_roleNames = QAbstractItemModel::roleNames(); + QMetaEnum rolesMetaEnum = metaObject()->enumerator(metaObject()->indexOfEnumerator("Role")); + for (int r = Qt::UserRole; r < int(Role::NRoles); ++r) + d->m_roleNames.insert(r, QByteArray(rolesMetaEnum.valueToKey(r)).toLower()); } +/*! + Destroys the model. +*/ QPdfBookmarkModel::~QPdfBookmarkModel() = default; QPdfDocument* QPdfBookmarkModel::document() const { - Q_D(const QPdfBookmarkModel); - return d->m_document; } void QPdfBookmarkModel::setDocument(QPdfDocument *document) { - Q_D(QPdfBookmarkModel); - if (d->m_document == document) return; @@ -255,65 +287,56 @@ void QPdfBookmarkModel::setDocument(QPdfDocument *document) d->rebuild(); } -QPdfBookmarkModel::StructureMode QPdfBookmarkModel::structureMode() const -{ - Q_D(const QPdfBookmarkModel); - - return d->m_structureMode; -} - -void QPdfBookmarkModel::setStructureMode(StructureMode mode) -{ - Q_D(QPdfBookmarkModel); - - if (d->m_structureMode == mode) - return; - - d->m_structureMode = mode; - emit structureModeChanged(d->m_structureMode); - - d->rebuild(); -} - +/*! + \reimp +*/ int QPdfBookmarkModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 1; } +/*! + \reimp +*/ QHash<int, QByteArray> QPdfBookmarkModel::roleNames() const { - QHash<int, QByteArray> names; - - names[TitleRole] = "title"; - names[LevelRole] = "level"; - names[PageNumberRole] = "pageNumber"; - - return names; + return d->m_roleNames; } +/*! + \reimp +*/ QVariant QPdfBookmarkModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); const BookmarkNode *node = static_cast<BookmarkNode*>(index.internalPointer()); - switch (role) { - case TitleRole: + switch (Role(role)) { + case Role::Title: return node->title(); - case LevelRole: + case Role::Level: return node->level(); - case PageNumberRole: + case Role::Page: return node->pageNumber(); - default: - return QVariant(); + case Role::Location: + return node->location(); + case Role::Zoom: + return node->zoom(); + case Role::NRoles: + break; } + if (role == Qt::DisplayRole) + return node->title(); + return QVariant(); } +/*! + \reimp +*/ QModelIndex QPdfBookmarkModel::index(int row, int column, const QModelIndex &parent) const { - Q_D(const QPdfBookmarkModel); - if (!hasIndex(row, column, parent)) return QModelIndex(); @@ -331,10 +354,11 @@ QModelIndex QPdfBookmarkModel::index(int row, int column, const QModelIndex &par return QModelIndex(); } +/*! + \reimp +*/ QModelIndex QPdfBookmarkModel::parent(const QModelIndex &index) const { - Q_D(const QPdfBookmarkModel); - if (!index.isValid()) return QModelIndex(); @@ -347,10 +371,11 @@ QModelIndex QPdfBookmarkModel::parent(const QModelIndex &index) const return createIndex(parentNode->row(), 0, parentNode); } +/*! + \reimp +*/ int QPdfBookmarkModel::rowCount(const QModelIndex &parent) const { - Q_D(const QPdfBookmarkModel); - if (parent.column() > 0) return 0; diff --git a/src/pdf/qpdfbookmarkmodel.h b/src/pdf/qpdfbookmarkmodel.h index 315222a65..5a3c24f84 100644 --- a/src/pdf/qpdfbookmarkmodel.h +++ b/src/pdf/qpdfbookmarkmodel.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2020 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 QPDFBOOKMARKMODEL_H #define QPDFBOOKMARKMODEL_H @@ -46,28 +10,23 @@ QT_BEGIN_NAMESPACE class QPdfDocument; -class QPdfBookmarkModelPrivate; +struct QPdfBookmarkModelPrivate; class Q_PDF_EXPORT QPdfBookmarkModel : public QAbstractItemModel { Q_OBJECT Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged) - Q_PROPERTY(StructureMode structureMode READ structureMode WRITE setStructureMode NOTIFY structureModeChanged) public: - enum StructureMode + enum class Role : int { - TreeMode, - ListMode - }; - Q_ENUM(StructureMode) - - enum Role - { - TitleRole = Qt::DisplayRole, - LevelRole = Qt::UserRole, - PageNumberRole + Title = Qt::UserRole, + Level, + Page, + Location, + Zoom, + NRoles }; Q_ENUM(Role) @@ -78,9 +37,6 @@ public: QPdfDocument* document() const; void setDocument(QPdfDocument *document); - StructureMode structureMode() const; - void setStructureMode(StructureMode mode); - QVariant data(const QModelIndex &index, int role) const override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &index) const override; @@ -90,12 +46,13 @@ public: Q_SIGNALS: void documentChanged(QPdfDocument *document); - void structureModeChanged(QPdfBookmarkModel::StructureMode structureMode); private: - Q_DECLARE_PRIVATE(QPdfBookmarkModel) + std::unique_ptr<QPdfBookmarkModelPrivate> d; + + Q_PRIVATE_SLOT(d, void _q_documentStatusChanged()) - Q_PRIVATE_SLOT(d_func(), void _q_documentStatusChanged()) + friend struct QPdfBookmarkModelPrivate; }; QT_END_NAMESPACE diff --git a/src/pdf/qpdfdestination.cpp b/src/pdf/qpdfdestination.cpp deleted file mode 100644 index 33ec391da..000000000 --- a/src/pdf/qpdfdestination.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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 "qpdfdestination.h" -#include "qpdfdestination_p.h" - -QT_BEGIN_NAMESPACE - -/*! - \class QPdfDestination - \since 5.15 - \inmodule QtPdf - - \brief The QPdfDestination class defines a location on a page in a PDF - document, and a suggested zoom level at which it is intended to be viewed. -*/ - -/*! - Constructs an invalid Destination. - - \sa valid -*/ -QPdfDestination::QPdfDestination() - : d(new QPdfDestinationPrivate()) -{ -} - -QPdfDestination::QPdfDestination(int page, QPointF location, qreal zoom) - : d(new QPdfDestinationPrivate(page, location, zoom)) -{ -} - -QPdfDestination::QPdfDestination(QPdfDestinationPrivate *d) - : d(d) -{ -} - -QPdfDestination::~QPdfDestination() = default; -QPdfDestination::QPdfDestination(const QPdfDestination &other) = default; -QPdfDestination::QPdfDestination(QPdfDestination &&other) noexcept = default; -QPdfDestination &QPdfDestination::operator=(const QPdfDestination &other) = default; - -/*! - \property QPdfDestination::valid - - This property holds whether the destination is valid. -*/ -bool QPdfDestination::isValid() const -{ - return d->page >= 0; -} - -/*! - \property QPdfDestination::page - - This property holds the page number. -*/ -int QPdfDestination::page() const -{ - return d->page; -} - -/*! - \property QPdfDestination::location - - This property holds the location on the page, in units of points. -*/ -QPointF QPdfDestination::location() const -{ - return d->location; -} - -/*! - \property QPdfDestination::zoom - - This property holds the suggested magnification level, where 1.0 means default scale - (1 pixel = 1 point). -*/ -qreal QPdfDestination::zoom() const -{ - return d->zoom; -} - -QDebug operator<<(QDebug dbg, const QPdfDestination& dest) -{ - QDebugStateSaver saver(dbg); - dbg.nospace(); - dbg << "QPdfDestination(page=" << dest.page() - << " location=" << dest.location() - << " zoom=" << dest.zoom(); - dbg << ')'; - return dbg; -} - -QT_END_NAMESPACE - -#include "moc_qpdfdestination.cpp" diff --git a/src/pdf/qpdfdestination.h b/src/pdf/qpdfdestination.h deleted file mode 100644 index e445f0e5a..000000000 --- a/src/pdf/qpdfdestination.h +++ /dev/null @@ -1,92 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ - -#ifndef QPDFDESTINATION_H -#define QPDFDESTINATION_H - -#include <QtPdf/qtpdfglobal.h> -#include <QtCore/qdebug.h> -#include <QtCore/qobject.h> -#include <QtCore/qpoint.h> -#include <QtCore/qshareddata.h> - -QT_BEGIN_NAMESPACE - -class QPdfDestinationPrivate; - -class QPdfDestination -{ - Q_GADGET_EXPORT(Q_PDF_EXPORT) - Q_PROPERTY(bool valid READ isValid) - Q_PROPERTY(int page READ page) - Q_PROPERTY(QPointF location READ location) - Q_PROPERTY(qreal zoom READ zoom) - -public: - Q_PDF_EXPORT ~QPdfDestination(); - Q_PDF_EXPORT QPdfDestination(const QPdfDestination &other); - Q_PDF_EXPORT QPdfDestination &operator=(const QPdfDestination &other); - - Q_PDF_EXPORT QPdfDestination(QPdfDestination &&other) noexcept; - QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QPdfDestination) - - void swap(QPdfDestination &other) noexcept { d.swap(other.d); } - - Q_PDF_EXPORT bool isValid() const; - Q_PDF_EXPORT int page() const; - Q_PDF_EXPORT QPointF location() const; - Q_PDF_EXPORT qreal zoom() const; - -protected: - QPdfDestination(); - QPdfDestination(int page, QPointF location, qreal zoom); - QPdfDestination(QPdfDestinationPrivate *d); - friend class QPdfDocument; - friend class QQuickPdfNavigationStack; - -protected: - QExplicitlySharedDataPointer<QPdfDestinationPrivate> d; -}; -Q_DECLARE_SHARED(QPdfDestination) - -Q_PDF_EXPORT QDebug operator<<(QDebug, const QPdfDestination &); - -QT_END_NAMESPACE - -#endif // QPDFDESTINATION_H diff --git a/src/pdf/qpdfdestination_p.h b/src/pdf/qpdfdestination_p.h deleted file mode 100644 index f1e639125..000000000 --- a/src/pdf/qpdfdestination_p.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ - -#ifndef QPDFDESTINATION_P_H -#define QPDFDESTINATION_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 "qpdfdestination.h" - -#include <QPointF> - -QT_BEGIN_NAMESPACE - -class QPdfDestinationPrivate : public QSharedData -{ -public: - QPdfDestinationPrivate() = default; - QPdfDestinationPrivate(int page, QPointF location, qreal zoom) - : page(page), - location(location), - zoom(zoom) { } - - int page = -1; - QPointF location; - qreal zoom = 1; -}; - -QT_END_NAMESPACE - -#endif // QPDFDESTINATION_P_H diff --git a/src/pdf/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp index 5304baa2e..b738296ae 100644 --- a/src/pdf/qpdfdocument.cpp +++ b/src/pdf/qpdfdocument.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2020 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 "qpdfdocument.h" #include "qpdfdocument_p.h" @@ -49,6 +13,7 @@ #include <QFile> #include <QHash> #include <QLoggingCategory> +#include <QMetaEnum> #include <QMutex> #include <QVector2D> @@ -64,12 +29,58 @@ QPdfMutexLocker::QPdfMutexLocker() { } +class Q_PDF_EXPORT QPdfPageModel : public QAbstractListModel +{ + Q_OBJECT +public: + QPdfPageModel(QPdfDocument *doc) : QAbstractListModel(doc) + { + m_roleNames = QAbstractItemModel::roleNames(); + QMetaEnum rolesMetaEnum = doc->metaObject()->enumerator(doc->metaObject()->indexOfEnumerator("PageModelRole")); + for (int r = Qt::UserRole; r < int(QPdfDocument::PageModelRole::NRoles); ++r) { + auto name = QByteArray(rolesMetaEnum.valueToKey(r)); + name[0] = tolower(name[0]); + m_roleNames.insert(r, name); + } + connect(doc, &QPdfDocument::statusChanged, this, [this](QPdfDocument::Status s) { + if (s == QPdfDocument::Status::Loading) + beginResetModel(); + else if (s == QPdfDocument::Status::Ready) + endResetModel(); + }); + } + + QVariant data(const QModelIndex &index, int role) const override + { + if (!index.isValid()) + return QVariant(); + switch (QPdfDocument::PageModelRole(role)) { + case QPdfDocument::PageModelRole::Label: + return document()->pageLabel(index.row()); + case QPdfDocument::PageModelRole::PointSize: + return document()->pagePointSize(index.row()); + case QPdfDocument::PageModelRole::NRoles: + break; + } + return QVariant(); + } + + int rowCount(const QModelIndex & = QModelIndex()) const override { return document()->pageCount(); } + + QHash<int, QByteArray> roleNames() const override { return m_roleNames; } + +private: + QPdfDocument *document() const { return static_cast<QPdfDocument *>(parent()); } + + QHash<int, QByteArray> m_roleNames; +}; + QPdfDocumentPrivate::QPdfDocumentPrivate() : avail(nullptr) , doc(nullptr) , loadComplete(false) - , status(QPdfDocument::Null) - , lastError(QPdfDocument::NoError) + , status(QPdfDocument::Status::Null) + , lastError(QPdfDocument::Error::None) , pageCount(0) { asyncBuffer.setData(QByteArray()); @@ -77,8 +88,12 @@ QPdfDocumentPrivate::QPdfDocumentPrivate() const QPdfMutexLocker lock; - if (libraryRefCount == 0) + if (libraryRefCount == 0) { + QElapsedTimer timer; + timer.start(); FPDF_InitLibrary(); + qCDebug(qLcDoc) << "FPDF_InitLibrary took" << timer.elapsed() << "ms"; + } ++libraryRefCount; // FPDF_FILEACCESS setup @@ -100,8 +115,10 @@ QPdfDocumentPrivate::~QPdfDocumentPrivate() const QPdfMutexLocker lock; - if (!--libraryRefCount) + if (!--libraryRefCount) { + qCDebug(qLcDoc) << "FPDF_DestroyLibrary"; FPDF_DestroyLibrary(); + } } void QPdfDocumentPrivate::clear() @@ -120,6 +137,7 @@ void QPdfDocumentPrivate::clear() if (pageCount != 0) { pageCount = 0; emit q->pageCountChanged(pageCount); + emit q->pageModelChanged(); } loadComplete = false; @@ -135,7 +153,7 @@ void QPdfDocumentPrivate::clear() void QPdfDocumentPrivate::updateLastError() { if (doc) { - lastError = QPdfDocument::NoError; + lastError = QPdfDocument::Error::None; return; } @@ -144,15 +162,17 @@ void QPdfDocumentPrivate::updateLastError() lock.unlock(); switch (error) { - case FPDF_ERR_SUCCESS: lastError = QPdfDocument::NoError; break; - case FPDF_ERR_UNKNOWN: lastError = QPdfDocument::UnknownError; break; - case FPDF_ERR_FILE: lastError = QPdfDocument::FileNotFoundError; break; - case FPDF_ERR_FORMAT: lastError = QPdfDocument::InvalidFileFormatError; break; - case FPDF_ERR_PASSWORD: lastError = QPdfDocument::IncorrectPasswordError; break; - case FPDF_ERR_SECURITY: lastError = QPdfDocument::UnsupportedSecuritySchemeError; break; + case FPDF_ERR_SUCCESS: lastError = QPdfDocument::Error::None; break; + case FPDF_ERR_UNKNOWN: lastError = QPdfDocument::Error::Unknown; break; + case FPDF_ERR_FILE: lastError = QPdfDocument::Error::FileNotFound; break; + case FPDF_ERR_FORMAT: lastError = QPdfDocument::Error::InvalidFileFormat; break; + case FPDF_ERR_PASSWORD: lastError = QPdfDocument::Error::IncorrectPassword; break; + case FPDF_ERR_SECURITY: lastError = QPdfDocument::Error::UnsupportedSecurityScheme; break; default: Q_UNREACHABLE(); } + if (lastError != QPdfDocument::Error::None) + qCDebug(qLcDoc) << "FPDF error" << error << "->" << lastError; } void QPdfDocumentPrivate::load(QIODevice *newDevice, bool transferDeviceOwnership) @@ -168,19 +188,19 @@ void QPdfDocumentPrivate::load(QIODevice *newDevice, bool transferDeviceOwnershi QNetworkReply *reply = qobject_cast<QNetworkReply*>(sequentialSourceDevice); if (!reply) { - setStatus(QPdfDocument::Error); + setStatus(QPdfDocument::Status::Error); qWarning() << "QPdfDocument: Loading from sequential devices only supported with QNetworkAccessManager."; return; } if (reply->isFinished() && reply->error() != QNetworkReply::NoError) { - setStatus(QPdfDocument::Error); + setStatus(QPdfDocument::Status::Error); return; } QObject::connect(reply, &QNetworkReply::finished, q, [this, reply](){ if (reply->error() != QNetworkReply::NoError || reply->bytesAvailable() == 0) { - this->setStatus(QPdfDocument::Error); + this->setStatus(QPdfDocument::Status::Error); } }); @@ -192,7 +212,7 @@ void QPdfDocumentPrivate::load(QIODevice *newDevice, bool transferDeviceOwnershi device = newDevice; initiateAsyncLoadWithTotalSizeKnown(device->size()); if (!avail) { - setStatus(QPdfDocument::Error); + setStatus(QPdfDocument::Status::Error); return; } @@ -201,7 +221,7 @@ void QPdfDocumentPrivate::load(QIODevice *newDevice, bool transferDeviceOwnershi if (!doc) { updateLastError(); - setStatus(QPdfDocument::Error); + setStatus(QPdfDocument::Status::Error); return; } @@ -211,15 +231,16 @@ void QPdfDocumentPrivate::load(QIODevice *newDevice, bool transferDeviceOwnershi if (newPageCount != pageCount) { pageCount = newPageCount; emit q->pageCountChanged(pageCount); + emit q->pageModelChanged(); } // If it's a local file, and the first couple of pages are available, // probably the whole document is available. if (checkPageComplete(0) && (pageCount < 2 || checkPageComplete(1))) { - setStatus(QPdfDocument::Ready); + setStatus(QPdfDocument::Status::Ready); } else { updateLastError(); - setStatus(QPdfDocument::Error); + setStatus(QPdfDocument::Status::Error); } } } @@ -231,13 +252,13 @@ void QPdfDocumentPrivate::_q_tryLoadingWithSizeFromContentHeader() const QNetworkReply *networkReply = qobject_cast<QNetworkReply*>(sequentialSourceDevice); if (!networkReply) { - setStatus(QPdfDocument::Error); + setStatus(QPdfDocument::Status::Error); return; } const QVariant contentLength = networkReply->header(QNetworkRequest::ContentLengthHeader); if (!contentLength.isValid()) { - setStatus(QPdfDocument::Error); + setStatus(QPdfDocument::Status::Error); return; } @@ -283,11 +304,10 @@ void QPdfDocumentPrivate::tryLoadDocument() break; case PDF_DATA_NOTAVAIL: qCDebug(qLcDoc) << "data not yet available"; - lastError = QPdfDocument::DataNotYetAvailableError; - setStatus(QPdfDocument::Error); + lastError = QPdfDocument::Error::DataNotYetAvailable; break; case PDF_DATA_AVAIL: - // all good + lastError = QPdfDocument::Error::None; break; } @@ -297,12 +317,14 @@ void QPdfDocumentPrivate::tryLoadDocument() lock.unlock(); updateLastError(); + if (lastError != QPdfDocument::Error::None) + setStatus(QPdfDocument::Status::Error); - if (lastError == QPdfDocument::IncorrectPasswordError) { + if (lastError == QPdfDocument::Error::IncorrectPassword) { FPDF_CloseDocument(doc); doc = nullptr; - setStatus(QPdfDocument::Error); + setStatus(QPdfDocument::Status::Error); emit q->passwordRequired(); } } @@ -339,9 +361,10 @@ void QPdfDocumentPrivate::checkComplete() if (newPageCount != pageCount) { pageCount = newPageCount; emit q->pageCountChanged(pageCount); + emit q->pageModelChanged(); } - setStatus(QPdfDocument::Ready); + setStatus(QPdfDocument::Status::Ready); } } @@ -482,24 +505,36 @@ QPdfDocument::~QPdfDocument() /*! Loads the document contents from \a fileName. */ -QPdfDocument::DocumentError QPdfDocument::load(const QString &fileName) +QPdfDocument::Error QPdfDocument::load(const QString &fileName) { qCDebug(qLcDoc) << "loading" << fileName; close(); - d->setStatus(QPdfDocument::Loading); + d->setStatus(QPdfDocument::Status::Loading); - QScopedPointer<QFile> f(new QFile(fileName)); + std::unique_ptr<QFile> f(new QFile(fileName)); if (!f->open(QIODevice::ReadOnly)) { - d->lastError = FileNotFoundError; - d->setStatus(QPdfDocument::Error); + d->lastError = Error::FileNotFound; + d->setStatus(QPdfDocument::Status::Error); } else { - d->load(f.take(), /*transfer ownership*/true); + d->load(f.release(), /*transfer ownership*/true); } return d->lastError; } +/*! \internal + Returns the filename of the document that has been opened, + or an empty string if no document is open. +*/ +QString QPdfDocument::fileName() const +{ + const QFile *f = qobject_cast<QFile *>(d->device.data()); + if (f) + return f->fileName(); + return QString(); +} + /*! \enum QPdfDocument::Status @@ -532,7 +567,7 @@ void QPdfDocument::load(QIODevice *device) { close(); - d->setStatus(QPdfDocument::Loading); + d->setStatus(QPdfDocument::Status::Loading); d->load(device, /*transfer ownership*/false); } @@ -589,32 +624,15 @@ QVariant QPdfDocument::metaData(MetaDataField field) const if (!d->doc) return QString(); + static QMetaEnum fieldsMetaEnum = metaObject()->enumerator(metaObject()->indexOfEnumerator("MetaDataField")); QByteArray fieldName; switch (field) { - case Title: - fieldName = "Title"; - break; - case Subject: - fieldName = "Subject"; - break; - case Author: - fieldName = "Author"; - break; - case Keywords: - fieldName = "Keywords"; - break; - case Producer: - fieldName = "Producer"; - break; - case Creator: - fieldName = "Creator"; - break; - case CreationDate: - fieldName = "CreationDate"; - break; - case ModificationDate: + case MetaDataField::ModificationDate: fieldName = "ModDate"; break; + default: + fieldName = QByteArray(fieldsMetaEnum.valueToKey(int(field))); + break; } QPdfMutexLocker lock; @@ -627,15 +645,15 @@ QVariant QPdfDocument::metaData(MetaDataField field) const QString text = QString::fromUtf16(reinterpret_cast<const char16_t *>(buf.data())); switch (field) { - case Title: // fall through - case Subject: - case Author: - case Keywords: - case Producer: - case Creator: + case MetaDataField::Title: // fall through + case MetaDataField::Subject: + case MetaDataField::Author: + case MetaDataField::Keywords: + case MetaDataField::Producer: + case MetaDataField::Creator: return text; - case CreationDate: // fall through - case ModificationDate: + case MetaDataField::CreationDate: // fall through + case MetaDataField::ModificationDate: // convert a "D:YYYYMMDDHHmmSSOHH'mm'" into "YYYY-MM-DDTHH:mm:ss+HH:mm" if (text.startsWith(QLatin1String("D:"))) text = text.mid(2); @@ -655,17 +673,17 @@ QVariant QPdfDocument::metaData(MetaDataField field) const } /*! - \enum QPdfDocument::DocumentError + \enum QPdfDocument::Error This enum describes the error while attempting the last operation on the document. - \value NoError No error occurred. - \value UnknownError Unknown type of error. - \value DataNotYetAvailableError The document is still loading, it's too early to attempt the operation. - \value FileNotFoundError The file given to load() was not found. - \value InvalidFileFormatError The file given to load() is not a valid PDF file. - \value IncorrectPasswordError The password given to setPassword() is not correct for this file. - \value UnsupportedSecuritySchemeError QPdfDocument is not able to unlock this kind of PDF file. + \value None No error occurred. + \value Unknown Unknown type of error. + \value DataNotYetAvailable The document is still loading, it's too early to attempt the operation. + \value FileNotFound The file given to load() was not found. + \value InvalidFileFormat The file given to load() is not a valid PDF file. + \value IncorrectPassword The password given to setPassword() is not correct for this file. + \value UnsupportedSecurityScheme QPdfDocument is not able to unlock this kind of PDF file. \sa QPdfDocument::error() */ @@ -674,7 +692,7 @@ QVariant QPdfDocument::metaData(MetaDataField field) const Returns the type of error if \l status is \c Error, or \c NoError if there is no error. */ -QPdfDocument::DocumentError QPdfDocument::error() const +QPdfDocument::Error QPdfDocument::error() const { return d->lastError; } @@ -687,7 +705,7 @@ void QPdfDocument::close() if (!d->doc) return; - d->setStatus(Unloading); + d->setStatus(Status::Unloading); d->clear(); @@ -696,7 +714,7 @@ void QPdfDocument::close() emit passwordChanged(); } - d->setStatus(Null); + d->setStatus(Status::Null); } /*! @@ -713,7 +731,7 @@ int QPdfDocument::pageCount() const /*! Returns the size of page \a page in points (1/72 of an inch). */ -QSizeF QPdfDocument::pageSize(int page) const +QSizeF QPdfDocument::pagePointSize(int page) const { QSizeF result; if (!d->doc || !d->checkPageComplete(page)) @@ -726,6 +744,57 @@ QSizeF QPdfDocument::pageSize(int page) const } /*! + \enum QPdfDocument::PageModelRole + + Roles in pageModel(). + + \value Label The page number to be used for display purposes (QString). + \value PointSize The page size in points (1/72 of an inch) (QSizeF). + \omitvalue NRoles +*/ + +/*! + \property QPdfDocument::pageModel + + This property holds an instance of QAbstractListModel to provide + page-specific metadata, containing one row for each page in the document. + + \sa QPdfDocument::PageModelRole +*/ +QAbstractListModel *QPdfDocument::pageModel() +{ + if (!d->pageModel) + d->pageModel = new QPdfPageModel(this); + return d->pageModel; +} + +/*! + Returns the \a page number to be used for display purposes. + + For example, a document may have multiple sections with different numbering. + Perhaps the preface uses roman numerals, the body starts on page 1, and the + appendix starts at A1. Whenever a PDF viewer shows a page number, to avoid + confusing the user it should be the same "number" as is printed on the + corner of the page, rather than the zero-based page index that we use in + APIs (assuming the document author has made the page labels match the + printed numbers). + + If the document does not have custom page numbering, this function returns + \c {page + 1}. +*/ +QString QPdfDocument::pageLabel(int page) +{ + const unsigned long len = FPDF_GetPageLabel(d->doc, page, nullptr, 0); + if (len == 0) + return QString::number(page + 1); + QList<char16_t> buf(len); + QPdfMutexLocker lock; + FPDF_GetPageLabel(d->doc, page, buf.data(), len); + lock.unlock(); + return QString::fromUtf16(buf.constData()); +} + +/*! Renders the \a page into a QImage of size \a imageSize according to the provided \a renderOptions. @@ -755,35 +824,35 @@ QImage QPdfDocument::render(int page, QSize imageSize, QPdfDocumentRenderOptions int rotation = 0; switch (renderOptions.rotation()) { - case QPdf::Rotate0: + case QPdfDocumentRenderOptions::Rotation::None: rotation = 0; break; - case QPdf::Rotate90: + case QPdfDocumentRenderOptions::Rotation::Clockwise90: rotation = 1; break; - case QPdf::Rotate180: + case QPdfDocumentRenderOptions::Rotation::Clockwise180: rotation = 2; break; - case QPdf::Rotate270: + case QPdfDocumentRenderOptions::Rotation::Clockwise270: rotation = 3; break; } - const QPdf::RenderFlags renderFlags = renderOptions.renderFlags(); + const QPdfDocumentRenderOptions::RenderFlags renderFlags = renderOptions.renderFlags(); int flags = 0; - if (renderFlags & QPdf::RenderAnnotations) + if (renderFlags & QPdfDocumentRenderOptions::RenderFlag::Annotations) flags |= FPDF_ANNOT; - if (renderFlags & QPdf::RenderOptimizedForLcd) + if (renderFlags & QPdfDocumentRenderOptions::RenderFlag::OptimizedForLcd) flags |= FPDF_LCD_TEXT; - if (renderFlags & QPdf::RenderGrayscale) + if (renderFlags & QPdfDocumentRenderOptions::RenderFlag::Grayscale) flags |= FPDF_GRAYSCALE; - if (renderFlags & QPdf::RenderForceHalftone) + if (renderFlags & QPdfDocumentRenderOptions::RenderFlag::ForceHalftone) flags |= FPDF_RENDER_FORCEHALFTONE; - if (renderFlags & QPdf::RenderTextAliased) + if (renderFlags & QPdfDocumentRenderOptions::RenderFlag::TextAliased) flags |= FPDF_RENDER_NO_SMOOTHTEXT; - if (renderFlags & QPdf::RenderImageAliased) + if (renderFlags & QPdfDocumentRenderOptions::RenderFlag::ImageAliased) flags |= FPDF_RENDER_NO_SMOOTHIMAGE; - if (renderFlags & QPdf::RenderPathAliased) + if (renderFlags & QPdfDocumentRenderOptions::RenderFlag::PathAliased) flags |= FPDF_RENDER_NO_SMOOTHPATH; if (renderOptions.scaledClipRect().isValid()) { @@ -796,7 +865,7 @@ QImage QPdfDocument::render(int page, QSize imageSize, QPdfDocumentRenderOptions float y1 = clipRect.bottom(); float x2 = clipRect.right(); float y2 = clipRect.top(); - QSizeF origSize = pageSize(page); + QSizeF origSize = pagePointSize(page); QVector2D pageScale(1, 1); if (!renderOptions.scaledSize().isNull()) { pageScale = QVector2D(renderOptions.scaledSize().width() / float(origSize.width()), @@ -959,4 +1028,5 @@ QPdfSelection QPdfDocument::getAllText(int page) QT_END_NAMESPACE +#include "qpdfdocument.moc" #include "moc_qpdfdocument.cpp" diff --git a/src/pdf/qpdfdocument.h b/src/pdf/qpdfdocument.h index 9a81d4a8c..5f55ed29c 100644 --- a/src/pdf/qpdfdocument.h +++ b/src/pdf/qpdfdocument.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2020 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 QPDFDOCUMENT_H #define QPDFDOCUMENT_H @@ -43,6 +7,7 @@ #include <QtPdf/qtpdfglobal.h> #include <QtCore/qobject.h> +#include <QtCore/QAbstractListModel> #include <QtGui/qimage.h> #include <QtPdf/qpdfdocumentrenderoptions.h> #include <QtPdf/qpdfselection.h> @@ -59,9 +24,10 @@ class Q_PDF_EXPORT QPdfDocument : public QObject Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged FINAL) Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged FINAL) Q_PROPERTY(Status status READ status NOTIFY statusChanged FINAL) + Q_PROPERTY(QAbstractListModel* pageModel READ pageModel NOTIFY pageModelChanged FINAL) public: - enum Status { + enum class Status { Null, Loading, Ready, @@ -70,18 +36,18 @@ public: }; Q_ENUM(Status) - enum DocumentError { - NoError, - UnknownError, - DataNotYetAvailableError, - FileNotFoundError, - InvalidFileFormatError, - IncorrectPasswordError, - UnsupportedSecuritySchemeError + enum class Error { + None, + Unknown, + DataNotYetAvailable, + FileNotFound, + InvalidFileFormat, + IncorrectPassword, + UnsupportedSecurityScheme }; - Q_ENUM(DocumentError) + Q_ENUM(Error) - enum MetaDataField { + enum class MetaDataField { Title, Subject, Author, @@ -93,11 +59,18 @@ public: }; Q_ENUM(MetaDataField) + enum class PageModelRole { + Label = Qt::UserRole, + PointSize, + NRoles + }; + Q_ENUM(PageModelRole) + QPdfDocument() : QPdfDocument(nullptr) {} explicit QPdfDocument(QObject *parent); - ~QPdfDocument(); + ~QPdfDocument() override; - DocumentError load(const QString &fileName); + Error load(const QString &fileName); Status status() const; @@ -107,13 +80,17 @@ public: QVariant metaData(MetaDataField field) const; - DocumentError error() const; + Error error() const; void close(); int pageCount() const; - QSizeF pageSize(int page) const; + Q_INVOKABLE QSizeF pagePointSize(int page) const; + + Q_INVOKABLE QString pageLabel(int page); + + QAbstractListModel *pageModel(); QImage render(int page, QSize imageSize, QPdfDocumentRenderOptions options = QPdfDocumentRenderOptions()); @@ -126,14 +103,19 @@ Q_SIGNALS: void passwordRequired(); void statusChanged(QPdfDocument::Status status); void pageCountChanged(int pageCount); + void pageModelChanged(); private: - friend class QPdfBookmarkModelPrivate; + friend struct QPdfBookmarkModelPrivate; + friend class QPdfFile; friend class QPdfLinkModelPrivate; + friend class QPdfPageModel; friend class QPdfSearchModel; friend class QPdfSearchModelPrivate; friend class QQuickPdfSelection; + QString fileName() const; + Q_PRIVATE_SLOT(d, void _q_tryLoadingWithSizeFromContentHeader()) Q_PRIVATE_SLOT(d, void _q_copyFromSequentialSourceDevice()) QScopedPointer<QPdfDocumentPrivate> d; diff --git a/src/pdf/qpdfdocument_p.h b/src/pdf/qpdfdocument_p.h index 9c816adc4..973dc1d4a 100644 --- a/src/pdf/qpdfdocument_p.h +++ b/src/pdf/qpdfdocument_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2020 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 QPDFDOCUMENT_P_H #define QPDFDOCUMENT_P_H @@ -71,6 +35,8 @@ public: QPdfMutexLocker(); }; +class QPdfPageModel; + class Q_PDF_PRIVATE_EXPORT QPdfDocumentPrivate: public FPDF_FILEACCESS, public FX_FILEAVAIL, public FX_DOWNLOADHINTS { public: @@ -78,6 +44,7 @@ public: ~QPdfDocumentPrivate(); QPdfDocument *q; + QPdfPageModel *pageModel = nullptr; FPDF_AVAIL avail; FPDF_DOCUMENT doc; @@ -90,7 +57,7 @@ public: QByteArray password; QPdfDocument::Status status; - QPdfDocument::DocumentError lastError; + QPdfDocument::Error lastError; int pageCount; void clear(); diff --git a/src/pdf/qpdfdocumentrenderoptions.h b/src/pdf/qpdfdocumentrenderoptions.h index 250efdc2f..af074d976 100644 --- a/src/pdf/qpdfdocumentrenderoptions.h +++ b/src/pdf/qpdfdocumentrenderoptions.h @@ -1,47 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> +// Copyright (C) 2020 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 QPDFDOCUMENTRENDEROPTIONS_H #define QPDFDOCUMENTRENDEROPTIONS_H -#include <QtPdf/qpdfnamespace.h> +#include <QtPdf/qtpdfglobal.h> #include <QtCore/qobject.h> #include <QtCore/qrect.h> @@ -50,13 +14,32 @@ QT_BEGIN_NAMESPACE class QPdfDocumentRenderOptions { public: + enum class Rotation { + None, + Clockwise90, + Clockwise180, + Clockwise270 + }; + + enum class RenderFlag { + None = 0x000, + Annotations = 0x001, + OptimizedForLcd = 0x002, + Grayscale = 0x004, + ForceHalftone = 0x008, + TextAliased = 0x010, + ImageAliased = 0x020, + PathAliased = 0x040 + }; + Q_DECLARE_FLAGS(RenderFlags, RenderFlag) + constexpr QPdfDocumentRenderOptions() noexcept : m_renderFlags(0), m_rotation(0), m_reserved(0) {} - constexpr QPdf::Rotation rotation() const noexcept { return static_cast<QPdf::Rotation>(m_rotation); } - constexpr void setRotation(QPdf::Rotation r) noexcept { m_rotation = r; } + constexpr Rotation rotation() const noexcept { return static_cast<Rotation>(m_rotation); } + constexpr void setRotation(Rotation r) noexcept { m_rotation = quint32(r); } - constexpr QPdf::RenderFlags renderFlags() const noexcept { return static_cast<QPdf::RenderFlags>(m_renderFlags); } - constexpr void setRenderFlags(QPdf::RenderFlags r) noexcept { m_renderFlags = quint32(r.toInt()); } + constexpr RenderFlags renderFlags() const noexcept { return static_cast<RenderFlags>(m_renderFlags); } + constexpr void setRenderFlags(RenderFlags r) noexcept { m_renderFlags = quint32(r.toInt()); } constexpr QRect scaledClipRect() const noexcept { return m_clipRect; } constexpr void setScaledClipRect(const QRect &r) noexcept { m_clipRect = r; } @@ -65,7 +48,7 @@ public: constexpr void setScaledSize(const QSize &s) noexcept { m_scaledSize = s; } private: - friend constexpr inline bool operator==(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) noexcept; + friend constexpr inline bool operator==(const QPdfDocumentRenderOptions &lhs, const QPdfDocumentRenderOptions &rhs) noexcept; QRect m_clipRect; QSize m_scaledSize; @@ -77,15 +60,16 @@ private: }; Q_DECLARE_TYPEINFO(QPdfDocumentRenderOptions, Q_PRIMITIVE_TYPE); +Q_DECLARE_OPERATORS_FOR_FLAGS(QPdfDocumentRenderOptions::RenderFlags) -constexpr inline bool operator==(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) noexcept +constexpr inline bool operator==(const QPdfDocumentRenderOptions &lhs, const QPdfDocumentRenderOptions &rhs) noexcept { return lhs.m_clipRect == rhs.m_clipRect && lhs.m_scaledSize == rhs.m_scaledSize && lhs.m_renderFlags == rhs.m_renderFlags && lhs.m_rotation == rhs.m_rotation && lhs.m_reserved == rhs.m_reserved && lhs.m_reserved2 == rhs.m_reserved2; // fix -Wunused-private-field } -constexpr inline bool operator!=(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) noexcept +constexpr inline bool operator!=(const QPdfDocumentRenderOptions &lhs, const QPdfDocumentRenderOptions &rhs) noexcept { return !operator==(lhs, rhs); } diff --git a/src/pdf/qpdfdocumentrenderoptions.qdoc b/src/pdf/qpdfdocumentrenderoptions.qdoc index 8e03df882..ad8e7bfdb 100644 --- a/src/pdf/qpdfdocumentrenderoptions.qdoc +++ b/src/pdf/qpdfdocumentrenderoptions.qdoc @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qpdfdocumentrenderoptions.h" @@ -52,13 +16,42 @@ QT_BEGIN_NAMESPACE */ /*! + \enum QPdfDocumentRenderOptions::Rotation + + This enum describes the rotation of the page for rendering. + + \value None Do not rotate (the default) + \value Clockwise90 Rotate 90 degrees clockwise + \value Clockwise180 Rotate 180 degrees + \value Clockwise270 Rotate 270 degrees clockwise + + \sa QPdfDocument::render() +*/ +/*! + \enum QPdfDocumentRenderOptions::RenderFlag + + This enum is used to describe how a page should be rendered. + + \value None The default value, representing no flags. + \value Annotations The page is rendered with annotations. + \value OptimizedForLcd The text of the page is rendered optimized for LCD display. + \value Grayscale The page is rendered grayscale. + \value ForceHalftone Always use halftones for rendering if the output image is stretched. + \value TextAliased Anti-aliasing is disabled for rendering text. + \value ImageAliased Anti-aliasing is disabled for rendering images. + \value PathAliased Anti-aliasing is disabled for rendering paths. + + \sa QPdfDocument::render() +*/ + +/*! \fn QPdfDocumentRenderOptions::QPdfDocumentRenderOptions() Constructs a QPdfDocumentRenderOptions object. */ /*! - \fn QPdf::Rotation QPdfDocumentRenderOptions::rotation() const + \fn QPdfDocumentRenderOptions::Rotation QPdfDocumentRenderOptions::rotation() const Returns the rotation used for rendering a page from a PDF document. @@ -66,7 +59,7 @@ QT_BEGIN_NAMESPACE */ /*! - \fn void QPdfDocumentRenderOptions::setRotation(QPdf::Rotation rotation) + \fn void QPdfDocumentRenderOptions::setRotation(QPdfDocumentRenderOptions::Rotation rotation) Sets the \a rotation used for rendering a page from a PDF document. @@ -74,7 +67,7 @@ QT_BEGIN_NAMESPACE */ /*! - \fn QPdf::RenderFlags QPdfDocumentRenderOptions::renderFlags() const + \fn QPdfDocumentRenderOptions::RenderFlags QPdfDocumentRenderOptions::renderFlags() const Returns the special flags used for rendering a page from a PDF document. @@ -82,7 +75,7 @@ QT_BEGIN_NAMESPACE */ /*! - \fn void QPdfDocumentRenderOptions::setRenderFlags(QPdf::RenderFlags flags) + \fn void QPdfDocumentRenderOptions::setRenderFlags(QPdfDocumentRenderOptions::RenderFlags flags) Sets the special \a flags used for rendering a page from a PDF document. diff --git a/src/pdf/qpdffile.cpp b/src/pdf/qpdffile.cpp new file mode 100644 index 000000000..a54f6a568 --- /dev/null +++ b/src/pdf/qpdffile.cpp @@ -0,0 +1,28 @@ +// Copyright (C) 2022 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 "qpdffile_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \internal + \class QPdfFile + \inmodule QtPdf + + QPdfFile is a means of passing a PDF file along with the associated + QPdfDocument together into QPdfIOHandler::load(QIODevice *device) so that + QPdfIOHandler does not need to construct its own redundant QPdfDocument + instance. If it succeeds in casting the QIODevice to a QPdfFile, it is + expected to use the QPdfDocument operations for all I/O, and thus the + normal QFile I/O functions are not needed for that use case. +*/ + +QPdfFile::QPdfFile(QPdfDocument *doc) + : QFile(doc->fileName()), m_document(doc) +{ +} + +QT_END_NAMESPACE + +//#include "moc_qpdffile_p.cpp" diff --git a/src/pdf/qpdffile_p.h b/src/pdf/qpdffile_p.h new file mode 100644 index 000000000..f678cdcdc --- /dev/null +++ b/src/pdf/qpdffile_p.h @@ -0,0 +1,37 @@ +// Copyright (C) 2022 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 QPDFFILE_P_H +#define QPDFFILE_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 "qpdfdocument.h" + +#include <QtCore/qfile.h> + +QT_BEGIN_NAMESPACE + +class Q_PDF_EXPORT QPdfFile : public QFile +{ + Q_OBJECT +public: + QPdfFile(QPdfDocument *doc); + QPdfDocument *document() { return m_document; } + +private: + QPdfDocument *m_document; +}; + +QT_END_NAMESPACE + +#endif // QPDFFILE_P_H diff --git a/src/pdf/qpdflink.cpp b/src/pdf/qpdflink.cpp new file mode 100644 index 000000000..d1f5bdfdc --- /dev/null +++ b/src/pdf/qpdflink.cpp @@ -0,0 +1,190 @@ +// Copyright (C) 2022 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 "qpdflink.h" +#include "qpdflink_p.h" +#include "qpdflinkmodel_p.h" +#include <QGuiApplication> +#include <QDebug> + +QT_BEGIN_NAMESPACE + +/*! + \class QPdfLink + \since 6.4 + \inmodule QtPdf + + \brief The QPdfLink class defines a link between a region on a page + (such as a hyperlink or a search result) and a destination + (page, location on the page, and zoom level at which to view it). +*/ + +/*! + Constructs an invalid Destination. + + \sa valid +*/ +QPdfLink::QPdfLink() : + QPdfLink(new QPdfLinkPrivate()) { } + +QPdfLink::QPdfLink(int page, QPointF location, qreal zoom) + : QPdfLink(new QPdfLinkPrivate(page, location, zoom)) +{ +} + +QPdfLink::QPdfLink(int page, QList<QRectF> rects, + QString contextBefore, QString contextAfter) + : QPdfLink(new QPdfLinkPrivate(page, std::move(rects), + std::move(contextBefore), + std::move(contextAfter))) +{ +} + +QPdfLink::QPdfLink(QPdfLinkPrivate *d) : d(d) {} + +QPdfLink::~QPdfLink() = default; +QPdfLink::QPdfLink(const QPdfLink &other) noexcept = default; +QPdfLink::QPdfLink(QPdfLink &&other) noexcept = default; +QPdfLink &QPdfLink::operator=(const QPdfLink &other) = default; + +/*! + \property QPdfLink::valid + + This property holds whether the link is valid. +*/ +bool QPdfLink::isValid() const +{ + return d->page >= 0; +} + +/*! + \property QPdfLink::page + + This property holds the page number. + If the link is a search result, it is the page number on which the result is found; + if the link is a hyperlink, it is the destination page number. +*/ +int QPdfLink::page() const +{ + return d->page; +} + +/*! + \property QPdfLink::location + + This property holds the location on the \l page, in units of points. + If the link is a search result, it is the location where the result is found; + if the link is a hyperlink, it is the destination location. +*/ +QPointF QPdfLink::location() const +{ + return d->location; +} + +/*! + \property QPdfLink::zoom + + This property holds the suggested magnification level, where 1.0 means default scale + (1 pixel = 1 point). If the link is a search result, this value is not used. +*/ +qreal QPdfLink::zoom() const +{ + return d->zoom; +} + +/*! + \property QPdfLink::url + + This property holds the destination URL if the link is an external hyperlink; + otherwise, it's empty. +*/ +QUrl QPdfLink::url() const +{ + return d->url; +} + +/*! + \property QPdfLink::contextBefore + + This property holds adjacent text found on the page before the search string. + If the link is a hyperlink, this string is empty. + + \sa QPdfSearchModel::resultsOnPage(), QPdfSearchModel::resultAtIndex() +*/ +QString QPdfLink::contextBefore() const +{ + return d->contextBefore; +} + +/*! + \property QPdfLink::contextAfter + + This property holds adjacent text found on the page after the search string. + If the link is a hyperlink, this string is empty. + + \sa QPdfSearchModel::resultsOnPage(), QPdfSearchModel::resultAtIndex() +*/ +QString QPdfLink::contextAfter() const +{ + return d->contextAfter; +} + +/*! + \property QPdfLink::rectangles + + This property holds the region (set of rectangles) occupied by the link or + search result on the page where it was found. If the text wraps around to + multiple lines on the page, there may be multiple rectangles: + + \image wrapping-search-result.png + + \sa QPdfSearchModel::resultsOnPage(), QPdfSearchModel::resultAtIndex() +*/ +QList<QRectF> QPdfLink::rectangles() const +{ + return d->rects; +} + +/*! + Returns a translated representation for display. + + \sa copyToClipboard() +*/ +QString QPdfLink::toString() const +{ + static const QString format = QPdfLinkModel::tr("page %1 location %2,%3 zoom %4"); + return d->page > 0 ? format.arg(QString::number(d->page), + QString::number(d->location.x()), + QString::number(d->location.y()), + QString::number(d->zoom)) + : d->url.toString(); +} + +/*! + Copies the toString() representation of the link to the + \l {QGuiApplication::clipboard()}{system clipboard} depending on the \a mode given. +*/ +void QPdfLink::copyToClipboard(QClipboard::Mode mode) const +{ + QGuiApplication::clipboard()->setText(toString(), mode); +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QPdfLink &link) +{ + QDebugStateSaver saver(dbg); + dbg.nospace(); + dbg << "QPdfLink(page=" << link.page() + << " location=" << link.location() + << " zoom=" << link.zoom() + << " contextBefore=" << link.contextBefore() + << " contextAfter=" << link.contextAfter() + << " rects=" << link.rectangles(); + dbg << ')'; + return dbg; +} +#endif + +QT_END_NAMESPACE + +#include "moc_qpdflink.cpp" diff --git a/src/pdf/qpdflink.h b/src/pdf/qpdflink.h new file mode 100644 index 000000000..63389afe6 --- /dev/null +++ b/src/pdf/qpdflink.h @@ -0,0 +1,78 @@ +// Copyright (C) 2022 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 QPDFLINK_H +#define QPDFLINK_H + +#include <QtPdf/qtpdfglobal.h> +#include <QtCore/qlist.h> +#include <QtCore/qobject.h> +#include <QtCore/qpoint.h> +#include <QtCore/qrect.h> +#include <QtCore/qshareddata.h> +#include <QtGui/qclipboard.h> + +QT_BEGIN_NAMESPACE + +class QDebug; +class QPdfLinkPrivate; + +class QPdfLink +{ + Q_GADGET_EXPORT(Q_PDF_EXPORT) + Q_PROPERTY(bool valid READ isValid) + Q_PROPERTY(int page READ page) + Q_PROPERTY(QPointF location READ location) + Q_PROPERTY(qreal zoom READ zoom) + Q_PROPERTY(QUrl url READ url) + Q_PROPERTY(QString contextBefore READ contextBefore) + Q_PROPERTY(QString contextAfter READ contextAfter) + Q_PROPERTY(QList<QRectF> rectangles READ rectangles) + +public: + Q_PDF_EXPORT QPdfLink(); + Q_PDF_EXPORT ~QPdfLink(); + Q_PDF_EXPORT QPdfLink &operator=(const QPdfLink &other); + + Q_PDF_EXPORT QPdfLink(const QPdfLink &other) noexcept; + Q_PDF_EXPORT QPdfLink(QPdfLink &&other) noexcept; + QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QPdfLink) + + void swap(QPdfLink &other) noexcept { d.swap(other.d); } + + Q_PDF_EXPORT bool isValid() const; + Q_PDF_EXPORT int page() const; + Q_PDF_EXPORT QPointF location() const; + Q_PDF_EXPORT qreal zoom() const; + Q_PDF_EXPORT QUrl url() const; + Q_PDF_EXPORT QString contextBefore() const; + Q_PDF_EXPORT QString contextAfter() const; + Q_PDF_EXPORT QList<QRectF> rectangles() const; + Q_PDF_EXPORT Q_INVOKABLE QString toString() const; + Q_PDF_EXPORT Q_INVOKABLE void copyToClipboard(QClipboard::Mode mode = QClipboard::Clipboard) const; + +private: // methods + QPdfLink(int page, QPointF location, qreal zoom); + QPdfLink(int page, QList<QRectF> rects, QString contextBefore, QString contextAfter); + QPdfLink(QPdfLinkPrivate *d); + friend class QPdfDocument; + friend class QPdfLinkModelPrivate; + friend class QPdfSearchModelPrivate; + friend class QPdfPageNavigator; + friend class QQuickPdfPageNavigator; + +private: // storage + QExplicitlySharedDataPointer<QPdfLinkPrivate> d; + +}; +Q_DECLARE_SHARED(QPdfLink) + +#ifndef QT_NO_DEBUG_STREAM +Q_PDF_EXPORT QDebug operator<<(QDebug, const QPdfLink &); +#endif + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QPdfLink) + +#endif // QPDFLINK_H diff --git a/src/pdf/qpdflink_p.h b/src/pdf/qpdflink_p.h new file mode 100644 index 000000000..fa82f47c3 --- /dev/null +++ b/src/pdf/qpdflink_p.h @@ -0,0 +1,53 @@ +// Copyright (C) 2022 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 QPDFLINK_P_H +#define QPDFLINK_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 "qpdflink.h" + +#include <QPointF> +#include <QRectF> +#include <QUrl> + +QT_BEGIN_NAMESPACE + +class QPdfLinkPrivate : public QSharedData +{ +public: + QPdfLinkPrivate() = default; + QPdfLinkPrivate(int page, QPointF location, qreal zoom) + : page(page), + location(location), + zoom(zoom) { } + QPdfLinkPrivate(int page, QList<QRectF> rects, QString contextBefore, QString contextAfter) + : page(page), + location(rects.first().topLeft()), + zoom(0), + contextBefore{std::move(contextBefore)}, + contextAfter{std::move(contextAfter)}, + rects{std::move(rects)} {} + + int page = -1; + QPointF location; + qreal zoom = 1; + QString contextBefore; + QString contextAfter; + QUrl url; + QList<QRectF> rects; +}; + +QT_END_NAMESPACE + +#endif // QPDFLINK_P_H diff --git a/src/pdf/qpdflinkmodel.cpp b/src/pdf/qpdflinkmodel.cpp index 93d39020c..06afd9641 100644 --- a/src/pdf/qpdflinkmodel.cpp +++ b/src/pdf/qpdflinkmodel.cpp @@ -1,42 +1,7 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2020 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 "qpdflink_p.h" #include "qpdflinkmodel_p.h" #include "qpdflinkmodel_p_p.h" #include "qpdfdocument_p.h" @@ -51,14 +16,44 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(qLcLink, "qt.pdf.links") +/*! \internal + \class QPdfLinkModel + \since 5.15 + \inmodule QtPdf + \inherits QAbstractListModel + + \brief The QPdfLinkModel class holds the geometry and the destination for + each link that the specified \l page contains. + + This is used in PDF viewers to implement the hyperlink mechanism. +*/ + +/*! \internal + \enum QPdfLinkModel::Role + + \value Link A QPdfLink object. + \value Rectangle Bounding rectangle around the link. + \value Url If the link is a web link, the URL for that; otherwise an empty URL. + \value Page If the link is an internal link, the page number to which the link should jump; otherwise \c {-1}. + \value Location If the link is an internal link, the location on the page to which the link should jump. + \value Zoom If the link is an internal link, the suggested zoom level on the destination page. + \omitvalue NRoles +*/ + +/*! \internal + Constructs a new link model with parent object \a parent. +*/ QPdfLinkModel::QPdfLinkModel(QObject *parent) : QAbstractListModel(*(new QPdfLinkModelPrivate()), parent) { QMetaEnum rolesMetaEnum = metaObject()->enumerator(metaObject()->indexOfEnumerator("Role")); - for (int r = Qt::UserRole; r < int(Role::_Count); ++r) + for (int r = Qt::UserRole; r < int(Role::NRoles); ++r) m_roleNames.insert(r, QByteArray(rolesMetaEnum.valueToKey(r)).toLower()); } +/*! \internal + Destroys the model. +*/ QPdfLinkModel::~QPdfLinkModel() {} QHash<int, QByteArray> QPdfLinkModel::roleNames() const @@ -66,6 +61,9 @@ QHash<int, QByteArray> QPdfLinkModel::roleNames() const return m_roleNames; } +/*! \internal + \reimp +*/ int QPdfLinkModel::rowCount(const QModelIndex &parent) const { Q_D(const QPdfLinkModel); @@ -73,22 +71,27 @@ int QPdfLinkModel::rowCount(const QModelIndex &parent) const return d->links.count(); } +/*! \internal + \reimp +*/ QVariant QPdfLinkModel::data(const QModelIndex &index, int role) const { Q_D(const QPdfLinkModel); - const QPdfLinkModelPrivate::Link &link = d->links.at(index.row()); + const auto &link = d->links.at(index.row()); switch (Role(role)) { - case Role::Rect: - return link.rect; + case Role::Link: + return QVariant::fromValue(link); + case Role::Rectangle: + return link.rectangles().empty() ? QVariant() : link.rectangles().constFirst(); case Role::Url: - return link.url; + return link.url(); case Role::Page: - return link.page; + return link.page(); case Role::Location: - return link.location; + return link.location(); case Role::Zoom: - return link.zoom; - case Role::_Count: + return link.zoom(); + case Role::NRoles: break; } if (role == Qt::DisplayRole) @@ -96,6 +99,10 @@ QVariant QPdfLinkModel::data(const QModelIndex &index, int role) const return QVariant(); } +/*! \internal + \property QPdfLinkModel::document + \brief the document to load links from +*/ QPdfDocument *QPdfLinkModel::document() const { Q_D(const QPdfLinkModel); @@ -118,6 +125,10 @@ void QPdfLinkModel::setDocument(QPdfDocument *document) d->update(); } +/*! \internal + \property QPdfLinkModel::page + \brief the page to load links from +*/ int QPdfLinkModel::page() const { Q_D(const QPdfLinkModel); @@ -169,16 +180,16 @@ void QPdfLinkModelPrivate::update() qCWarning(qLcLink) << "skipping link with invalid bounding box"; continue; // while enumerating links } - Link linkData; - linkData.rect = QRectF(rect.left, pageHeight - rect.top, + QPdfLink linkData; + linkData.d->rects << QRectF(rect.left, pageHeight - rect.top, rect.right - rect.left, rect.top - rect.bottom); FPDF_DEST dest = FPDFLink_GetDest(doc, linkAnnot); FPDF_ACTION action = FPDFLink_GetAction(linkAnnot); switch (FPDFAction_GetType(action)) { case PDFACTION_UNSUPPORTED: // this happens with valid links in some PDFs case PDFACTION_GOTO: { - linkData.page = FPDFDest_GetDestPageIndex(doc, dest); - if (linkData.page < 0) { + linkData.d->page = FPDFDest_GetDestPageIndex(doc, dest); + if (linkData.d->page < 0) { qCWarning(qLcLink) << "skipping link with invalid page number"; continue; // while enumerating links } @@ -186,25 +197,25 @@ void QPdfLinkModelPrivate::update() FS_FLOAT x, y, zoom; ok = FPDFDest_GetLocationInPage(dest, &hasX, &hasY, &hasZoom, &x, &y, &zoom); if (!ok) { - qCWarning(qLcLink) << "link with invalid location and/or zoom @" << linkData.rect; + qCWarning(qLcLink) << "link with invalid location and/or zoom @" << linkData.d->rects; break; // at least we got a page number, so the link will jump there } if (hasX && hasY) - linkData.location = QPointF(x, pageHeight - y); + linkData.d->location = QPointF(x, pageHeight - y); if (hasZoom) - linkData.zoom = zoom; + linkData.d->zoom = zoom; break; } case PDFACTION_URI: { unsigned long len = FPDFAction_GetURIPath(doc, action, nullptr, 0); if (len < 1) { - qCWarning(qLcLink) << "skipping link with empty URI @" << linkData.rect; + qCWarning(qLcLink) << "skipping link with empty URI @" << linkData.d->rects; continue; // while enumerating links } else { QByteArray buf(len, 0); unsigned long got = FPDFAction_GetURIPath(doc, action, buf.data(), len); Q_ASSERT(got == len); - linkData.url = QString::fromLatin1(buf.data(), got - 1); + linkData.d->url = QString::fromLatin1(buf.data(), got - 1); } break; } @@ -212,13 +223,13 @@ void QPdfLinkModelPrivate::update() case PDFACTION_REMOTEGOTO: { unsigned long len = FPDFAction_GetFilePath(action, nullptr, 0); if (len < 1) { - qCWarning(qLcLink) << "skipping link with empty file path @" << linkData.rect; + qCWarning(qLcLink) << "skipping link with empty file path @" << linkData.d->rects; continue; // while enumerating links } else { QByteArray buf(len, 0); unsigned long got = FPDFAction_GetFilePath(action, buf.data(), len); Q_ASSERT(got == len); - linkData.url = QUrl::fromLocalFile(QString::fromLatin1(buf.data(), got - 1)).toString(); + linkData.d->url = QUrl::fromLocalFile(QString::fromLatin1(buf.data(), got - 1)).toString(); // Unfortunately, according to comments in fpdf_doc.h, if it's PDFACTION_REMOTEGOTO, // we can't get the page and location without first opening the linked document @@ -237,7 +248,7 @@ void QPdfLinkModelPrivate::update() if (webLinks) { int count = FPDFLink_CountWebLinks(webLinks); for (int i = 0; i < count; ++i) { - Link linkData; + QPdfLink linkData; int len = FPDFLink_GetURL(webLinks, i, nullptr, 0); if (len < 1) { qCWarning(qLcLink) << "skipping link" << i << "with empty URL"; @@ -245,16 +256,15 @@ void QPdfLinkModelPrivate::update() QList<unsigned short> buf(len); int got = FPDFLink_GetURL(webLinks, i, buf.data(), len); Q_ASSERT(got == len); - linkData.url = QString::fromUtf16( + linkData.d->url = QString::fromUtf16( reinterpret_cast<const char16_t *>(buf.data()), got - 1); } - FPDFLink_GetTextRange(webLinks, i, &linkData.textStart, &linkData.textCharCount); len = FPDFLink_CountRects(webLinks, i); for (int r = 0; r < len; ++r) { double left, top, right, bottom; bool success = FPDFLink_GetRect(webLinks, i, r, &left, &top, &right, &bottom); if (success) { - linkData.rect = QRectF(left, pageHeight - top, right - left, top - bottom); + linkData.d->rects << QRectF(left, pageHeight - top, right - left, top - bottom); links << linkData; } } @@ -267,8 +277,8 @@ void QPdfLinkModelPrivate::update() // All done FPDF_ClosePage(pdfPage); if (Q_UNLIKELY(qLcLink().isDebugEnabled())) { - for (const Link &l : links) - qCDebug(qLcLink) << l.rect << l.toString(); + for (const auto &l : links) + qCDebug(qLcLink) << l; } q->endResetModel(); } @@ -277,21 +287,10 @@ void QPdfLinkModel::onStatusChanged(QPdfDocument::Status status) { Q_D(QPdfLinkModel); qCDebug(qLcLink) << "sees document statusChanged" << status; - if (status == QPdfDocument::Ready) + if (status == QPdfDocument::Status::Ready) d->update(); } -QString QPdfLinkModelPrivate::Link::toString() const -{ - QString ret; - if (page >= 0) - return QLatin1String("page ") + QString::number(page) + - QLatin1String(" location ") + QString::number(location.x()) + QLatin1Char(',') + QString::number(location.y()) + - QLatin1String(" zoom ") + QString::number(zoom); - else - return url.toString(); -} - QT_END_NAMESPACE #include "moc_qpdflinkmodel_p.cpp" diff --git a/src/pdf/qpdflinkmodel_p.h b/src/pdf/qpdflinkmodel_p.h index 495370fe1..3251d4e9a 100644 --- a/src/pdf/qpdflinkmodel_p.h +++ b/src/pdf/qpdflinkmodel_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2020 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 QPDFLINKMODEL_P_H #define QPDFLINKMODEL_P_H @@ -69,12 +33,13 @@ class Q_PDF_EXPORT QPdfLinkModel : public QAbstractListModel public: enum class Role : int { - Rect = Qt::UserRole, + Link = Qt::UserRole, + Rectangle, Url, Page, Location, Zoom, - _Count + NRoles }; Q_ENUM(Role) explicit QPdfLinkModel(QObject *parent = nullptr); diff --git a/src/pdf/qpdflinkmodel_p_p.h b/src/pdf/qpdflinkmodel_p_p.h index 14c8bc734..ba553d41f 100644 --- a/src/pdf/qpdflinkmodel_p_p.h +++ b/src/pdf/qpdflinkmodel_p_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2020 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 QPDFLINKMODEL_P_P_H #define QPDFLINKMODEL_P_P_H @@ -52,6 +16,7 @@ // #include "qpdflinkmodel_p.h" +#include "qpdflink.h" #include <private/qabstractitemmodel_p.h> #include "third_party/pdfium/public/fpdfview.h" @@ -69,23 +34,8 @@ public: void update(); - struct Link { - // where it is on the current page - QRectF rect; - int textStart = -1; - int textCharCount = 0; - // destination inside PDF - int page = -1; // -1 means look at the url instead - QPointF location; - qreal zoom = 0; // 0 means no specified zoom: don't change when clicking - // web destination - QUrl url; - - QString toString() const; - }; - QPdfDocument *document = nullptr; - QList<Link> links; + QList<QPdfLink> links; int page = 0; }; diff --git a/src/pdf/qpdfnamespace.h b/src/pdf/qpdfnamespace.h deleted file mode 100644 index 9c2d3bf0d..000000000 --- a/src/pdf/qpdfnamespace.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ - -#ifndef QPDFNAMESPACE_H -#define QPDFNAMESPACE_H - -#include <QtPdf/qtpdfglobal.h> -#include <QtCore/qobject.h> - -QT_BEGIN_NAMESPACE - -namespace QPdf { - Q_NAMESPACE_EXPORT(Q_PDF_EXPORT) - - enum Rotation { - Rotate0, - Rotate90, - Rotate180, - Rotate270 - }; - Q_ENUM_NS(Rotation) - - enum RenderFlag { - NoRenderFlags = 0x000, - RenderAnnotations = 0x001, - RenderOptimizedForLcd = 0x002, - RenderGrayscale = 0x004, - RenderForceHalftone = 0x008, - RenderTextAliased = 0x010, - RenderImageAliased = 0x020, - RenderPathAliased = 0x040 - }; - Q_FLAG_NS(RenderFlag) - Q_DECLARE_FLAGS(RenderFlags, RenderFlag) - Q_DECLARE_OPERATORS_FOR_FLAGS(RenderFlags) -} - -QT_END_NAMESPACE -#endif diff --git a/src/pdf/qpdfnamespace.qdoc b/src/pdf/qpdfnamespace.qdoc deleted file mode 100644 index 3dbe59595..000000000 --- a/src/pdf/qpdfnamespace.qdoc +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ - -/*! - \namespace QPdf - \inmodule QtPdf - \keyword QPdf Namespace - - \brief The QPdf namespace contains miscellaneous identifiers - used throughout the QtPdf module. -*/ - -/*! - \enum QPdf::Rotation - - This enum describes the rotation of the page for rendering. - - \value Rotate0 Do not rotate (the default) - \value Rotate90 Rotate 90 degrees clockwise - \value Rotate180 Rotate 180 degrees - \value Rotate270 Rotate 270 degrees clockwise - - \sa QPdfDocument::render() -*/ -/*! - \enum QPdf::RenderFlag - - This enum is used to describe how a page should be rendered. - - \value NoRenderFlags The default value, representing no flags. - \value RenderAnnotations The page is rendered with annotations. - \value RenderOptimizedForLcd The text of the page is rendered optimized for LCD display. - \value RenderGrayscale The page is rendered grayscale. - \value RenderForceHalftone Always use halftones for rendering if the output image is stretched. - \value RenderTextAliased Anti-aliasing is disabled for rendering text. - \value RenderImageAliased Anti-aliasing is disabled for rendering images. - \value RenderPathAliased Anti-aliasing is disabled for rendering paths. - - \sa QPdfDocument::render() -*/ - diff --git a/src/pdf/qpdfpagenavigation.cpp b/src/pdf/qpdfpagenavigation.cpp deleted file mode 100644 index 410662526..000000000 --- a/src/pdf/qpdfpagenavigation.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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 "qpdfpagenavigation.h" - -#include "qpdfdocument.h" - -#include <private/qobject_p.h> - -#include <QPointer> - -QT_BEGIN_NAMESPACE - -class QPdfPageNavigationPrivate -{ -public: - QPdfPageNavigationPrivate(QPdfPageNavigation *q) : q_ptr(q) { } - - void update() - { - const bool documentAvailable = m_document && m_document->status() == QPdfDocument::Ready; - - if (documentAvailable) { - const int newPageCount = m_document->pageCount(); - if (m_pageCount != newPageCount) { - m_pageCount = newPageCount; - emit q_ptr->pageCountChanged(m_pageCount); - } - } else { - if (m_pageCount != 0) { - m_pageCount = 0; - emit q_ptr->pageCountChanged(m_pageCount); - } - } - - if (m_currentPage != 0) { - m_currentPage = 0; - emit q_ptr->currentPageChanged(m_currentPage); - } - - updatePrevNext(); - } - - void updatePrevNext() - { - const bool hasPreviousPage = m_currentPage > 0; - const bool hasNextPage = m_currentPage < (m_pageCount - 1); - - if (m_canGoToPreviousPage != hasPreviousPage) { - m_canGoToPreviousPage = hasPreviousPage; - emit q_ptr->canGoToPreviousPageChanged(m_canGoToPreviousPage); - } - - if (m_canGoToNextPage != hasNextPage) { - m_canGoToNextPage = hasNextPage; - emit q_ptr->canGoToNextPageChanged(m_canGoToNextPage); - } - } - - void documentStatusChanged() - { - update(); - } - - QPdfPageNavigation *q_ptr = nullptr; - QPointer<QPdfDocument> m_document = nullptr; - int m_currentPage = 0; - int m_pageCount = 0; - bool m_canGoToPreviousPage = false; - bool m_canGoToNextPage = false; - - QMetaObject::Connection m_documentStatusChangedConnection; -}; - -/*! - \class QPdfPageNavigation - \since 5.10 - \inmodule QtPdf - - \brief The QPdfPageNavigation class handles the navigation through a PDF document. - - \sa QPdfDocument -*/ - - -/*! - Constructs a page navigation object with parent object \a parent. -*/ -QPdfPageNavigation::QPdfPageNavigation(QObject *parent) - : QObject(parent), d_ptr(new QPdfPageNavigationPrivate(this)) -{ -} - -/*! - Destroys the page navigation object. -*/ -QPdfPageNavigation::~QPdfPageNavigation() -{ -} - -/*! - \property QPdfPageNavigation::document - \brief The document instance on which this object navigates. - - By default, this property is \c nullptr. - - \sa document(), setDocument(), QPdfDocument -*/ - -/*! - Returns the document on which this object navigates, or a \c nullptr - if none has set before. - - \sa QPdfDocument -*/ -QPdfDocument* QPdfPageNavigation::document() const -{ - return d_ptr->m_document; -} - -/*! - Sets the \a document this object navigates on. - - After a new document has been set, the currentPage will be \c 0. - - \sa QPdfDocument -*/ -void QPdfPageNavigation::setDocument(QPdfDocument *document) -{ - if (d_ptr->m_document == document) - return; - - if (d_ptr->m_document) - disconnect(d_ptr->m_documentStatusChangedConnection); - - d_ptr->m_document = document; - emit documentChanged(d_ptr->m_document); - - if (d_ptr->m_document) - d_ptr->m_documentStatusChangedConnection = - connect(d_ptr->m_document.data(), &QPdfDocument::statusChanged, this, - [this]() { d_ptr->documentStatusChanged(); }); - - d_ptr->update(); -} - -/*! - \property QPdfPageNavigation::currentPage - \brief The current page number in the document. - - \sa currentPage(), setCurrentPage() -*/ - -/*! - Returns the current page number or \c 0 if there is no document set. - - After a document has been loaded, the currentPage will always be \c 0. -*/ -int QPdfPageNavigation::currentPage() const -{ - return d_ptr->m_currentPage; -} - -/*! - \fn void QPdfPageNavigation::setCurrentPage(int page) - - Sets the current \a page number. -*/ -void QPdfPageNavigation::setCurrentPage(int newPage) -{ - if (newPage < 0 || newPage >= d_ptr->m_pageCount) - return; - - if (d_ptr->m_currentPage == newPage) - return; - - d_ptr->m_currentPage = newPage; - emit currentPageChanged(d_ptr->m_currentPage); - - d_ptr->updatePrevNext(); -} - -/*! - \property QPdfPageNavigation::pageCount - \brief The number of pages in the document. - - \sa pageCount() -*/ - -/*! - Returns the number of pages in the document or \c 0 if there - is no document set. -*/ -int QPdfPageNavigation::pageCount() const -{ - return d_ptr->m_pageCount; -} - -/*! - \property QPdfPageNavigation::canGoToPreviousPage - \brief Indicates whether there is a page before the current page. - - \sa canGoToPreviousPage(), goToPreviousPage() -*/ - -/*! - Returns whether there is a page before the current one. -*/ -bool QPdfPageNavigation::canGoToPreviousPage() const -{ - return d_ptr->m_canGoToPreviousPage; -} - -/*! - \property QPdfPageNavigation::canGoToNextPage - \brief Indicates whether there is a page after the current page. - - \sa canGoToNextPage(), goToNextPage() -*/ - -/*! - Returns whether there is a page after the current one. -*/ -bool QPdfPageNavigation::canGoToNextPage() const -{ - return d_ptr->m_canGoToNextPage; -} - -/*! - Changes the current page to the previous page. - - If there is no previous page in the document, nothing happens. - - \sa canGoToPreviousPage -*/ -void QPdfPageNavigation::goToPreviousPage() -{ - if (d_ptr->m_currentPage > 0) - setCurrentPage(d_ptr->m_currentPage - 1); -} - -/*! - Changes the current page to the next page. - - If there is no next page in the document, nothing happens. - - \sa canGoToNextPage -*/ -void QPdfPageNavigation::goToNextPage() -{ - if (d_ptr->m_currentPage < d_ptr->m_pageCount - 1) - setCurrentPage(d_ptr->m_currentPage + 1); -} - -QT_END_NAMESPACE - -#include "moc_qpdfpagenavigation.cpp" diff --git a/src/pdf/qpdfpagenavigation.h b/src/pdf/qpdfpagenavigation.h deleted file mode 100644 index 9c967bad8..000000000 --- a/src/pdf/qpdfpagenavigation.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ - -#ifndef QPDFPAGENAVIGATION_H -#define QPDFPAGENAVIGATION_H - -#include <QtPdf/qtpdfglobal.h> -#include <QtCore/qobject.h> - -QT_BEGIN_NAMESPACE - -class QPdfDocument; -class QPdfPageNavigationPrivate; - -class Q_PDF_EXPORT QPdfPageNavigation : public QObject -{ - Q_OBJECT - - Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged) - - Q_PROPERTY(int currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged) - Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged) - Q_PROPERTY(bool canGoToPreviousPage READ canGoToPreviousPage NOTIFY canGoToPreviousPageChanged) - Q_PROPERTY(bool canGoToNextPage READ canGoToNextPage NOTIFY canGoToNextPageChanged) - -public: - QPdfPageNavigation() : QPdfPageNavigation(nullptr) {} - explicit QPdfPageNavigation(QObject *parent); - ~QPdfPageNavigation(); - - QPdfDocument* document() const; - void setDocument(QPdfDocument *document); - - int currentPage() const; - void setCurrentPage(int currentPage); - - int pageCount() const; - - bool canGoToPreviousPage() const; - bool canGoToNextPage() const; - -public Q_SLOTS: - void goToPreviousPage(); - void goToNextPage(); - -Q_SIGNALS: - void documentChanged(QPdfDocument *document); - void currentPageChanged(int currentPage); - void pageCountChanged(int pageCount); - void canGoToPreviousPageChanged(bool canGo); - void canGoToNextPageChanged(bool canGo); - -private: - QScopedPointer<QPdfPageNavigationPrivate> d_ptr; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/pdf/qpdfpagenavigator.cpp b/src/pdf/qpdfpagenavigator.cpp new file mode 100644 index 000000000..9e807e5cd --- /dev/null +++ b/src/pdf/qpdfpagenavigator.cpp @@ -0,0 +1,362 @@ +// Copyright (C) 2022 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 "qpdfpagenavigator.h" +#include "qpdfdocument.h" +#include "qpdflink_p.h" + +#include <QtCore/qloggingcategory.h> +#include <QtCore/qpointer.h> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(qLcNav, "qt.pdf.pagenavigator") + +struct QPdfPageNavigatorPrivate +{ + QPdfPageNavigator *q = nullptr; + + QList<QExplicitlySharedDataPointer<QPdfLinkPrivate>> pageHistory; + int currentHistoryIndex = 0; + bool changing = false; +}; + +/*! + \class QPdfPageNavigator + \since 6.4 + \inmodule QtPdf + \brief Navigation history within a PDF document. + + The QPdfPageNavigator class remembers which destinations the user + has visited in a PDF document, and provides the ability to traverse + backward and forward. It is used to implement back and forward actions + similar to the back and forward buttons in a web browser. + + \sa QPdfDocument +*/ + +/*! + Constructs a page navigation stack with parent object \a parent. +*/ +QPdfPageNavigator::QPdfPageNavigator(QObject *parent) + : QObject(parent), d(new QPdfPageNavigatorPrivate) +{ + d->q = this; + clear(); +} + +/*! + Destroys the page navigation stack. +*/ +QPdfPageNavigator::~QPdfPageNavigator() +{ +} + +/*! + Goes back to the page, location and zoom level that was being viewed before + back() was called, and then emits the \l jumped() signal. + + If a new destination was pushed since the last time \l back() was called, + the forward() function does nothing, because there is a branch in the + timeline which causes the "future" to be lost. +*/ +void QPdfPageNavigator::forward() +{ + if (d->currentHistoryIndex >= d->pageHistory.count() - 1) + return; + const bool backAvailableWas = backAvailable(); + const bool forwardAvailableWas = forwardAvailable(); + QPointF currentLocationWas = currentLocation(); + qreal currentZoomWas = currentZoom(); + ++d->currentHistoryIndex; + d->changing = true; + emit jumped(currentLink()); + if (currentZoomWas != currentZoom()) + emit currentZoomChanged(currentZoom()); + emit currentPageChanged(currentPage()); + if (currentLocationWas != currentLocation()) + emit currentLocationChanged(currentLocation()); + if (!backAvailableWas) + emit backAvailableChanged(backAvailable()); + if (forwardAvailableWas != forwardAvailable()) + emit forwardAvailableChanged(forwardAvailable()); + d->changing = false; + qCDebug(qLcNav) << "forward: index" << d->currentHistoryIndex << "page" << currentPage() + << "@" << currentLocation() << "zoom" << currentZoom(); +} + +/*! + Pops the stack, updates the \l currentPage, \l currentLocation and + \l currentZoom properties to the most-recently-viewed destination, and then + emits the \l jumped() signal. +*/ +void QPdfPageNavigator::back() +{ + if (d->currentHistoryIndex <= 0) + return; + const bool backAvailableWas = backAvailable(); + const bool forwardAvailableWas = forwardAvailable(); + QPointF currentLocationWas = currentLocation(); + qreal currentZoomWas = currentZoom(); + --d->currentHistoryIndex; + d->changing = true; + emit jumped(currentLink()); + if (currentZoomWas != currentZoom()) + emit currentZoomChanged(currentZoom()); + emit currentPageChanged(currentPage()); + if (currentLocationWas != currentLocation()) + emit currentLocationChanged(currentLocation()); + if (backAvailableWas != backAvailable()) + emit backAvailableChanged(backAvailable()); + if (!forwardAvailableWas) + emit forwardAvailableChanged(forwardAvailable()); + d->changing = false; + qCDebug(qLcNav) << "back: index" << d->currentHistoryIndex << "page" << currentPage() + << "@" << currentLocation() << "zoom" << currentZoom(); +} +/*! + \property QPdfPageNavigator::currentPage + + This property holds the current page that is being viewed. + The default is \c 0. +*/ +int QPdfPageNavigator::currentPage() const +{ + if (d->currentHistoryIndex < 0 || d->currentHistoryIndex >= d->pageHistory.count()) + return -1; // only until ctor or clear() runs + return d->pageHistory.at(d->currentHistoryIndex)->page; +} + +/*! + \property QPdfPageNavigator::currentLocation + + This property holds the current location on the page that is being viewed + (the location that was last given to jump() or update()). The default is + \c {0, 0}. +*/ +QPointF QPdfPageNavigator::currentLocation() const +{ + if (d->currentHistoryIndex < 0 || d->currentHistoryIndex >= d->pageHistory.count()) + return QPointF(); + return d->pageHistory.at(d->currentHistoryIndex)->location; +} + +/*! + \property QPdfPageNavigator::currentZoom + + This property holds the magnification scale (1 logical pixel = 1 point) + on the page that is being viewed. The default is \c 1. +*/ +qreal QPdfPageNavigator::currentZoom() const +{ + if (d->currentHistoryIndex < 0 || d->currentHistoryIndex >= d->pageHistory.count()) + return 1; + return d->pageHistory.at(d->currentHistoryIndex)->zoom; +} + +QPdfLink QPdfPageNavigator::currentLink() const +{ + if (d->currentHistoryIndex < 0 || d->currentHistoryIndex >= d->pageHistory.count()) + return QPdfLink(); + return QPdfLink(d->pageHistory.at(d->currentHistoryIndex).data()); +} + +/*! + Clear the history and restore \l currentPage, \l currentLocation and + \l currentZoom to their default values. +*/ +void QPdfPageNavigator::clear() +{ + d->pageHistory.clear(); + d->currentHistoryIndex = 0; + // Begin with an implicit jump to page 0, so that + // backAvailable() will become true after jump() is called one more time. + d->pageHistory.append(QExplicitlySharedDataPointer<QPdfLinkPrivate>(new QPdfLinkPrivate(0, {}, 1))); +} + +/*! + Adds the given \a destination to the history of visited locations. + + In this case, PDF views respond to the \l jumped signal by scrolling to + place \c destination.rectangles in the viewport, as opposed to placing + \c destination.location in the viewport. So it's appropriate to call this + method to jump to a search result from QPdfSearchModel (because the + rectangles cover the region of text found). To jump to a hyperlink + destination, call jump(page, location, zoom) instead, because in that + case the QPdfLink object's \c rectangles cover the hyperlink origin + location rather than the destination. +*/ +void QPdfPageNavigator::jump(QPdfLink destination) +{ + const bool zoomChange = !qFuzzyCompare(destination.zoom(), currentZoom()); + const bool pageChange = (destination.page() != currentPage()); + const bool locationChange = (destination.location() != currentLocation()); + const bool backAvailableWas = backAvailable(); + const bool forwardAvailableWas = forwardAvailable(); + if (!d->changing) { + if (d->currentHistoryIndex >= 0 && forwardAvailableWas) + d->pageHistory.remove(d->currentHistoryIndex + 1, d->pageHistory.count() - d->currentHistoryIndex - 1); + d->pageHistory.append(destination.d); + d->currentHistoryIndex = d->pageHistory.count() - 1; + } + if (zoomChange) + emit currentZoomChanged(currentZoom()); + if (pageChange) + emit currentPageChanged(currentPage()); + if (locationChange) + emit currentLocationChanged(currentLocation()); + if (d->changing) + return; + if (!backAvailableWas) + emit backAvailableChanged(backAvailable()); + if (forwardAvailableWas) + emit forwardAvailableChanged(forwardAvailable()); + emit jumped(currentLink()); + qCDebug(qLcNav) << "push: index" << d->currentHistoryIndex << destination << "-> history" << + [this]() { + QStringList ret; + for (auto d : d->pageHistory) + ret << QString::number(d->page); + return ret.join(QLatin1Char(',')); + }(); +} + +/*! + Adds the given destination, consisting of \a page, \a location, and \a zoom, + to the history of visited locations. + + The \a zoom argument represents magnification (where \c 1 is the default + scale, 1 logical pixel = 1 point). If \a zoom is not given or is \c 0, + currentZoom keeps its existing value, and currentZoomChanged is not emitted. + + The \a location should be the same as QPdfLink::location() if the user is + following a link; and since that is specified as the upper-left corner of + the destination, it is best for consistency to always use the location + visible in the upper-left corner of the viewport, in points. + + If forwardAvailable is \c true, calling this function represents a branch + in the timeline which causes the "future" to be lost, and therefore + forwardAvailable will change to \c false. +*/ +void QPdfPageNavigator::jump(int page, const QPointF &location, qreal zoom) +{ + if (page == currentPage() && location == currentLocation() && zoom == currentZoom()) + return; + if (qFuzzyIsNull(zoom)) + zoom = currentZoom(); + const bool zoomChange = !qFuzzyCompare(zoom, currentZoom()); + const bool pageChange = (page != currentPage()); + const bool locationChange = (location != currentLocation()); + const bool backAvailableWas = backAvailable(); + const bool forwardAvailableWas = forwardAvailable(); + if (!d->changing) { + if (d->currentHistoryIndex >= 0 && forwardAvailableWas) + d->pageHistory.remove(d->currentHistoryIndex + 1, d->pageHistory.count() - d->currentHistoryIndex - 1); + d->pageHistory.append(QExplicitlySharedDataPointer<QPdfLinkPrivate>(new QPdfLinkPrivate(page, location, zoom))); + d->currentHistoryIndex = d->pageHistory.count() - 1; + } + if (zoomChange) + emit currentZoomChanged(currentZoom()); + if (pageChange) + emit currentPageChanged(currentPage()); + if (locationChange) + emit currentLocationChanged(currentLocation()); + if (d->changing) + return; + if (!backAvailableWas) + emit backAvailableChanged(backAvailable()); + if (forwardAvailableWas) + emit forwardAvailableChanged(forwardAvailable()); + emit jumped(currentLink()); + qCDebug(qLcNav) << "push: index" << d->currentHistoryIndex << "page" << page + << "@" << location << "zoom" << zoom << "-> history" << + [this]() { + QStringList ret; + for (auto d : d->pageHistory) + ret << QString::number(d->page); + return ret.join(QLatin1Char(',')); + }(); +} + +/*! + Modifies the current destination, consisting of \a page, \a location and \a zoom. + + This can be called periodically while the user is manually moving around + the document, so that after back() is called, forward() will jump back to + the most-recently-viewed destination rather than the destination that was + last specified by push(). + + The \c currentZoomChanged, \c currentPageChanged and \c currentLocationChanged + signals will be emitted if the respective properties are actually changed. + The \l jumped signal is not emitted, because this operation represents + smooth movement rather than a navigational jump. +*/ +void QPdfPageNavigator::update(int page, const QPointF &location, qreal zoom) +{ + if (d->currentHistoryIndex < 0 || d->currentHistoryIndex >= d->pageHistory.count()) + return; + int currentPageWas = currentPage(); + QPointF currentLocationWas = currentLocation(); + qreal currentZoomWas = currentZoom(); + if (page == currentPageWas && location == currentLocationWas && zoom == currentZoomWas) + return; + d->pageHistory[d->currentHistoryIndex]->page = page; + d->pageHistory[d->currentHistoryIndex]->location = location; + d->pageHistory[d->currentHistoryIndex]->zoom = zoom; + if (currentZoomWas != zoom) + emit currentZoomChanged(currentZoom()); + if (currentPageWas != page) + emit currentPageChanged(currentPage()); + if (currentLocationWas != location) + emit currentLocationChanged(currentLocation()); + qCDebug(qLcNav) << "update: index" << d->currentHistoryIndex << "page" << page + << "@" << location << "zoom" << zoom << "-> history" << + [this]() { + QStringList ret; + for (auto d : d->pageHistory) + ret << QString::number(d->page); + return ret.join(QLatin1Char(',')); + }(); +} + +/*! + \property QPdfPageNavigator::backAvailable + \readonly + + Holds \c true if a \e back destination is available in the history: + that is, if push() or forward() has been called. +*/ +bool QPdfPageNavigator::backAvailable() const +{ + return d->currentHistoryIndex > 0; +} + +/*! + \property QPdfPageNavigator::forwardAvailable + \readonly + + Holds \c true if a \e forward destination is available in the history: + that is, if back() has been previously called. +*/ +bool QPdfPageNavigator::forwardAvailable() const +{ + return d->currentHistoryIndex < d->pageHistory.count() - 1; +} + +/*! + \fn void QPdfPageNavigator::jumped(QPdfLink current) + + This signal is emitted when an abrupt jump occurs, to the \a current + page index, location on the page, and zoom level; but \e not when simply + scrolling through the document one page at a time. That is, jump(), + forward() and back() emit this signal, but update() does not. + + If \c {current.rectangles.length > 0}, they are rectangles that cover + a specific destination area: a search result that should be made + visible; otherwise, \c {current.location} is the destination location on + the \c page (a hyperlink destination, or during forward/back navigation). +*/ + +QT_END_NAMESPACE + +#include "moc_qpdfpagenavigator.cpp" diff --git a/src/pdf/qpdfpagenavigator.h b/src/pdf/qpdfpagenavigator.h new file mode 100644 index 000000000..cec89ef5a --- /dev/null +++ b/src/pdf/qpdfpagenavigator.h @@ -0,0 +1,62 @@ +// Copyright (C) 2022 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 QPDFPAGENAVIGATOR_H +#define QPDFPAGENAVIGATOR_H + +#include <QtPdf/qtpdfglobal.h> +#include <QtPdf/qpdflink.h> +#include <QtCore/qobject.h> + +QT_BEGIN_NAMESPACE + +struct QPdfPageNavigatorPrivate; + +class Q_PDF_EXPORT QPdfPageNavigator : public QObject +{ + Q_OBJECT + + Q_PROPERTY(int currentPage READ currentPage NOTIFY currentPageChanged) + Q_PROPERTY(QPointF currentLocation READ currentLocation NOTIFY currentLocationChanged) + Q_PROPERTY(qreal currentZoom READ currentZoom NOTIFY currentZoomChanged) + Q_PROPERTY(bool backAvailable READ backAvailable NOTIFY backAvailableChanged) + Q_PROPERTY(bool forwardAvailable READ forwardAvailable NOTIFY forwardAvailableChanged) + +public: + QPdfPageNavigator() : QPdfPageNavigator(nullptr) {} + explicit QPdfPageNavigator(QObject *parent); + ~QPdfPageNavigator() override; + + int currentPage() const; + QPointF currentLocation() const; + qreal currentZoom() const; + + bool backAvailable() const; + bool forwardAvailable() const; + +public Q_SLOTS: + void clear(); + void jump(QPdfLink destination); + void jump(int page, const QPointF &location, qreal zoom = 0); + void update(int page, const QPointF &location, qreal zoom); + void forward(); + void back(); + +Q_SIGNALS: + void currentPageChanged(int page); + void currentLocationChanged(QPointF location); + void currentZoomChanged(qreal zoom); + void backAvailableChanged(bool available); + void forwardAvailableChanged(bool available); + void jumped(QPdfLink current); + +protected: + QPdfLink currentLink() const; + +private: + QScopedPointer<QPdfPageNavigatorPrivate> d; +}; + +QT_END_NAMESPACE + +#endif // QPDFPAGENAVIGATOR_H diff --git a/src/pdf/qpdfpagerenderer.cpp b/src/pdf/qpdfpagerenderer.cpp index 9d0ff18f7..e46261817 100644 --- a/src/pdf/qpdfpagerenderer.cpp +++ b/src/pdf/qpdfpagerenderer.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qpdfpagerenderer.h" @@ -125,7 +89,7 @@ void RenderWorker::requestPage(quint64 requestId, int pageNumber, QSize imageSiz { const QMutexLocker locker(&m_mutex); - if (!m_document || m_document->status() != QPdfDocument::Ready) + if (!m_document || m_document->status() != QPdfDocument::Status::Ready) return; const QImage image = m_document->render(pageNumber, imageSize, options); @@ -315,7 +279,7 @@ void QPdfPageRenderer::setDocument(QPdfDocument *document) quint64 QPdfPageRenderer::requestPage(int pageNumber, QSize imageSize, QPdfDocumentRenderOptions options) { - if (!d_ptr->m_document || d_ptr->m_document->status() != QPdfDocument::Ready) + if (!d_ptr->m_document || d_ptr->m_document->status() != QPdfDocument::Status::Ready) return 0; for (const auto &request : qAsConst(d_ptr->m_pendingRequests)) { @@ -343,3 +307,4 @@ quint64 QPdfPageRenderer::requestPage(int pageNumber, QSize imageSize, QT_END_NAMESPACE #include "qpdfpagerenderer.moc" +#include "moc_qpdfpagerenderer.cpp" diff --git a/src/pdf/qpdfpagerenderer.h b/src/pdf/qpdfpagerenderer.h index 0898e03ea..cb9be06fe 100644 --- a/src/pdf/qpdfpagerenderer.h +++ b/src/pdf/qpdfpagerenderer.h @@ -1,42 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> +// Copyright (C) 2020 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 QPDFPAGERENDERER_H #define QPDFPAGERENDERER_H @@ -82,7 +46,7 @@ public: Q_SIGNALS: void documentChanged(QPdfDocument *document); - void renderModeChanged(RenderMode renderMode); + void renderModeChanged(QPdfPageRenderer::RenderMode renderMode); void pageRendered(int pageNumber, QSize imageSize, const QImage &image, QPdfDocumentRenderOptions options, quint64 requestId); diff --git a/src/pdf/qpdfsearchmodel.cpp b/src/pdf/qpdfsearchmodel.cpp index e515cabfd..e8946ea86 100644 --- a/src/pdf/qpdfsearchmodel.cpp +++ b/src/pdf/qpdfsearchmodel.cpp @@ -1,47 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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 "qpdfdestination.h" +// Copyright (C) 2020 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 "qpdfdocument_p.h" +#include "qpdflink.h" +#include "qpdflink_p.h" #include "qpdfsearchmodel.h" #include "qpdfsearchmodel_p.h" -#include "qpdfsearchresult_p.h" #include "third_party/pdfium/public/fpdf_doc.h" #include "third_party/pdfium/public/fpdf_text.h" @@ -58,11 +22,44 @@ static const int UpdateTimerInterval = 100; static const int ContextChars = 64; static const double CharacterHitTolerance = 6.0; +/*! + \class QPdfSearchModel + \since 5.15 + \inmodule QtPdf + \inherits QAbstractListModel + + \brief The QPdfSearchModel class searches for a string in a PDF document + and holds the results. + + This is used in the \l {Model/View Programming} paradigm to display + a list of search results, to highlight them on the rendered PDF pages, + and to iterate through them using the "search forward" / "search backward" + buttons and shortcuts that would be found in a typical document-viewing UI: + + \image search-results.png +*/ + +/*! + \enum QPdfSearchModel::Role + + \value Page The page number where the search result is found (int). + \value IndexOnPage The index of the search result on the page (int). + \value Location The position of the search result on the page (QPointF). + \value ContextBefore The adjacent text on the page, before the search string (QString). + \value ContextAfter The adjacent text on the page, after the search string (QString). + \omitvalue NRoles + + \sa QPdfLink +*/ + +/*! + Constructs a new search model with parent object \a parent. +*/ QPdfSearchModel::QPdfSearchModel(QObject *parent) : QAbstractListModel(*(new QPdfSearchModelPrivate()), parent) { QMetaEnum rolesMetaEnum = metaObject()->enumerator(metaObject()->indexOfEnumerator("Role")); - for (int r = Qt::UserRole; r < int(Role::_Count); ++r) { + for (int r = Qt::UserRole; r < int(Role::NRoles); ++r) { QByteArray roleName = QByteArray(rolesMetaEnum.valueToKey(r)); if (roleName.isEmpty()) continue; @@ -71,13 +68,24 @@ QPdfSearchModel::QPdfSearchModel(QObject *parent) } } +/*! + Destroys the model. +*/ QPdfSearchModel::~QPdfSearchModel() {} +/*! + \reimp +*/ QHash<int, QByteArray> QPdfSearchModel::roleNames() const { return m_roleNames; } +/*! + \reimp + + The number of rows in the model is equal to the number of search results found. +*/ int QPdfSearchModel::rowCount(const QModelIndex &parent) const { Q_D(const QPdfSearchModel); @@ -85,6 +93,9 @@ int QPdfSearchModel::rowCount(const QModelIndex &parent) const return d->rowCountSoFar; } +/*! + \reimp +*/ QVariant QPdfSearchModel::data(const QModelIndex &index, int role) const { Q_D(const QPdfSearchModel); @@ -102,7 +113,7 @@ QVariant QPdfSearchModel::data(const QModelIndex &index, int role) const return d->searchResults[pi.page][pi.index].contextBefore(); case Role::ContextAfter: return d->searchResults[pi.page][pi.index].contextAfter(); - case Role::_Count: + case Role::NRoles: break; } if (role == Qt::DisplayRole) { @@ -120,6 +131,10 @@ void QPdfSearchModel::updatePage(int page) d->doSearch(page); } +/*! + \property QPdfSearchModel::searchString + \brief the string to search for +*/ QString QPdfSearchModel::searchString() const { Q_D(const QPdfSearchModel); @@ -139,7 +154,10 @@ void QPdfSearchModel::setSearchString(const QString &searchString) endResetModel(); } -QList<QPdfSearchResult> QPdfSearchModel::resultsOnPage(int page) const +/*! + Returns the list of all results found on the given \a page. +*/ +QList<QPdfLink> QPdfSearchModel::resultsOnPage(int page) const { Q_D(const QPdfSearchModel); const_cast<QPdfSearchModelPrivate *>(d)->doSearch(page); @@ -148,15 +166,23 @@ QList<QPdfSearchResult> QPdfSearchModel::resultsOnPage(int page) const return d->searchResults[page]; } -QPdfSearchResult QPdfSearchModel::resultAtIndex(int index) const +/*! + Returns a result found by \a index in the \l document, regardless of the + page on which it was found. \a index must be less than \l rowCount. +*/ +QPdfLink QPdfSearchModel::resultAtIndex(int index) const { Q_D(const QPdfSearchModel); const auto pi = const_cast<QPdfSearchModelPrivate*>(d)->pageAndIndexForResult(index); if (pi.page < 0) - return QPdfSearchResult(); + return {}; return d->searchResults[pi.page][pi.index]; } +/*! + \property QPdfSearchModel::document + \brief the document to search +*/ QPdfDocument *QPdfSearchModel::document() const { Q_D(const QPdfSearchModel); @@ -230,7 +256,7 @@ bool QPdfSearchModelPrivate::doSearch(int page) return false; } FPDF_SCHHANDLE sh = FPDFText_FindStart(textPage, searchString.utf16(), 0, 0); - QList<QPdfSearchResult> newSearchResults; + QList<QPdfLink> newSearchResults; while (FPDFText_FindNext(sh)) { int idx = FPDFText_GetSchResultIndex(sh); int count = FPDFText_GetSchCount(sh); @@ -276,7 +302,7 @@ bool QPdfSearchModelPrivate::doSearch(int page) } } if (!rects.isEmpty()) - newSearchResults << QPdfSearchResult(page, rects, contextBefore, contextAfter); + newSearchResults << QPdfLink(page, rects, contextBefore, contextAfter); } FPDFText_FindClose(sh); FPDFText_ClosePage(textPage); @@ -298,6 +324,8 @@ bool QPdfSearchModelPrivate::doSearch(int page) QPdfSearchModelPrivate::PageAndIndex QPdfSearchModelPrivate::pageAndIndexForResult(int resultIndex) { + if (pagesSearched.isEmpty()) + return {-1, -1}; const int pageCount = document->pageCount(); int totalSoFar = 0; int previousTotalSoFar = 0; diff --git a/src/pdf/qpdfsearchmodel.h b/src/pdf/qpdfsearchmodel.h index d051fdc40..c1e4e64ec 100644 --- a/src/pdf/qpdfsearchmodel.h +++ b/src/pdf/qpdfsearchmodel.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2020 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 QPDFSEARCHMODEL_H #define QPDFSEARCHMODEL_H @@ -44,7 +8,7 @@ #include <QtCore/qabstractitemmodel.h> #include <QtPdf/qpdfdocument.h> -#include <QtPdf/qpdfsearchresult.h> +#include <QtPdf/qpdflink.h> QT_BEGIN_NAMESPACE @@ -63,15 +27,15 @@ public: Location, ContextBefore, ContextAfter, - _Count + NRoles }; Q_ENUM(Role) QPdfSearchModel() : QPdfSearchModel(nullptr) {} explicit QPdfSearchModel(QObject *parent); - ~QPdfSearchModel(); + ~QPdfSearchModel() override; - QList<QPdfSearchResult> resultsOnPage(int page) const; - QPdfSearchResult resultAtIndex(int index) const; + QList<QPdfLink> resultsOnPage(int page) const; + QPdfLink resultAtIndex(int index) const; QPdfDocument *document() const; QString searchString() const; diff --git a/src/pdf/qpdfsearchmodel_p.h b/src/pdf/qpdfsearchmodel_p.h index 3b89f5f35..4922c81e9 100644 --- a/src/pdf/qpdfsearchmodel_p.h +++ b/src/pdf/qpdfsearchmodel_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2020 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 QPDFSEARCHMODEL_P_H #define QPDFSEARCHMODEL_P_H @@ -52,7 +16,6 @@ // #include "qpdfsearchmodel.h" -#include "qpdfsearchresult_p.h" #include <private/qabstractitemmodel_p.h> #include "third_party/pdfium/public/fpdfview.h" @@ -78,7 +41,7 @@ public: QPdfDocument *document = nullptr; QString searchString; QList<bool> pagesSearched; - QList<QList<QPdfSearchResult>> searchResults; + QList<QList<QPdfLink>> searchResults; int rowCountSoFar = 0; int updateTimerId = -1; int nextPageToUpdate = 0; diff --git a/src/pdf/qpdfsearchresult.cpp b/src/pdf/qpdfsearchresult.cpp deleted file mode 100644 index 7c096868a..000000000 --- a/src/pdf/qpdfsearchresult.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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 "qpdfsearchresult.h" -#include "qpdfsearchresult_p.h" - -QT_BEGIN_NAMESPACE - -QPdfSearchResult::QPdfSearchResult() : - QPdfSearchResult(new QPdfSearchResultPrivate()) { } - -QPdfSearchResult::QPdfSearchResult(int page, QList<QRectF> rects, - QString contextBefore, QString contextAfter) - : QPdfSearchResult(new QPdfSearchResultPrivate(page, std::move(rects), - std::move(contextBefore), - std::move(contextAfter))) -{ -} - -QPdfSearchResult::QPdfSearchResult(QPdfSearchResultPrivate *d) : - QPdfDestination(static_cast<QPdfDestinationPrivate *>(d)) { } - -QPdfSearchResult::~QPdfSearchResult() = default; - -QString QPdfSearchResult::contextBefore() const -{ - return static_cast<QPdfSearchResultPrivate *>(d.data())->contextBefore; -} - -QString QPdfSearchResult::contextAfter() const -{ - return static_cast<QPdfSearchResultPrivate *>(d.data())->contextAfter; -} - -QList<QRectF> QPdfSearchResult::rectangles() const -{ - return static_cast<QPdfSearchResultPrivate *>(d.data())->rects; -} - -QDebug operator<<(QDebug dbg, const QPdfSearchResult &searchResult) -{ - QDebugStateSaver saver(dbg); - dbg.nospace(); - dbg << "QPdfSearchResult(page=" << searchResult.page() - << " contextBefore=" << searchResult.contextBefore() - << " contextAfter=" << searchResult.contextAfter() - << " rects=" << searchResult.rectangles(); - dbg << ')'; - return dbg; -} - -QT_END_NAMESPACE - -#include "moc_qpdfsearchresult.cpp" diff --git a/src/pdf/qpdfsearchresult.h b/src/pdf/qpdfsearchresult.h deleted file mode 100644 index f191b0082..000000000 --- a/src/pdf/qpdfsearchresult.h +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ - -#ifndef QPDFSEARCHRESULT_H -#define QPDFSEARCHRESULT_H - -#include <QtCore/qdebug.h> -#include <QtCore/qlist.h> -#include <QtCore/qrect.h> -#include <QtPdf/qpdfdestination.h> - -QT_BEGIN_NAMESPACE - -class QPdfSearchResultPrivate; - -class QPdfSearchResult : public QPdfDestination -{ - Q_GADGET_EXPORT(Q_PDF_EXPORT) - Q_PROPERTY(QString contextBefore READ contextBefore) - Q_PROPERTY(QString contextAfter READ contextAfter) - Q_PROPERTY(QList<QRectF> rectangles READ rectangles) - -public: - Q_PDF_EXPORT QPdfSearchResult(); - Q_PDF_EXPORT ~QPdfSearchResult(); - - Q_PDF_EXPORT QString contextBefore() const; - Q_PDF_EXPORT QString contextAfter() const; - Q_PDF_EXPORT QList<QRectF> rectangles() const; - -private: - QPdfSearchResult(int page, QList<QRectF> rects, QString contextBefore, QString contextAfter); - QPdfSearchResult(QPdfSearchResultPrivate *d); - friend class QPdfDocument; - friend class QPdfSearchModelPrivate; - friend class QQuickPdfNavigationStack; -}; -Q_DECLARE_SHARED(QPdfSearchResult) - -Q_PDF_EXPORT QDebug operator<<(QDebug, const QPdfSearchResult &); - -QT_END_NAMESPACE - -#endif // QPDFSEARCHRESULT_H diff --git a/src/pdf/qpdfsearchresult_p.h b/src/pdf/qpdfsearchresult_p.h deleted file mode 100644 index 2ad25aa6a..000000000 --- a/src/pdf/qpdfsearchresult_p.h +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ - -#ifndef QPDFSEARCHRESULT_P_H -#define QPDFSEARCHRESULT_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 "qpdfsearchresult.h" - -#include "qpdfdestination_p.h" - -QT_BEGIN_NAMESPACE - -class QPdfSearchResultPrivate : public QPdfDestinationPrivate -{ -public: - QPdfSearchResultPrivate() = default; - QPdfSearchResultPrivate(int page, QList<QRectF> rects, QString contextBefore, QString contextAfter) : - QPdfDestinationPrivate(page, rects.first().topLeft(), 0), - contextBefore{std::move(contextBefore)}, - contextAfter{std::move(contextAfter)}, - rects{std::move(rects)} {} - - QString contextBefore; - QString contextAfter; - QList<QRectF> rects; -}; - -QT_END_NAMESPACE - -#endif // QPDFSEARCHRESULT_P_H diff --git a/src/pdf/qpdfselection.cpp b/src/pdf/qpdfselection.cpp index 514d8a0e3..df30eb353 100644 --- a/src/pdf/qpdfselection.cpp +++ b/src/pdf/qpdfselection.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2020 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 "qpdfselection.h" #include "qpdfselection_p.h" diff --git a/src/pdf/qpdfselection.h b/src/pdf/qpdfselection.h index dbd9dff46..8fcfaf2d8 100644 --- a/src/pdf/qpdfselection.h +++ b/src/pdf/qpdfselection.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2020 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 QPDFSELECTION_H #define QPDFSELECTION_H diff --git a/src/pdf/qpdfselection_p.h b/src/pdf/qpdfselection_p.h index b30565362..541480746 100644 --- a/src/pdf/qpdfselection_p.h +++ b/src/pdf/qpdfselection_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2020 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 QPDFSELECTION_P_H #define QPDFSELECTION_P_H diff --git a/src/pdf/qtpdfglobal.h b/src/pdf/qtpdfglobal.h index b31917b63..d38eafaab 100644 --- a/src/pdf/qtpdfglobal.h +++ b/src/pdf/qtpdfglobal.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF 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$ -** -****************************************************************************/ +// Copyright (C) 2020 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 QTPDFGLOBAL_H #define QTPDFGLOBAL_H |