diff options
Diffstat (limited to 'src/pdf')
105 files changed, 3252 insertions, 7161 deletions
diff --git a/src/pdf/CMakeLists.txt b/src/pdf/CMakeLists.txt new file mode 100644 index 000000000..4a54b816e --- /dev/null +++ b/src/pdf/CMakeLists.txt @@ -0,0 +1,260 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.19) +find_package(Ninja 1.7.2 REQUIRED) +find_package(Nodejs 14.19 REQUIRED) +find_package(PkgConfig) +if(PkgConfig_FOUND) + create_pkg_config_host_wrapper(${CMAKE_CURRENT_BINARY_DIR}) +endif() + +set(buildDir "${CMAKE_CURRENT_BINARY_DIR}") + +## +# PDF MODULE +## + +qt_internal_add_module(Pdf + SOURCES + qpdfbookmarkmodel.cpp qpdfbookmarkmodel.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.h qpdflinkmodel_p.h + qpdfpagenavigator.cpp qpdfpagenavigator.h + qpdfpagerenderer.cpp qpdfpagerenderer.h + qpdfsearchmodel.cpp qpdfsearchmodel.h qpdfsearchmodel_p.h + qpdfselection.cpp qpdfselection.h qpdfselection_p.h + qtpdfglobal.h + INCLUDE_DIRECTORIES + ../3rdparty/chromium + DEFINES + QT_BUILD_PDF_LIB + LIBRARIES + Qt::CorePrivate + Qt::Network + PUBLIC_LIBRARIES + Qt::Core + Qt::Gui + GENERATE_CPP_EXPORTS +) + +add_subdirectory(plugins/imageformats/pdf) + +get_install_config(config) +get_architectures(archs) +list(GET archs 0 arch) + +## +# PDF DOCS +## + +qt_internal_add_docs(Pdf + doc/qtpdf.qdocconf +) + +add_code_attributions_target( + TARGET generate_pdf_attributions + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pdf_attributions.qdoc + GN_TARGET :QtPdf + FILE_TEMPLATE doc/about_credits.tmpl + ENTRY_TEMPLATE doc/about_credits_entry.tmpl + BUILDDIR ${buildDir}/${config}/${arch} +) +add_dependencies(generate_pdf_attributions run_pdf_GnDone) +add_dependencies(prepare_docs_Pdf generate_pdf_attributions) + +## +# TOOLCHAIN SETUP +## + +if(LINUX OR MINGW OR ANDROID) + setup_toolchains() +endif() + +## +# GN BUILD SETUP +## + +addSyncTargets(pdf) + +get_configs(configs) +get_architectures(archs) +foreach(arch ${archs}) + foreach(config ${configs}) + + ## + # BULID.gn SETUP + ## + + set(buildGn pdf_${config}_${arch}) + add_gn_target(${buildGn} ${config} ${arch} + SOURCES DEFINES CXX_COMPILE_OPTIONS C_COMPILE_OPTIONS + INCLUDES MOC_PATH PNG_INCLUDES JPEG_INCLUDES HARFBUZZ_INCLUDES + FREETYPE_INCLUDES ZLIB_INCLUDES + ) + resolve_target_includes(gnIncludes Pdf) + get_forward_declaration_macro(forwardDeclarationMacro) + + extend_gn_target(${buildGn} + INCLUDES + ${gnIncludes} + ) + + ## + # GN PARAMETERS + ## + + unset(gnArgArg) + append_build_type_setup(gnArgArg) + append_compiler_linker_sdk_setup(gnArgArg) + append_sanitizer_setup(gnArgArg) + append_toolchain_setup(gnArgArg) + append_pkg_config_setup(gnArgArg) + + list(APPEND gnArgArg + qtwebengine_target="${buildDir}/${config}/${arch}:QtPdf" + qt_libpng_config="${buildDir}/${config}/${arch}:qt_libpng_config" + qt_libjpeg_config="${buildDir}/${config}/${arch}:qt_libjpeg_config" + qt_harfbuzz_config="${buildDir}/${config}/${arch}:qt_harfbuzz_config" + qt_freetype_config="${buildDir}/${config}/${arch}:qt_freetype_config" + enable_swiftshader=false + enable_swiftshader_vulkan=false + angle_enable_swiftshader=false + dawn_use_swiftshader=false + use_dawn=false + build_dawn_tests=false + enable_ipc_fuzzer=false + enable_remoting=false + enable_resource_allowlist_generation=false + enable_vr=false + enable_web_speech=false + chrome_pgo_phase=0 + strip_absolute_paths_from_debug_symbols=false + use_perfetto_client_library=false + v8_enable_webassembly=false + ) + + if(LINUX OR ANDROID) + list(APPEND gnArgArg + is_cfi=false + ozone_auto_platforms=false + enable_arcore=false + use_ml_inliner=false + ) + extend_gn_list(gnArgArg + ARGS use_system_icu + CONDITION QT_FEATURE_webengine_system_icu + ) + extend_gn_list(gnArgArg + ARGS use_system_libopenjpeg2 + CONDITION QT_FEATURE_webengine_system_libopenjpeg2 + ) + endif() + if(MACOS) + list(APPEND gnArgArg angle_enable_vulkan=false) + endif() + if(IOS) + list(APPEND gnArgArg enable_base_tracing=false) + extend_gn_list(gnArgArg + ARGS enable_ios_bitcode + CONDITION QT_FEATURE_pdf_bitcode + ) + endif() + if(WIN32 OR ANDROID) + list(APPEND gnArgArg + ninja_use_custom_environment_files=false + safe_browsing_mode=0 + ) + extend_gn_list(gnArgArg + ARGS qt_uses_static_runtime + CONDITION QT_FEATURE_pdf_static_runtime + ) + endif() + + extend_gn_list(gnArgArg + ARGS pdf_enable_v8 + CONDITION QT_FEATURE_pdf_v8 + ) + extend_gn_list(gnArgArg + ARGS pdf_enable_xfa + CONDITION QT_FEATURE_pdf_xfa + ) + extend_gn_list(gnArgArg + ARGS pdf_enable_xfa_bmp + CONDITION QT_FEATURE_pdf_xfa_bmp + ) + extend_gn_list(gnArgArg + ARGS pdf_enable_xfa_gif + CONDITION QT_FEATURE_pdf_xfa_gif + ) + extend_gn_list(gnArgArg + ARGS pdf_enable_xfa_png + CONDITION QT_FEATURE_pdf_xfa_png + ) + extend_gn_list(gnArgArg + ARGS pdf_enable_xfa_tiff + CONDITION QT_FEATURE_pdf_xfa_tiff + ) + extend_gn_list(gnArgArg + ARGS pdfium_use_system_zlib use_system_zlib + CONDITION QT_FEATURE_webengine_system_zlib + ) + extend_gn_list(gnArgArg + ARGS pdfium_use_system_libpng use_system_libpng + CONDITION QT_FEATURE_webengine_system_libpng + ) + extend_gn_list(gnArgArg + ARGS pdfium_use_qt_libpng + CONDITION QT_FEATURE_webengine_qt_libpng + ) + extend_gn_list(gnArgArg + ARGS pdfium_use_system_libtiff + CONDITION QT_FEATURE_webengine_system_libtiff + ) + extend_gn_list(gnArgArg + ARGS use_qt_libjpeg + CONDITION QT_FEATURE_webengine_qt_libjpeg + ) + extend_gn_list(gnArgArg + ARGS use_qt_harfbuzz + CONDITION QT_FEATURE_webengine_qt_harfbuzz + ) + extend_gn_list(gnArgArg + ARGS use_qt_freetype + CONDITION QT_FEATURE_webengine_qt_freetype + ) + + add_gn_command( + CMAKE_TARGET Pdf + NINJA_TARGETS QtPdf + GN_TARGET ${buildGn} + GN_ARGS ${gnArgArg} + BUILDDIR ${buildDir}/${config}/${arch} + MODULE pdf + ) + + endforeach() + create_cxx_configs(Pdf ${arch}) +endforeach() + + +## +# PDF SETUP +## + +get_architectures(archs) +list(GET archs 0 arch) +target_include_directories(Pdf PRIVATE ${buildDir}/$<CONFIG>/${arch}/gen) +add_gn_build_artifacts_to_target( + CMAKE_TARGET Pdf + NINJA_TARGET QtPdf + MODULE pdf + BUILDDIR ${buildDir} + COMPLETE_STATIC TRUE + NINJA_STAMP QtPdf.stamp +) +add_dependencies(Pdf run_pdf_NinjaDone) + diff --git a/src/pdf/api/qpdfbookmarkmodel.h b/src/pdf/api/qpdfbookmarkmodel.h deleted file mode 100644 index 8e06a1547..000000000 --- a/src/pdf/api/qpdfbookmarkmodel.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPDFBOOKMARKMODEL_H -#define QPDFBOOKMARKMODEL_H - -#include <QtPdf/qtpdfglobal.h> -#include <QtCore/qabstractitemmodel.h> - -QT_BEGIN_NAMESPACE - -class QPdfDocument; -class 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 - { - TreeMode, - ListMode - }; - Q_ENUM(StructureMode) - - enum Role - { - TitleRole = Qt::DisplayRole, - LevelRole = Qt::UserRole, - PageNumberRole - }; - Q_ENUM(Role) - - explicit QPdfBookmarkModel(QObject *parent = nullptr); - - 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; - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override; - QHash<int, QByteArray> roleNames() const override; - -Q_SIGNALS: - void documentChanged(QPdfDocument *document); - void structureModeChanged(QPdfBookmarkModel::StructureMode structureMode); - -private: - Q_DECLARE_PRIVATE(QPdfBookmarkModel) - - Q_PRIVATE_SLOT(d_func(), void _q_documentStatusChanged()) -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/pdf/api/qpdfdestination.h b/src/pdf/api/qpdfdestination.h deleted file mode 100644 index f9c186ff6..000000000 --- a/src/pdf/api/qpdfdestination.h +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.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 Q_PDF_EXPORT QPdfDestination -{ - Q_GADGET - 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: - ~QPdfDestination(); - QPdfDestination(const QPdfDestination &other); - QPdfDestination &operator=(const QPdfDestination &other); - QPdfDestination(QPdfDestination &&other) noexcept; - QPdfDestination &operator=(QPdfDestination &&other) noexcept { swap(other); return *this; } - void swap(QPdfDestination &other) noexcept { d.swap(other.d); } - bool isValid() const; - int page() const; - QPointF location() const; - 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_PDF_EXPORT QDebug operator<<(QDebug, const QPdfDestination &); - -QT_END_NAMESPACE - -#endif // QPDFDESTINATION_H diff --git a/src/pdf/api/qpdfdestination_p.h b/src/pdf/api/qpdfdestination_p.h deleted file mode 100644 index 3520fb795..000000000 --- a/src/pdf/api/qpdfdestination_p.h +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.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 <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/api/qpdfdocument.h b/src/pdf/api/qpdfdocument.h deleted file mode 100644 index 54ca687fa..000000000 --- a/src/pdf/api/qpdfdocument.h +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPDFDOCUMENT_H -#define QPDFDOCUMENT_H - -#include <QtPdf/qtpdfglobal.h> - -#include <QtCore/qobject.h> -#include <QtGui/qimage.h> -#include <QtPdf/qpdfdocumentrenderoptions.h> -#include <QtPdf/qpdfselection.h> - -QT_BEGIN_NAMESPACE - -class QPdfDocumentPrivate; -class QNetworkReply; - -class Q_PDF_EXPORT QPdfDocument : public QObject -{ - Q_OBJECT - - 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) - -public: - enum Status { - Null, - Loading, - Ready, - Unloading, - Error - }; - Q_ENUM(Status) - - enum DocumentError { - NoError, - UnknownError, - DataNotYetAvailableError, - FileNotFoundError, - InvalidFileFormatError, - IncorrectPasswordError, - UnsupportedSecuritySchemeError - }; - Q_ENUM(DocumentError) - - enum MetaDataField { - Title, - Subject, - Author, - Keywords, - Producer, - Creator, - CreationDate, - ModificationDate - }; - Q_ENUM(MetaDataField) - - explicit QPdfDocument(QObject *parent = nullptr); - ~QPdfDocument(); - - DocumentError load(const QString &fileName); - - Status status() const; - - void load(QIODevice *device); - void setPassword(const QString &password); - QString password() const; - - QVariant metaData(MetaDataField field) const; - - DocumentError error() const; - - void close(); - - int pageCount() const; - - QSizeF pageSize(int page) const; - - QImage render(int page, QSize imageSize, QPdfDocumentRenderOptions options = QPdfDocumentRenderOptions()); - - Q_INVOKABLE QPdfSelection getSelection(int page, QPointF start, QPointF end); - Q_INVOKABLE QPdfSelection getSelectionAtIndex(int page, int startIndex, int maxLength); - Q_INVOKABLE QPdfSelection getAllText(int page); - -Q_SIGNALS: - void passwordChanged(); - void passwordRequired(); - void statusChanged(QPdfDocument::Status status); - void pageCountChanged(int pageCount); - -private: - friend class QPdfBookmarkModelPrivate; - friend class QPdfLinkModelPrivate; - friend class QPdfSearchModel; - friend class QPdfSearchModelPrivate; - friend class QQuickPdfSelection; - - Q_PRIVATE_SLOT(d, void _q_tryLoadingWithSizeFromContentHeader()) - Q_PRIVATE_SLOT(d, void _q_copyFromSequentialSourceDevice()) - QScopedPointer<QPdfDocumentPrivate> d; -}; - -QT_END_NAMESPACE - -#endif // QPDFDOCUMENT_H diff --git a/src/pdf/api/qpdfdocumentrenderoptions.h b/src/pdf/api/qpdfdocumentrenderoptions.h deleted file mode 100644 index cafb4716f..000000000 --- a/src/pdf/api/qpdfdocumentrenderoptions.h +++ /dev/null @@ -1,94 +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: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPDFDOCUMENTRENDEROPTIONS_H -#define QPDFDOCUMENTRENDEROPTIONS_H - -#include <QtPdf/qpdfnamespace.h> -#include <QtCore/qobject.h> -#include <QtCore/qrect.h> - -QT_BEGIN_NAMESPACE - -class QPdfDocumentRenderOptions -{ -public: - Q_DECL_CONSTEXPR QPdfDocumentRenderOptions() noexcept : m_renderFlags(0), m_rotation(0), m_reserved(0) {} - - Q_DECL_CONSTEXPR QPdf::Rotation rotation() const noexcept { return static_cast<QPdf::Rotation>(m_rotation); } - Q_DECL_RELAXED_CONSTEXPR void setRotation(QPdf::Rotation r) noexcept { m_rotation = r; } - - Q_DECL_CONSTEXPR QPdf::RenderFlags renderFlags() const noexcept { return static_cast<QPdf::RenderFlags>(m_renderFlags); } - Q_DECL_RELAXED_CONSTEXPR void setRenderFlags(QPdf::RenderFlags r) noexcept { m_renderFlags = r; } - - Q_DECL_CONSTEXPR QRect scaledClipRect() const noexcept { return m_clipRect; } - Q_DECL_RELAXED_CONSTEXPR void setScaledClipRect(const QRect &r) noexcept { m_clipRect = r; } - - Q_DECL_CONSTEXPR QSize scaledSize() const noexcept { return m_scaledSize; } - Q_DECL_RELAXED_CONSTEXPR void setScaledSize(const QSize &s) noexcept { m_scaledSize = s; } - -private: - friend Q_DECL_CONSTEXPR inline bool operator==(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) noexcept; - - QRect m_clipRect; - QSize m_scaledSize; - - quint32 m_renderFlags : 8; - quint32 m_rotation : 3; - quint32 m_reserved : 21; - quint32 m_reserved2 = 0; -}; - -Q_DECLARE_TYPEINFO(QPdfDocumentRenderOptions, Q_PRIMITIVE_TYPE); - -Q_DECL_CONSTEXPR inline bool operator==(QPdfDocumentRenderOptions lhs, 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 -} - -Q_DECL_CONSTEXPR inline bool operator!=(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) noexcept -{ - return !operator==(lhs, rhs); -} - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(QPdfDocumentRenderOptions) - -#endif // QPDFDOCUMENTRENDEROPTIONS_H diff --git a/src/pdf/api/qpdflinkmodel_p.h b/src/pdf/api/qpdflinkmodel_p.h deleted file mode 100644 index cf9c0aad4..000000000 --- a/src/pdf/api/qpdflinkmodel_p.h +++ /dev/null @@ -1,106 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPDFLINKMODEL_P_H -#define QPDFLINKMODEL_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 "qtpdfglobal.h" -#include "qpdfdocument.h" - -#include <QObject> -#include <QAbstractListModel> - -QT_BEGIN_NAMESPACE - -class QPdfLinkModelPrivate; - -class Q_PDF_EXPORT QPdfLinkModel : public QAbstractListModel -{ - Q_OBJECT - Q_PROPERTY(QPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged) - Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged) - -public: - enum class Role : int { - Rect = Qt::UserRole, - Url, - Page, - Location, - Zoom, - _Count - }; - Q_ENUM(Role) - explicit QPdfLinkModel(QObject *parent = nullptr); - ~QPdfLinkModel(); - - QPdfDocument *document() const; - - QHash<int, QByteArray> roleNames() const override; - int rowCount(const QModelIndex &parent) const override; - QVariant data(const QModelIndex &index, int role) const override; - - int page() const; - -public Q_SLOTS: - void setDocument(QPdfDocument *document); - void setPage(int page); - -Q_SIGNALS: - void documentChanged(); - void pageChanged(int page); - -private Q_SLOTS: - void onStatusChanged(QPdfDocument::Status status); - -private: - QHash<int, QByteArray> m_roleNames; - Q_DECLARE_PRIVATE(QPdfLinkModel) -}; - -QT_END_NAMESPACE - -#endif // QPDFLINKMODEL_P_H diff --git a/src/pdf/api/qpdflinkmodel_p_p.h b/src/pdf/api/qpdflinkmodel_p_p.h deleted file mode 100644 index 0454d6755..000000000 --- a/src/pdf/api/qpdflinkmodel_p_p.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPDFLINKMODEL_P_P_H -#define QPDFLINKMODEL_P_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 "qpdflinkmodel_p.h" -#include <private/qabstractitemmodel_p.h> - -#include "third_party/pdfium/public/fpdfview.h" - -#include <QUrl> - -QT_BEGIN_NAMESPACE - -class QPdfLinkModelPrivate: public QAbstractItemModelPrivate -{ - Q_DECLARE_PUBLIC(QPdfLinkModel) - -public: - QPdfLinkModelPrivate(); - - 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; - QVector<Link> links; - int page = 0; -}; - -QT_END_NAMESPACE - -#endif // QPDFLINKMODEL_P_P_H diff --git a/src/pdf/api/qpdfnamespace.h b/src/pdf/api/qpdfnamespace.h deleted file mode 100644 index e76d0abd9..000000000 --- a/src/pdf/api/qpdfnamespace.h +++ /dev/null @@ -1,73 +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: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPDFNAMESPACE_H -#define QPDFNAMESPACE_H - -#include <QtCore/qobject.h> - -QT_BEGIN_NAMESPACE - -namespace QPdf { - Q_NAMESPACE - - 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(QPdf::RenderFlags) - -QT_END_NAMESPACE -#endif diff --git a/src/pdf/api/qpdfpagenavigation.h b/src/pdf/api/qpdfpagenavigation.h deleted file mode 100644 index 0f416bf77..000000000 --- a/src/pdf/api/qpdfpagenavigation.h +++ /dev/null @@ -1,92 +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: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.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: - explicit QPdfPageNavigation(QObject *parent = nullptr); - ~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: - Q_DECLARE_PRIVATE(QPdfPageNavigation) -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/pdf/api/qpdfpagerenderer.h b/src/pdf/api/qpdfpagerenderer.h deleted file mode 100644 index c7b8de0df..000000000 --- a/src/pdf/api/qpdfpagerenderer.h +++ /dev/null @@ -1,92 +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: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPDFPAGERENDERER_H -#define QPDFPAGERENDERER_H - -#include <QtPdf/qtpdfglobal.h> - -#include <QtCore/qobject.h> -#include <QtCore/qsize.h> -#include <QtPdf/qpdfdocumentrenderoptions.h> - -QT_BEGIN_NAMESPACE - -class QPdfDocument; -class QPdfPageRendererPrivate; - -class Q_PDF_EXPORT QPdfPageRenderer : public QObject -{ - Q_OBJECT - - Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged) - Q_PROPERTY(RenderMode renderMode READ renderMode WRITE setRenderMode NOTIFY renderModeChanged) - -public: - enum class RenderMode - { - MultiThreaded, - SingleThreaded - }; - Q_ENUM(RenderMode) - - explicit QPdfPageRenderer(QObject *parent = nullptr); - ~QPdfPageRenderer() override; - - RenderMode renderMode() const; - void setRenderMode(RenderMode mode); - - QPdfDocument* document() const; - void setDocument(QPdfDocument *document); - - quint64 requestPage(int pageNumber, QSize imageSize, - QPdfDocumentRenderOptions options = QPdfDocumentRenderOptions()); - -Q_SIGNALS: - void documentChanged(QPdfDocument *document); - void renderModeChanged(RenderMode renderMode); - - void pageRendered(int pageNumber, QSize imageSize, const QImage &image, - QPdfDocumentRenderOptions options, quint64 requestId); - -private: - Q_DECLARE_PRIVATE(QPdfPageRenderer) -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/pdf/api/qpdfsearchmodel.h b/src/pdf/api/qpdfsearchmodel.h deleted file mode 100644 index eb0fb831f..000000000 --- a/src/pdf/api/qpdfsearchmodel.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPDFSEARCHMODEL_H -#define QPDFSEARCHMODEL_H - -#include <QtPdf/qtpdfglobal.h> - -#include <QtCore/qabstractitemmodel.h> -#include <QtPdf/qpdfdocument.h> -#include <QtPdf/qpdfsearchresult.h> - -QT_BEGIN_NAMESPACE - -class QPdfSearchModelPrivate; - -class Q_PDF_EXPORT QPdfSearchModel : public QAbstractListModel -{ - Q_OBJECT - Q_PROPERTY(QPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged) - Q_PROPERTY(QString searchString READ searchString WRITE setSearchString NOTIFY searchStringChanged) - -public: - enum class Role : int { - Page = Qt::UserRole, - IndexOnPage, - Location, - ContextBefore, - ContextAfter, - _Count - }; - Q_ENUM(Role) - explicit QPdfSearchModel(QObject *parent = nullptr); - ~QPdfSearchModel(); - - QVector<QPdfSearchResult> resultsOnPage(int page) const; - QPdfSearchResult resultAtIndex(int index) const; - - QPdfDocument *document() const; - QString searchString() const; - - QHash<int, QByteArray> roleNames() const override; - int rowCount(const QModelIndex &parent) const override; - QVariant data(const QModelIndex &index, int role) const override; - -public Q_SLOTS: - void setSearchString(QString searchString); - void setDocument(QPdfDocument *document); - -Q_SIGNALS: - void documentChanged(); - void searchStringChanged(); - -protected: - void updatePage(int page); - void timerEvent(QTimerEvent *event) override; - -private: - QHash<int, QByteArray> m_roleNames; - Q_DECLARE_PRIVATE(QPdfSearchModel) -}; - -QT_END_NAMESPACE - -#endif // QPDFSEARCHMODEL_H diff --git a/src/pdf/api/qpdfsearchmodel_p.h b/src/pdf/api/qpdfsearchmodel_p.h deleted file mode 100644 index 2a23706b2..000000000 --- a/src/pdf/api/qpdfsearchmodel_p.h +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPDFSEARCHMODEL_P_H -#define QPDFSEARCHMODEL_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 "qpdfsearchmodel.h" -#include "qpdfsearchresult_p.h" -#include <private/qabstractitemmodel_p.h> - -#include "third_party/pdfium/public/fpdfview.h" - -QT_BEGIN_NAMESPACE - -class QPdfSearchModelPrivate : public QAbstractItemModelPrivate -{ - Q_DECLARE_PUBLIC(QPdfSearchModel) - -public: - QPdfSearchModelPrivate(); - void clearResults(); - bool doSearch(int page); - - struct PageAndIndex { - int page; - int index; - }; - PageAndIndex pageAndIndexForResult(int resultIndex); - int rowsBeforePage(int page); - - QPdfDocument *document = nullptr; - QString searchString; - QVector<bool> pagesSearched; - QVector<QVector<QPdfSearchResult>> searchResults; - int rowCountSoFar = 0; - int updateTimerId = -1; - int nextPageToUpdate = 0; -}; - -QT_END_NAMESPACE - -#endif // QPDFSEARCHMODEL_P_H diff --git a/src/pdf/api/qpdfsearchresult.h b/src/pdf/api/qpdfsearchresult.h deleted file mode 100644 index 2dfca2dc4..000000000 --- a/src/pdf/api/qpdfsearchresult.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPDFSEARCHRESULT_H -#define QPDFSEARCHRESULT_H - -#include <QtCore/qdebug.h> -#include <QtCore/qrect.h> -#include <QtCore/qvector.h> -#include <QtPdf/qpdfdestination.h> - -QT_BEGIN_NAMESPACE - -class QPdfSearchResultPrivate; - -class Q_PDF_EXPORT QPdfSearchResult : public QPdfDestination -{ - Q_GADGET - Q_PROPERTY(QString contextBefore READ contextBefore) - Q_PROPERTY(QString contextAfter READ contextAfter) - Q_PROPERTY(QVector<QRectF> rectangles READ rectangles) - -public: - QPdfSearchResult(); - ~QPdfSearchResult() {} - - QString contextBefore() const; - QString contextAfter() const; - QVector<QRectF> rectangles() const; - -private: - QPdfSearchResult(int page, QVector<QRectF> rects, QString contextBefore, QString contextAfter); - QPdfSearchResult(QPdfSearchResultPrivate *d); - friend class QPdfDocument; - friend class QPdfSearchModelPrivate; - friend class QQuickPdfNavigationStack; -}; - -Q_PDF_EXPORT QDebug operator<<(QDebug, const QPdfSearchResult &); - -QT_END_NAMESPACE - -#endif // QPDFSEARCHRESULT_H diff --git a/src/pdf/api/qpdfsearchresult_p.h b/src/pdf/api/qpdfsearchresult_p.h deleted file mode 100644 index 615dce4e0..000000000 --- a/src/pdf/api/qpdfsearchresult_p.h +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.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 "qpdfdestination_p.h" - -QT_BEGIN_NAMESPACE - -class QPdfSearchResultPrivate : public QPdfDestinationPrivate -{ -public: - QPdfSearchResultPrivate() = default; - QPdfSearchResultPrivate(int page, QVector<QRectF> rects, QString contextBefore, QString contextAfter) : - QPdfDestinationPrivate(page, rects.first().topLeft(), 0), - contextBefore(contextBefore), - contextAfter(contextAfter), - rects(rects) {} - - QString contextBefore; - QString contextAfter; - QVector<QRectF> rects; -}; - -QT_END_NAMESPACE - -#endif // QPDFSEARCHRESULT_P_H diff --git a/src/pdf/api/qpdfselection.h b/src/pdf/api/qpdfselection.h deleted file mode 100644 index 9d91d46c7..000000000 --- a/src/pdf/api/qpdfselection.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPDFSELECTION_H -#define QPDFSELECTION_H - -#include <QtPdf/qtpdfglobal.h> - -#include <QtCore/qobject.h> -#include <QtCore/qshareddata.h> -#include <QtGui/qclipboard.h> -#include <QtGui/qpolygon.h> - -QT_BEGIN_NAMESPACE - -class QPdfSelectionPrivate; - -class Q_PDF_EXPORT QPdfSelection -{ - Q_GADGET - Q_PROPERTY(bool valid READ isValid) - Q_PROPERTY(QVector<QPolygonF> bounds READ bounds) - Q_PROPERTY(QRectF boundingRectangle READ boundingRectangle) - Q_PROPERTY(QString text READ text) - Q_PROPERTY(int startIndex READ startIndex) - Q_PROPERTY(int endIndex READ endIndex) - -public: - ~QPdfSelection(); - QPdfSelection(const QPdfSelection &other); - QPdfSelection &operator=(const QPdfSelection &other); - QPdfSelection(QPdfSelection &&other) noexcept; - QPdfSelection &operator=(QPdfSelection &&other) noexcept { swap(other); return *this; } - void swap(QPdfSelection &other) noexcept { d.swap(other.d); } - bool isValid() const; - QVector<QPolygonF> bounds() const; - QString text() const; - QRectF boundingRectangle() const; - int startIndex() const; - int endIndex() const; -#if QT_CONFIG(clipboard) - void copyToClipboard(QClipboard::Mode mode = QClipboard::Clipboard) const; -#endif - -private: - QPdfSelection(); - QPdfSelection(const QString &text, QVector<QPolygonF> bounds, QRectF boundingRect, int startIndex, int endIndex); - QPdfSelection(QPdfSelectionPrivate *d); - friend class QPdfDocument; - friend class QQuickPdfSelection; - -private: - QExplicitlySharedDataPointer<QPdfSelectionPrivate> d; -}; - -QT_END_NAMESPACE - -#endif // QPDFSELECTION_H diff --git a/src/pdf/api/qpdfselection_p.h b/src/pdf/api/qpdfselection_p.h deleted file mode 100644 index 0577e5a31..000000000 --- a/src/pdf/api/qpdfselection_p.h +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPDFSELECTION_P_H -#define QPDFSELECTION_P_H - -#include <QPolygonF> -#include <QVector> - -QT_BEGIN_NAMESPACE - -class QPdfSelectionPrivate : public QSharedData -{ -public: - QPdfSelectionPrivate() = default; - QPdfSelectionPrivate(const QString &text, QVector<QPolygonF> bounds, QRectF boundingRect, int startIndex, int endIndex) - : text(text), - bounds(bounds), - boundingRect(boundingRect), - startIndex(startIndex), - endIndex(endIndex) { } - - QString text; - QVector<QPolygonF> bounds; - QRectF boundingRect; - int startIndex; - int endIndex; -}; - -QT_END_NAMESPACE - -#endif // QPDFSELECTION_P_H diff --git a/src/pdf/api/qtpdfglobal.h b/src/pdf/api/qtpdfglobal.h deleted file mode 100644 index 8b4b0c206..000000000 --- a/src/pdf/api/qtpdfglobal.h +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTPDFGLOBAL_H -#define QTPDFGLOBAL_H - -#include <QtCore/qglobal.h> - -QT_BEGIN_NAMESPACE - -#ifndef Q_PDF_EXPORT -# ifndef QT_STATIC -# if defined(QT_BUILD_PDF_LIB) -# define Q_PDF_EXPORT Q_DECL_EXPORT -# else -# define Q_PDF_EXPORT Q_DECL_IMPORT -# endif -# else -# define Q_PDF_EXPORT -# endif -#endif - -#define Q_PDF_PRIVATE_EXPORT Q_PDF_EXPORT - -QT_END_NAMESPACE - -#endif // QTPDFGLOBAL_H - diff --git a/src/pdf/config/common.pri b/src/pdf/config/common.pri deleted file mode 100644 index dd5bfa293..000000000 --- a/src/pdf/config/common.pri +++ /dev/null @@ -1,38 +0,0 @@ -include($$QTWEBENGINE_OUT_ROOT/src/pdf/qtpdf-config.pri) -QT_FOR_CONFIG += pdf-private - -qtConfig(pdf-v8) { - gn_args += pdf_enable_v8=true -} else { - gn_args += pdf_enable_v8=false -} - -qtConfig(pdf-xfa) { - gn_args += pdf_enable_xfa=true -} else { - gn_args += pdf_enable_xfa=false -} - -qtConfig(pdf-xfa-bmp) { - gn_args += pdf_enable_xfa_bmp=true -} else { - gn_args += pdf_enable_xfa_bmp=false -} - -qtConfig(pdf-xfa-gif) { - gn_args += pdf_enable_xfa_gif=true -} else { - gn_args += pdf_enable_xfa_gif=false -} - -qtConfig(pdf-xfa-png) { - gn_args += pdf_enable_xfa_png=true -} else { - gn_args += pdf_enable_xfa_png=false -} - -qtConfig(pdf-xfa-tiff) { - gn_args += pdf_enable_xfa_tiff=true -} else { - gn_args += pdf_enable_xfa_tiff=false -} diff --git a/src/pdf/config/ios.pri b/src/pdf/config/ios.pri deleted file mode 100644 index 1dcbeffde..000000000 --- a/src/pdf/config/ios.pri +++ /dev/null @@ -1,65 +0,0 @@ -load(functions) - -include($$QTWEBENGINE_OUT_ROOT/src/buildtools/qtbuildtools-config.pri) -include($$QTWEBENGINE_OUT_ROOT/src/pdf/qtpdf-config.pri) -QT_FOR_CONFIG += buildtools-private pdf-private - -clang_dir = $$which($${QMAKE_CXX}) -clang_dir = $$clean_path("$$dirname(clang_dir)/../") - -gn_args += \ -use_qt=true \ -closure_compile=false \ -is_component_build=false \ -is_shared=true \ -is_debug=true \ -enable_message_center=false \ -enable_nacl=false \ -enable_remoting=false \ -enable_reporting=false \ -enable_resource_whitelist_generation=false \ -enable_swiftshader=false \ -enable_web_speech=false \ -has_native_accessibility=false \ -enable_debugallocation=false \ -use_allocator_shim=false \ -use_allocator=\"none\" \ -use_custom_libcxx=false \ -v8_use_external_startup_data=false \ -toolkit_views=false \ -treat_warnings_as_errors=false \ -safe_browsing_mode=0 \ -optimize_webui=false \ -forbid_non_component_debug_builds=false \ -clang_use_chrome_plugins=false \ -use_xcode_clang=true \ -clang_base_path=\"$${clang_dir}\" \ -ios_enable_code_signing=false \ -target_os=\"ios\" \ -ios_deployment_target=\"$${QMAKE_IOS_DEPLOYMENT_TARGET}\" \ -enable_ios_bitcode=true \ -use_jumbo_build=false - -device:simulator { - # we do fat libray - gn_args+= \ - target_cpu=\"$${QMAKE_APPLE_DEVICE_ARCHS}\" \ - use_qt_fat_lib=true \ - arm_use_neon=false\ - # note this adds one arch of simulator at the moment, see also additional_target_cpus - target_sysroot=\"$$xcodeSDKInfo(Path, $$device.sdk)\" \ - additional_target_sysroot=[\"$$xcodeSDKInfo(Path, $$simulator.sdk)\"] -} else { - simulator { - equals(QMAKE_APPLE_SIMULATOR_ARCHS,"x86_64") { - gn_args+=target_cpu=\"x64\" - } else { - gn_args+=target_cpu=\"$${QMAKE_APPLE_SIMULATOR_ARCHS}\" - } - gn_args+=target_sysroot=\"$$xcodeSDKInfo(Path, $$simulator.sdk)\" - } - device { - gn_args+=target_cpu=\"$${QMAKE_APPLE_DEVICE_ARCHS}\" - gn_args+=target_sysroot=\"$$xcodeSDKInfo(Path, $$device.sdk)\" - } -} diff --git a/src/pdf/configure.cmake b/src/pdf/configure.cmake new file mode 100644 index 000000000..ac4e4e25f --- /dev/null +++ b/src/pdf/configure.cmake @@ -0,0 +1,54 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_feature("pdf-v8" PRIVATE + LABEL "Support V8" + PURPOSE "Enables javascript support." + AUTODETECT FALSE + CONDITION NOT IOS +) +qt_feature("pdf-xfa" PRIVATE + LABEL "Support XFA" + PURPOSE "Enables XFA support." + CONDITION QT_FEATURE_pdf_v8 +) +qt_feature("pdf-xfa-bmp" PRIVATE + LABEL "Support XFA-BMP" + PURPOSE "Enables XFA-BMP support." + CONDITION QT_FEATURE_pdf_xfa +) +qt_feature("pdf-xfa-gif" PRIVATE + LABEL "Support XFA-GIF" + PURPOSE "Enables XFA-GIF support." + CONDITION QT_FEATURE_pdf_xfa +) +qt_feature("pdf-xfa-png" PRIVATE + LABEL "Support XFA-PNG" + PURPOSE "Enables XFA-PNG support." + CONDITION QT_FEATURE_pdf_xfa +) +qt_feature("pdf-xfa-tiff" PRIVATE + LABEL "Support XFA-TIFF" + PURPOSE "Enables XFA-TIFF support." + CONDITION QT_FEATURE_pdf_xfa +) +qt_feature("pdf-bitcode" PRIVATE + LABEL "Bitcode support" + PURPOSE "Enables bitcode" + CONDITION IOS +) +qt_feature("pdf-static-runtime" PRIVATE + LABEL "Use static runtime" + PURPOSE "Enables static runtime" + CONDITION WIN32 AND QT_FEATURE_static AND QT_FEATURE_static_runtime +) +qt_configure_add_summary_section(NAME "Qt PDF") +qt_configure_add_summary_entry(ARGS "pdf-v8") +qt_configure_add_summary_entry(ARGS "pdf-xfa") +qt_configure_add_summary_entry(ARGS "pdf-xfa-bmp") +qt_configure_add_summary_entry(ARGS "pdf-xfa-gif") +qt_configure_add_summary_entry(ARGS "pdf-xfa-png") +qt_configure_add_summary_entry(ARGS "pdf-xfa-tiff") +qt_configure_add_summary_entry(ARGS "pdf-bitcode") +qt_configure_add_summary_entry(ARGS "pdf-static-runtime") +qt_configure_end_summary_section() diff --git a/src/pdf/configure.json b/src/pdf/configure.json deleted file mode 100644 index ddc0e99dc..000000000 --- a/src/pdf/configure.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "module": "pdf", - "depends" : [ "buildtools-private" ], - "testDir": "../../config.tests", - "condition": "features.build-qtpdf && features.webengine-qtpdf-support", - "libraries": { - }, - "tests": { - }, - "features": { - "pdf-v8": { - "label": "Support V8", - "purpose": "Enables javascript support.", - "autoDetect": "false", - "condition": "!config.ios", - "output": ["privateFeature" ] - }, - "pdf-xfa": { - "label": "Support XFA", - "purpose": "Enables XFA support.", - "condition": "features.pdf-v8", - "output": ["privateFeature" ] - }, - "pdf-xfa-bmp": { - "label": "Support XFA-BMP", - "purpose": "Enables XFA-BMP support.", - "condition": "features.pdf-xfa", - "output": ["privateFeature" ] - }, - "pdf-xfa-gif": { - "label": "Support XFA-GIF", - "purpose": "Enables XFA-GIF support.", - "condition": "features.pdf-xfa", - "output": ["privateFeature" ] - }, - "pdf-xfa-png": { - "label": "Support XFA-PNG", - "purpose": "Enables XFA-PNG support.", - "condition": "features.pdf-xfa", - "output": ["privateFeature" ] - }, - "pdf-xfa-tiff": { - "label": "Support XFA-TIFF", - "purpose": "Enables XFA-TIFF support.", - "condition": "features.pdf-xfa", - "output": ["privateFeature" ] - } - }, - "report": [ - ], - "summary": [ - { - "section": "Qt PDF", - "entries": [ - "pdf-v8", - "pdf-xfa", - "pdf-xfa-bmp", - "pdf-xfa-gif", - "pdf-xfa-png", - "pdf-xfa-tiff" - ] - } - ] -} diff --git a/src/pdf/configure/BUILD.root.gn.in b/src/pdf/configure/BUILD.root.gn.in new file mode 100644 index 000000000..e9f54ed6d --- /dev/null +++ b/src/pdf/configure/BUILD.root.gn.in @@ -0,0 +1,73 @@ +import("//build/config/features.gni") + +config("qt_libpng_config") { + include_dirs = [ @GN_PNG_INCLUDES@ ] + defines = [ "USE_SYSTEM_LIBPNG" ] +} +config ("qt_libjpeg_config") { + include_dirs = [ @GN_JPEG_INCLUDES@ ] +} +config("qt_harfbuzz_config") { + visibility = [ + "//third_party:freetype_harfbuzz", + "//third_party/freetype:freetype_source", + ] + include_dirs = [ @GN_HARFBUZZ_INCLUDES@ ] +} +config("qt_freetype_config") { + visibility = [ + "//build/config/freetype:freetype", + "//third_party:freetype_harfbuzz", + "//third_party/harfbuzz-ng:harfbuzz_source", + ] + include_dirs = [ @GN_FREETYPE_INCLUDES@ ] +} + +config("QtPdf_config") { + cflags = [ + @GN_CFLAGS_C@, + ] + cflags_cc = [ + @GN_CFLAGS_CC@, + ] + defines = [ + @GN_DEFINES@, + ] + include_dirs = [ + @GN_INCLUDE_DIRS@, + rebase_path("${target_gen_dir}/.moc/") + ] +} + +config("cpp20_config") { + # Chromium headers now use concepts and requires c++20 + if (is_win) { + cflags_cc = [ "/std:c++20" ] + } else { + cflags_cc = [ "-std=c++20" ] + } +} + +static_library("QtPdf") { + complete_static_lib = true + rsp_types = [ "objects", "archives", "libs", "ldir" ] + configs += [ + ":cpp20_config", + ":QtPdf_config" + ] + deps = [ + "//third_party/pdfium" + ] + if (is_msvc) { + libs = [ + "dloadhelper.lib", + "winmm.lib", + "usp10.lib", + ] + } + if (is_mingw) { + libs = [ + "winmm", + ] + } +} diff --git a/src/pdf/doc/about_credits.tmpl b/src/pdf/doc/about_credits.tmpl new file mode 100644 index 000000000..57fae9e78 --- /dev/null +++ b/src/pdf/doc/about_credits.tmpl @@ -0,0 +1 @@ +{{entries}} diff --git a/src/pdf/doc/about_credits_entry.tmpl b/src/pdf/doc/about_credits_entry.tmpl new file mode 100644 index 000000000..294198709 --- /dev/null +++ b/src/pdf/doc/about_credits_entry.tmpl @@ -0,0 +1,13 @@ +/*! +\page qtpdf-3rdparty-{{name-sanitized}}.html +\attribution +\ingroup qtpdf-licensing +\brief {{license-type}} +\title {{name}} + +\l{{{url}}}{Project Homepage} + +\badcode +{{license}} +\endcode +*/ diff --git a/src/pdf/doc/images/multipageviewer.png b/src/pdf/doc/images/multipageviewer.png Binary files differnew file mode 100644 index 000000000..2f0bb62a2 --- /dev/null +++ b/src/pdf/doc/images/multipageviewer.png diff --git a/src/pdf/doc/images/pdfviewer.png b/src/pdf/doc/images/pdfviewer.png Binary files differnew file mode 100644 index 000000000..ac8a31ac0 --- /dev/null +++ b/src/pdf/doc/images/pdfviewer.png 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/singlepageviewer.webp b/src/pdf/doc/images/singlepageviewer.webp Binary files differnew file mode 100644 index 000000000..e429cb818 --- /dev/null +++ b/src/pdf/doc/images/singlepageviewer.webp 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 7a77105c9..d0340fe83 100644 --- a/src/pdf/doc/qtpdf.qdocconf +++ b/src/pdf/doc/qtpdf.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qtwebengine.qdocconf) project = QtPdf description = Qt Pdf Reference Documentation @@ -12,10 +13,6 @@ qhp.QtPdf.virtualFolder = qtpdf qhp.QtPdf.indexTitle = Qt PDF qhp.QtPdf.indexRoot = -qhp.QtPdf.filterAttributes = qtpdf $QT_VERSION qtrefdoc -qhp.QtPdf.customFilters.Qt.name = QtPdf $QT_VERSION -qhp.QtPdf.customFilters.Qt.filterAttributes = qtpdf $QT_VERSION - qhp.QtPdf.subprojects = classes qmltypes examples qhp.QtPdf.subprojects.classes.title = C++ Classes @@ -33,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 \ @@ -40,19 +39,29 @@ depends += qtcore \ qmake \ qtdesigner \ qtquick \ - qtcmake + qtquickcontrols \ + qtcmake \ + qtsvg -headerdirs += ../api \ - ../quick +headerdirs += ../ \ + ../../pdfwidgets -sourcedirs += .. \ - ../quick +sourcedirs += ../ \ + ../../pdfquick \ + ../../pdfwidgets exampledirs += ../../../examples/pdfwidgets \ + ../../../examples/pdf \ snippets/ +# add a generic thumbnail for an example that has no \image in its doc +manifestmeta.thumbnail.names = "QtPdf/PDF Viewer Example" + imagedirs += images navigation.landingpage = "Qt PDF" navigation.cppclassespage = "Qt PDF C++ Classes" -navigation.qmltypespage = "Qt WebEngine QML Types" +navigation.qmltypespage = "Qt Quick PDF QML Types" + +# Enforce zero documentation warnings +warninglimit = 0 diff --git a/src/pdf/doc/snippets/multipageview.qml b/src/pdf/doc/snippets/multipageview.qml new file mode 100644 index 000000000..113444165 --- /dev/null +++ b/src/pdf/doc/snippets/multipageview.qml @@ -0,0 +1,11 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +//! [0] +import QtQuick +import QtQuick.Pdf + +PdfMultiPageView { + document: PdfDocument { source: "my.pdf" } +} +//! [0] diff --git a/src/pdf/doc/snippets/pdfpageview.qml b/src/pdf/doc/snippets/pdfpageview.qml new file mode 100644 index 000000000..5e233961a --- /dev/null +++ b/src/pdf/doc/snippets/pdfpageview.qml @@ -0,0 +1,12 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +//! [0] +import QtQuick +import QtQuick.Pdf + +PdfPageView { + document: PdfDocument { source: "my.pdf" } +} +//! [0] + diff --git a/src/pdf/doc/snippets/qtpdf-build.cmake b/src/pdf/doc/snippets/qtpdf-build.cmake index d46b9c3ee..b4372d411 100644 --- a/src/pdf/doc/snippets/qtpdf-build.cmake +++ b/src/pdf/doc/snippets/qtpdf-build.cmake @@ -1,2 +1,2 @@ -find_package(Qt5 COMPONENTS Pdf REQUIRED) -target_link_libraries(mytarget Qt5::Pdf) +find_package(Qt6 REQUIRED COMPONENTS Pdf) +target_link_libraries(mytarget Qt6::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..02dc23dc2 100644 --- a/src/pdf/doc/src/qtpdf-examples.qdoc +++ b/src/pdf/doc/src/qtpdf-examples.qdoc @@ -1,33 +1,8 @@ -/**************************************************************************** -** -** 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 - \ingroup all-examples \title Qt PDF Examples \brief Using the classes and types in the Qt PDF module. diff --git a/src/pdf/doc/src/qtpdf-index.qdoc b/src/pdf/doc/src/qtpdf-index.qdoc index b32787eb5..b72619fbf 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 Widget 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,21 +48,10 @@ \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 - \section1 Articles and Guides - - \list - \li \l{Qt PDF Overview} - \endlist - \section1 Examples \list @@ -73,4 +64,17 @@ \li \l{Qt PDF C++ Classes} \li \l{Qt Quick PDF QML Types} \endlist + + \section1 Articles and Guides + \list + \li {Qt PDF Platform Notes} {Platform Notes} + \endlist + + \section1 Licenses and Attributions + + Qt PDF is available under commercial licenses from \l{The Qt Company}. + In addition, it is available under the + \l{GNU Lesser General Public License, version 3}, or + the \l{GNU General Public License, version 2}. + See \l{Qt PDF Licensing} for further details about this module. */ diff --git a/src/pdf/doc/src/qtpdf-licensing.qdoc b/src/pdf/doc/src/qtpdf-licensing.qdoc new file mode 100644 index 000000000..190ee8331 --- /dev/null +++ b/src/pdf/doc/src/qtpdf-licensing.qdoc @@ -0,0 +1,18 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \group qtpdf-licensing + \title Qt PDF Licensing + + Qt PDF is available under commercial licenses from \l{The Qt Company}. + In addition, it is available under the + \l{GNU Lesser General Public License, version 3}, or + the \l{GNU General Public License, version 2}. + See \l{Qt Licensing} for further details. + + The module includes a snapshot of PDFium. As such, users need to respect + the licenses of PDFium and third-party code included in it. + + Third party licenses included in the sources are: +*/ 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/doc/src/qtpdf-platformnotes.qdoc b/src/pdf/doc/src/qtpdf-platformnotes.qdoc new file mode 100644 index 000000000..f50be120d --- /dev/null +++ b/src/pdf/doc/src/qtpdf-platformnotes.qdoc @@ -0,0 +1,11 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \page qtpdf-platformnotes.html + \title Qt PDF Platform Notes + + Building Qt PDF for Android is currently + \l{https://bugreports.qt.io/browse/QTBUG-83459} {not supported} on Windows host platforms. +*/ + diff --git a/src/pdf/gn_run.pro b/src/pdf/gn_run.pro deleted file mode 100644 index 70ee582a9..000000000 --- a/src/pdf/gn_run.pro +++ /dev/null @@ -1,69 +0,0 @@ -include($$QTWEBENGINE_OUT_ROOT/src/buildtools/qtbuildtools-config.pri) -QT_FOR_CONFIG += buildtools-private - -TEMPLATE = aux - -qtConfig(debug_and_release): CONFIG += debug_and_release -qtConfig(build_all): CONFIG += build_all - -qtConfig(webengine-system-ninja) { - QT_TOOL.ninja.binary = ninja -} else { - QT_TOOL.ninja.binary = $$shell_quote($$shell_path($$ninjaPath())) -} - -win32 { - # Add the gnuwin32/bin subdir of qt5.git to PATH. Needed for calling bison and friends. - gnuwin32path.name = PATH - gnuwin32path.value = $$shell_path($$clean_path($$QTWEBENGINE_ROOT/../gnuwin32/bin)) - gnuwin32path.CONFIG += prepend - exists($$gnuwin32path.value): QT_TOOL_ENV = gnuwin32path -} - -qtPrepareTool(NINJA, ninja) -QT_TOOL_ENV = - -build_pass|!debug_and_release { - gn_binary = gn - - runninja.target = run_ninja - - # fixme: refine args - gn_args = $$gnPdfArgs() - - # fixme: qtwebengine_target - gn_args += "qtwebengine_target=\"$$system_path($$OUT_PWD/$$getConfigDir()):QtPdf\"" - - # fixme: - !qtConfig(webengine-system-gn) { - gn_binary = $$system_quote($$system_path($$gnPath())) - } - - gn_args = $$system_quote($$gn_args) - gn_src_root = $$system_quote($$system_path($$QTWEBENGINE_ROOT/$$getChromiumSrcDir())) - gn_build_root = $$system_quote($$system_path($$OUT_PWD/$$getConfigDir())) - gn_python = "--script-executable=$$pythonPathForSystem()" - gn_run = $$gn_binary gen $$gn_build_root $$gn_python --args=$$gn_args --root=$$gn_src_root - - message("Running: $$gn_run ") - !system($$gn_run) { - error("GN run error!") - } - - ninjaflags = $$(NINJAFLAGS) - isEmpty(ninjaflags):!silent: ninjaflags = "-v" - - runninja.commands = $$NINJA $$ninjaflags -C $$gn_build_root QtPdf - QMAKE_EXTRA_TARGETS += runninja - - build_pass:build_all: default_target.target = all - else: default_target.target = first - default_target.depends = runninja - QMAKE_EXTRA_TARGETS += default_target -} - -!build_pass:debug_and_release { - # Special GNU make target for the meta Makefile that ensures that our debug and release Makefiles won't both run ninja in parallel. - notParallel.target = .NOTPARALLEL - QMAKE_EXTRA_TARGETS += notParallel -} diff --git a/src/pdf/jsbridge.cpp b/src/pdf/jsbridge.cpp deleted file mode 100644 index 33d3b2465..000000000 --- a/src/pdf/jsbridge.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "fpdfsdk/javascript/JS_Runtime_Stub.cpp" - diff --git a/src/pdf/pdf.pro b/src/pdf/pdf.pro deleted file mode 100644 index 9f98c32b0..000000000 --- a/src/pdf/pdf.pro +++ /dev/null @@ -1,31 +0,0 @@ -include($$QTWEBENGINE_OUT_ROOT/src/buildtools/qtbuildtools-config.pri) -QT_FOR_CONFIG += buildtools-private -TEMPLATE = subdirs -pdfcore.file = pdfcore.pro -pdfcore_generator.file = pdfcore_generator.pro -gn_run.file = gn_run.pro -pdfcore_prl_generator.file = pdfcore_prl_generator.pro -gn_run.depends = pdfcore_generator -pdfcore_prl_generator.depends = gn_run -pdfcore.depends = pdfcore_prl_generator -quick.depends = pdfcore - -!qtConfig(webengine-qtpdf-support):qtConfig(build-qtpdf)::!build_pass { - !qtwebengine_makeCheckPdfError() { - errorbuild.commands = @echo $$shell_quote("QtPdf will not be built. $${skipBuildReason}") - } else { - errorbuild.commands = @echo $$shell_quote("QtPdf module will not be built for unknown reason, please open a bug report at https://bugreports.qt.io") - } - errorbuild.CONFIG = phony - QMAKE_EXTRA_TARGETS += errorbuild - first.depends += errorbuild - QMAKE_EXTRA_TARGETS += first -} else { - SUBDIRS += \ - pdfcore_generator \ - gn_run \ - pdfcore_prl_generator \ - pdfcore \ - quick -} - diff --git a/src/pdf/pdfcore.pro b/src/pdf/pdfcore.pro deleted file mode 100644 index 2dfe39dc0..000000000 --- a/src/pdf/pdfcore.pro +++ /dev/null @@ -1,80 +0,0 @@ -TARGET = QtPdf -MODULE = pdf - -QT += gui core core-private -QT_PRIVATE += network - -TEMPLATE = lib - -INCLUDEPATH += $$QTWEBENGINE_ROOT/src/pdf -CHROMIUM_SRC_DIR = $$QTWEBENGINE_ROOT/$$getChromiumSrcDir() -CHROMIUM_GEN_DIR = $$OUT_PWD/../$$getConfigDir()/gen -INCLUDEPATH += $$QTWEBENGINE_ROOT/src/pdf \ - $$CHROMIUM_GEN_DIR \ - $$CHROMIUM_SRC_DIR \ - api - -DEFINES += QT_BUILD_PDF_LIB -win32: DEFINES += NOMINMAX - -QMAKE_DOCS = $$PWD/doc/qtpdf.qdocconf - -gcc { - QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter -} - -msvc { - QMAKE_CXXFLAGS_WARN_ON += -wd"4100" -} - -include($${QTWEBENGINE_ROOT}/src/buildtools/config/linking.pri) - -# install static dependencies and handle prl files for static builds - -static:!isEmpty(NINJA_ARCHIVES) { - static_dep_pri = $$OUT_PWD/$$getConfigDir()/$${TARGET}_static_dep.pri - !include($${static_dep_pri}) { - error("Could not find the prl information.") - } - ninja_archives = $$eval($$list($$NINJA_ARCHIVES)) - ninja_archs_install.files = $${ninja_archives} - ninja_archs_install.path = $$[QT_INSTALL_LIBS]/static_chrome - ninja_archs_install.CONFIG = no_check_exist - INSTALLS += ninja_archs_install -} - -SOURCES += \ - qpdfbookmarkmodel.cpp \ - qpdfdestination.cpp \ - qpdfdocument.cpp \ - qpdflinkmodel.cpp \ - qpdfpagenavigation.cpp \ - qpdfpagerenderer.cpp \ - qpdfsearchmodel.cpp \ - qpdfsearchresult.cpp \ - qpdfselection.cpp \ - -# all "public" headers must be in "api" for sync script and to hide auto generated headers -# by Chromium in case of in-source build - -HEADERS += \ - api/qpdfbookmarkmodel.h \ - api/qpdfdestination.h \ - api/qpdfdestination_p.h \ - api/qpdfdocument.h \ - api/qpdfdocument_p.h \ - api/qpdfdocumentrenderoptions.h \ - api/qtpdfglobal.h \ - api/qpdflinkmodel_p.h \ - api/qpdflinkmodel_p_p.h \ - api/qpdfnamespace.h \ - api/qpdfpagenavigation.h \ - api/qpdfpagerenderer.h \ - api/qpdfsearchmodel.h \ - api/qpdfsearchmodel_p.h \ - api/qpdfsearchresult.h \ - api/qpdfsearchresult_p.h \ - api/qpdfselection.h \ - api/qpdfselection_p.h \ - -load(qt_module) diff --git a/src/pdf/pdfcore_generator.pro b/src/pdf/pdfcore_generator.pro deleted file mode 100644 index e5c7258b7..000000000 --- a/src/pdf/pdfcore_generator.pro +++ /dev/null @@ -1,15 +0,0 @@ -qtConfig(debug_and_release): CONFIG += debug_and_release - -TARGET = QtPdf -TEMPLATE = lib -CONFIG = gn_generator $$CONFIG -CONFIG -=static # note we still do static when linking -GN_SRC_DIR = $$PWD -GN_FILE = $$OUT_PWD/$$getConfigDir()/BUILD.gn -GN_FIND_MOCABLES_SCRIPT = $$shell_path($$QTWEBENGINE_ROOT/tools/scripts/gn_find_mocables.py) -GN_RUN_BINARY_SCRIPT = $$shell_path($$QTWEBENGINE_ROOT/tools/scripts/gn_run_binary.py) -GN_IMPORTS = $$PWD/qtpdf.gni -GN_CREATE_PRI = true -QMAKE_INTERNAL_INCLUDED_FILES = $$GN_IMPORTS $$GN_INCLUDES $$GN_FILE - - diff --git a/src/pdf/pdfcore_prl_generator.pro b/src/pdf/pdfcore_prl_generator.pro deleted file mode 100644 index 39fdaed40..000000000 --- a/src/pdf/pdfcore_prl_generator.pro +++ /dev/null @@ -1,27 +0,0 @@ - -qtConfig(debug_and_release): CONFIG += debug_and_release - -TARGET = QtPdf -TEMPLATE = aux - -build_pass|!debug_and_relase { - linking_pri = $$OUT_PWD/$$getConfigDir()/$${TARGET}.pri - !include($$linking_pri) { - error("Could not find the linking information that gn should have generated.") - } - - !isEmpty(NINJA_ARCHIVES) { - prl_file = $$OUT_PWD/$$getConfigDir()/$${TARGET}_static_dep.pri - ninja_archives = $$eval($$list($$NINJA_ARCHIVES)) - qqt_libdir = \$\$\$\$[QT_INSTALL_LIBS] - for(ninja_arch, ninja_archives) { - ninja_arch_name = $$basename(ninja_arch) - ninja_arch_dirname = $$dirname(ninja_arch) - prl_content += "ninja_arch_prl_replace_$${ninja_arch_name}.match = $${ninja_arch_dirname}" - prl_content += "ninja_arch_prl_replace_$${ninja_arch_name}.replace = $${qqt_libdir}/static_chrome" - prl_content += "ninja_arch_prl_replace_$${ninja_arch_name}.CONFIG = path" - prl_content += "QMAKE_PRL_INSTALL_REPLACE += ninja_arch_prl_replace_$${ninja_arch_name}" - } - write_file($${prl_file}, prl_content) - } -} diff --git a/src/pdf/plugins/imageformats/pdf/CMakeLists.txt b/src/pdf/plugins/imageformats/pdf/CMakeLists.txt new file mode 100644 index 000000000..73a0b3144 --- /dev/null +++ b/src/pdf/plugins/imageformats/pdf/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_plugin(QPdfPlugin + OUTPUT_NAME qpdf + PLUGIN_TYPE imageformats + SOURCES + main.cpp + qpdfiohandler.cpp qpdfiohandler_p.h + LIBRARIES + Qt::PdfPrivate +) + diff --git a/src/pdf/plugins/imageformats/pdf/main.cpp b/src/pdf/plugins/imageformats/pdf/main.cpp new file mode 100644 index 000000000..cb69c4ca1 --- /dev/null +++ b/src/pdf/plugins/imageformats/pdf/main.cpp @@ -0,0 +1,41 @@ +// 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" + +QT_BEGIN_NAMESPACE + +class QPdfPlugin : public QImageIOPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QImageIOHandlerFactoryInterface_iid FILE "pdf.json") + +public: + Capabilities capabilities(QIODevice *device, const QByteArray &format) const override; + QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const override; +}; + +QImageIOPlugin::Capabilities QPdfPlugin::capabilities(QIODevice *device, const QByteArray &format) const +{ + if (format == "pdf") + return Capabilities(CanRead); + if (!format.isEmpty()) + return {}; + + Capabilities cap; + if (device->isReadable() && QPdfIOHandler::canRead(device)) + cap |= CanRead; + return cap; +} + +QImageIOHandler *QPdfPlugin::create(QIODevice *device, const QByteArray &format) const +{ + QPdfIOHandler *hand = new QPdfIOHandler(); + hand->setDevice(device); + hand->setFormat(format); + return hand; +} + +QT_END_NAMESPACE + +#include "main.moc" diff --git a/src/pdf/plugins/imageformats/pdf/pdf.json b/src/pdf/plugins/imageformats/pdf/pdf.json new file mode 100644 index 000000000..1f5268ca1 --- /dev/null +++ b/src/pdf/plugins/imageformats/pdf/pdf.json @@ -0,0 +1,4 @@ +{ + "Keys": [ "pdf" ], + "MimeTypes": [ "application/pdf" ] +} diff --git a/src/pdf/plugins/imageformats/pdf/qpdfiohandler.cpp b/src/pdf/plugins/imageformats/pdf/qpdfiohandler.cpp new file mode 100644 index 000000000..bb3e7c929 --- /dev/null +++ b/src/pdf/plugins/imageformats/pdf/qpdfiohandler.cpp @@ -0,0 +1,225 @@ +// 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 + +Q_LOGGING_CATEGORY(qLcPdf, "qt.imageformat.pdf") + +QPdfIOHandler::QPdfIOHandler() +{ +} + +QPdfIOHandler::~QPdfIOHandler() +{ + if (m_ownsDocument) + delete m_doc; +} + +bool QPdfIOHandler::canRead() const +{ + if (!device()) + return false; + if (m_loaded) + return true; + if (QPdfIOHandler::canRead(device())) { + setFormat("pdf"); + return true; + } + return false; +} + +bool QPdfIOHandler::canRead(QIODevice *device) +{ + char buf[6]; + device->peek(buf, 6); + return (!qstrncmp(buf, "%PDF-", 5) || Q_UNLIKELY(!qstrncmp(buf, "\012%PDF-", 6))); +} + +int QPdfIOHandler::currentImageNumber() const +{ + return m_page; +} + +QRect QPdfIOHandler::currentImageRect() const +{ + 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) << ret; + return ret; +} + +bool QPdfIOHandler::read(QImage *image) +{ + if (load(device())) { + if (m_doc.isNull() || 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->pagePointSize(m_page).toSize(); + QSize finalSize = pageSize; + QRectF bounds; + if (xform && !finalSize.isEmpty()) { + bounds = QRectF(QPointF(0,0), QSizeF(finalSize)); + QPoint tr1, tr2; + QSizeF sc(1, 1); + if (m_clipRect.isValid()) { + tr1 = -m_clipRect.topLeft(); + finalSize = m_clipRect.size(); + } + if (m_scaledSize.isValid()) { + sc = QSizeF(qreal(m_scaledSize.width()) / finalSize.width(), + qreal(m_scaledSize.height()) / finalSize.height()); + finalSize = m_scaledSize; + pageSize = m_scaledSize; + } + if (m_scaledClipRect.isValid()) { + tr2 = -m_scaledClipRect.topLeft(); + finalSize = m_scaledClipRect.size(); + } + QTransform t; + t.translate(tr2.x(), tr2.y()); + t.scale(sc.width(), sc.height()); + t.translate(tr1.x(), tr1.y()); + bounds = t.mapRect(bounds); + } + 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()) { + // avoid QTBUG-68229 + qWarning("QPdfIOHandler: QImage allocation failed (size %i x %i)", finalSize.width(), finalSize.height()); + return false; + } + } + if (!finalSize.isEmpty()) { + QPdfDocumentRenderOptions options; + if (m_scaledClipRect.isValid()) + options.setScaledClipRect(m_scaledClipRect); + options.setScaledSize(pageSize); + image->fill(m_backColor.rgba()); + QPainter p(image); + if (!m_doc.isNull()) { + QImage pageImage = m_doc->render(m_page, finalSize, options); + p.drawImage(0, 0, pageImage); + p.end(); + } + } + return true; + } + + return false; +} + +QVariant QPdfIOHandler::option(ImageOption option) const +{ + switch (option) { + case ImageFormat: + return QImage::Format_ARGB32_Premultiplied; + case Size: + const_cast<QPdfIOHandler *>(this)->load(device()); + return m_doc->pagePointSize(qMax(0, m_page)); + case ClipRect: + return m_clipRect; + case ScaledSize: + return m_scaledSize; + case ScaledClipRect: + return m_scaledClipRect; + case BackgroundColor: + return m_backColor; + case Name: + return m_doc->metaData(QPdfDocument::MetaDataField::Title); + default: + break; + } + return QVariant(); +} + +void QPdfIOHandler::setOption(ImageOption option, const QVariant & value) +{ + switch (option) { + case ClipRect: + m_clipRect = value.toRect(); + break; + case ScaledSize: + m_scaledSize = value.toSize(); + break; + case ScaledClipRect: + m_scaledClipRect = value.toRect(); + break; + case BackgroundColor: + m_backColor = value.value<QColor>(); + break; + default: + break; + } +} + +bool QPdfIOHandler::supportsOption(ImageOption option) const +{ + switch (option) + { + case ImageFormat: + case Size: + case ClipRect: + case ScaledSize: + case ScaledClipRect: + case BackgroundColor: + case Name: + return true; + default: + break; + } + return false; +} + +bool QPdfIOHandler::jumpToImage(int frame) +{ + qCDebug(qLcPdf) << frame; + if (frame < 0 || frame >= imageCount()) + return false; + m_page = frame; + return true; +} + +bool QPdfIOHandler::jumpToNextImage() +{ + return jumpToImage(m_page + 1); +} + +bool QPdfIOHandler::load(QIODevice *device) +{ + if (m_loaded) + return true; + if (format().isEmpty()) + if (!canRead()) + return false; + + 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; +} + +QT_END_NAMESPACE diff --git a/src/pdf/plugins/imageformats/pdf/qpdfiohandler_p.h b/src/pdf/plugins/imageformats/pdf/qpdfiohandler_p.h new file mode 100644 index 000000000..c4d8e0f9a --- /dev/null +++ b/src/pdf/plugins/imageformats/pdf/qpdfiohandler_p.h @@ -0,0 +1,57 @@ +// 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 + +// +// 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 <QtGui/qimageiohandler.h> +#include <QtPdf/QPdfDocument> + +QT_BEGIN_NAMESPACE + +class QPdfIOHandler : public QImageIOHandler +{ +public: + QPdfIOHandler(); + ~QPdfIOHandler() override; + bool canRead() const override; + static bool canRead(QIODevice *device); + int currentImageNumber() const override; + QRect currentImageRect() const override; + int imageCount() const override; + bool read(QImage *image) override; + QVariant option(ImageOption option) const override; + void setOption(ImageOption option, const QVariant & value) override; + bool supportsOption(ImageOption option) const override; + bool jumpToImage(int frame) override; + bool jumpToNextImage() override; + +private: + bool load(QIODevice *device); + +private: + QPointer<QPdfDocument> m_doc; + int m_page = -1; + + QRect m_clipRect; + QSize m_scaledSize; + QRect m_scaledClipRect; + QColor m_backColor = Qt::transparent; + bool m_loaded = false; + bool m_ownsDocument = false; +}; + +QT_END_NAMESPACE + +#endif // QPDFIOHANDLER_H diff --git a/src/pdf/qpdfbookmarkmodel.cpp b/src/pdf/qpdfbookmarkmodel.cpp index c9c365568..93dbf5d1f 100644 --- a/src/pdf/qpdfbookmarkmodel.cpp +++ b/src/pdf/qpdfbookmarkmodel.cpp @@ -1,38 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.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" @@ -42,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) { } @@ -81,7 +50,7 @@ public: int childCount() const { - return m_childNodes.count(); + return m_childNodes.size(); } int row() const @@ -127,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: - QVector<BookmarkNode*> m_childNodes; + 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(); @@ -179,21 +165,29 @@ 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)); - QVector<ushort> titleBuffer(titleLength); - FPDFBookmark_GetTitle(bookmark, titleBuffer.data(), quint32(titleBuffer.length())); + QList<char16_t> titleBuffer(titleLength); + FPDFBookmark_GetTitle(bookmark, titleBuffer.data(), quint32(titleBuffer.size())); const FPDF_DEST dest = FPDFBookmark_GetDest(document, bookmark); const int pageNumber = FPDFDest_GetDestPageIndex(document, dest); + const qreal pageHeight = m_document->pagePointSize(pageNumber).height(); + 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); @@ -211,30 +205,67 @@ 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; } +/*! + \property QPdfBookmarkModel::document + \brief the PDF document in which bookmarks are to be found. +*/ void QPdfBookmarkModel::setDocument(QPdfDocument *document) { - Q_D(QPdfBookmarkModel); - if (d->m_document == document) return; @@ -250,64 +281,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(); @@ -325,10 +348,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(); @@ -341,10 +365,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 new file mode 100644 index 000000000..5a3c24f84 --- /dev/null +++ b/src/pdf/qpdfbookmarkmodel.h @@ -0,0 +1,60 @@ +// 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 + +#include <QtPdf/qtpdfglobal.h> +#include <QtCore/qabstractitemmodel.h> + +QT_BEGIN_NAMESPACE + +class QPdfDocument; +struct QPdfBookmarkModelPrivate; + +class Q_PDF_EXPORT QPdfBookmarkModel : public QAbstractItemModel +{ + Q_OBJECT + + Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged) + +public: + enum class Role : int + { + Title = Qt::UserRole, + Level, + Page, + Location, + Zoom, + NRoles + }; + Q_ENUM(Role) + + QPdfBookmarkModel() : QPdfBookmarkModel(nullptr) {} + explicit QPdfBookmarkModel(QObject *parent); + ~QPdfBookmarkModel() override; + + QPdfDocument* document() const; + void setDocument(QPdfDocument *document); + + 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; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QHash<int, QByteArray> roleNames() const override; + +Q_SIGNALS: + void documentChanged(QPdfDocument *document); + +private: + std::unique_ptr<QPdfBookmarkModelPrivate> d; + + Q_PRIVATE_SLOT(d, void _q_documentStatusChanged()) + + friend struct QPdfBookmarkModelPrivate; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/pdf/qpdfdestination.cpp b/src/pdf/qpdfdestination.cpp deleted file mode 100644 index b70e031ca..000000000 --- a/src/pdf/qpdfdestination.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.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(const QPdfDestination &other) - : d(other.d) -{ -} - -QPdfDestination::QPdfDestination(QPdfDestination &&other) noexcept - : d(std::move(other.d)) -{ -} - -QPdfDestination::~QPdfDestination() -{ -} - -QPdfDestination &QPdfDestination::operator=(const QPdfDestination &other) -{ - d = other.d; - return *this; -} - -/*! - \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/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp index e4ec363ce..17fdb29b9 100644 --- a/src/pdf/qpdfdocument.cpp +++ b/src/pdf/qpdfdocument.cpp @@ -1,38 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.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" @@ -46,28 +13,102 @@ #include <QFile> #include <QHash> #include <QLoggingCategory> +#include <QMetaEnum> #include <QMutex> +#include <QPixmap> #include <QVector2D> +#include <QtCore/private/qtools_p.h> + QT_BEGIN_NAMESPACE -// The library is not thread-safe at all, it has a lot of global variables. -Q_GLOBAL_STATIC_WITH_ARGS(QMutex, pdfMutex, (QMutex::Recursive)); +Q_GLOBAL_STATIC(QRecursiveMutex, pdfMutex) static int libraryRefCount; static const double CharacterHitTolerance = 16.0; Q_LOGGING_CATEGORY(qLcDoc, "qt.pdf.document") QPdfMutexLocker::QPdfMutexLocker() - : QMutexLocker(pdfMutex()) + : std::unique_lock<QRecursiveMutex>(*pdfMutex()) { } +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] = QtMiscUtils::toAsciiLower(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; + } + + switch (role) { + case Qt::DecorationRole: + return pageThumbnail(index.row()); + case Qt::DisplayRole: + return document()->pageLabel(index.row()); + } + + 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()); } + QPixmap pageThumbnail(int page) const + { + auto it = m_thumbnails.constFind(page); + if (it == m_thumbnails.constEnd()) { + auto doc = document(); + auto size = doc->pagePointSize(page); + size.scale(128, 128, Qt::KeepAspectRatio); + // TODO use QPdfPageRenderer for threading? + auto image = document()->render(page, size.toSize()); + QPixmap ret = QPixmap::fromImage(image); + m_thumbnails.insert(page, ret); + return ret; + } + return it.value(); + } + + QHash<int, QByteArray> m_roleNames; + mutable QHash<int, QPixmap> m_thumbnails; +}; + 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()); @@ -75,8 +116,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 @@ -98,8 +143,10 @@ QPdfDocumentPrivate::~QPdfDocumentPrivate() const QPdfMutexLocker lock; - if (!--libraryRefCount) + if (!--libraryRefCount) { + qCDebug(qLcDoc) << "FPDF_DestroyLibrary"; FPDF_DestroyLibrary(); + } } void QPdfDocumentPrivate::clear() @@ -118,6 +165,7 @@ void QPdfDocumentPrivate::clear() if (pageCount != 0) { pageCount = 0; emit q->pageCountChanged(pageCount); + emit q->pageModelChanged(); } loadComplete = false; @@ -133,7 +181,7 @@ void QPdfDocumentPrivate::clear() void QPdfDocumentPrivate::updateLastError() { if (doc) { - lastError = QPdfDocument::NoError; + lastError = QPdfDocument::Error::None; return; } @@ -142,15 +190,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) @@ -166,19 +216,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); } }); @@ -190,7 +240,7 @@ void QPdfDocumentPrivate::load(QIODevice *newDevice, bool transferDeviceOwnershi device = newDevice; initiateAsyncLoadWithTotalSizeKnown(device->size()); if (!avail) { - setStatus(QPdfDocument::Error); + setStatus(QPdfDocument::Status::Error); return; } @@ -199,7 +249,7 @@ void QPdfDocumentPrivate::load(QIODevice *newDevice, bool transferDeviceOwnershi if (!doc) { updateLastError(); - setStatus(QPdfDocument::Error); + setStatus(QPdfDocument::Status::Error); return; } @@ -209,15 +259,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); } } } @@ -229,13 +280,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; } @@ -281,11 +332,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; } @@ -295,12 +345,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(); } } @@ -337,9 +389,10 @@ void QPdfDocumentPrivate::checkComplete() if (newPageCount != pageCount) { pageCount = newPageCount; emit q->pageCountChanged(pageCount); + emit q->pageModelChanged(); } - setStatus(QPdfDocument::Ready); + setStatus(QPdfDocument::Status::Ready); } } @@ -393,46 +446,98 @@ void QPdfDocumentPrivate::fpdf_AddSegment(_FX_DOWNLOADHINTS *pThis, size_t offse Q_UNUSED(size); } -QString QPdfDocumentPrivate::getText(FPDF_TEXTPAGE textPage, int startIndex, int count) +QString QPdfDocumentPrivate::getText(FPDF_TEXTPAGE textPage, int startIndex, int count) const { - QVector<ushort> buf(count + 1); + QList<ushort> buf(count + 1); // TODO is that enough space in case one unicode character is more than one in utf-16? int len = FPDFText_GetText(textPage, startIndex, count, buf.data()); Q_ASSERT(len - 1 <= count); // len is number of characters written, including the terminator - return QString::fromUtf16(buf.constData(), len - 1); + return QString::fromUtf16(reinterpret_cast<const char16_t *>(buf.constData()), len - 1); } -QPointF QPdfDocumentPrivate::getCharPosition(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex) +QPointF QPdfDocumentPrivate::getCharPosition(FPDF_PAGE pdfPage, FPDF_TEXTPAGE textPage, int charIndex) const { double x, y; - int count = FPDFText_CountChars(textPage); - bool ok = FPDFText_GetCharOrigin(textPage, qMin(count - 1, charIndex), &x, &y); - if (!ok) - return QPointF(); - return QPointF(x, pageHeight - y); + const int count = FPDFText_CountChars(textPage); + if (FPDFText_GetCharOrigin(textPage, qMin(count - 1, charIndex), &x, &y)) + return mapPageToView(pdfPage, x, y); + return {}; } -QRectF QPdfDocumentPrivate::getCharBox(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex) +QRectF QPdfDocumentPrivate::getCharBox(FPDF_PAGE pdfPage, FPDF_TEXTPAGE textPage, int charIndex) const { double l, t, r, b; - bool ok = FPDFText_GetCharBox(textPage, charIndex, &l, &r, &b, &t); - if (!ok) - return QRectF(); - return QRectF(l, pageHeight - t, r - l, t - b); + if (FPDFText_GetCharBox(textPage, charIndex, &l, &r, &b, &t)) + return mapPageToView(pdfPage, l, t, r, b); + return {}; +} + +/*! \internal + Convert the point \a x , \a y to the usual 1x (pixels = points) + 4th-quadrant "view" coordinate system relative to the top-left corner of + the rendered page. Some PDF files have internal transforms that make this + coordinate system different from "page coordinates", so we cannot just + subtract from page height to invert the y coordinates, in general. + */ +QPointF QPdfDocumentPrivate::mapPageToView(FPDF_PAGE pdfPage, double x, double y) const +{ + const auto pageHeight = FPDF_GetPageHeight(pdfPage); + const auto pageWidth = FPDF_GetPageWidth(pdfPage); + int rx, ry; + if (FPDF_PageToDevice(pdfPage, 0, 0, qRound(pageWidth), qRound(pageHeight), 0, x, y, &rx, &ry)) + return QPointF(rx, ry); + return {}; +} + +/*! \internal + Convert the bounding box defined by \a left \a top \a right and \a bottom + to the usual 1x (pixels = points) 4th-quadrant "view" coordinate system + that we use for rendering things on top of the page image. + Some PDF files have internal transforms that make this coordinate + system different from "page coordinates", so we cannot just + subtract from page height to invert the y coordinates, in general. + */ +QRectF QPdfDocumentPrivate::mapPageToView(FPDF_PAGE pdfPage, double left, double top, double right, double bottom) const +{ + const auto pageHeight = FPDF_GetPageHeight(pdfPage); + const auto pageWidth = FPDF_GetPageWidth(pdfPage); + int xfmLeft, xfmTop, xfmRight, xfmBottom; + if ( FPDF_PageToDevice(pdfPage, 0, 0, qRound(pageWidth), qRound(pageHeight), 0, left, top, &xfmLeft, &xfmTop) && + FPDF_PageToDevice(pdfPage, 0, 0, qRound(pageWidth), qRound(pageHeight), 0, right, bottom, &xfmRight, &xfmBottom) ) + return QRectF(xfmLeft, xfmTop, xfmRight - xfmLeft, xfmBottom - xfmTop); + return {}; +} + +/*! \internal + Convert the point \a x , \a y \a from the usual 1x (pixels = points) + 4th-quadrant "view" coordinate system relative to the top-left corner of + the rendered page, to "page coordinates" suited to the given \a pdfPage, + which may have arbitrary internal transforms. + */ +QPointF QPdfDocumentPrivate::mapViewToPage(FPDF_PAGE pdfPage, QPointF position) const +{ + const auto pageHeight = FPDF_GetPageHeight(pdfPage); + const auto pageWidth = FPDF_GetPageWidth(pdfPage); + double rx, ry; + if (FPDF_DeviceToPage(pdfPage, 0, 0, qRound(pageWidth), qRound(pageHeight), 0, position.x(), position.y(), &rx, &ry)) + return QPointF(rx, ry); + return {}; } QPdfDocumentPrivate::TextPosition QPdfDocumentPrivate::hitTest(int page, QPointF position) { const QPdfMutexLocker lock; + + TextPosition result; FPDF_PAGE pdfPage = FPDF_LoadPage(doc, page); - double pageHeight = FPDF_GetPageHeight(pdfPage); FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage); - int hitIndex = FPDFText_GetCharIndexAtPos(textPage, position.x(), pageHeight - position.y(), + const QPointF pagePos = mapViewToPage(pdfPage, position); + int hitIndex = FPDFText_GetCharIndexAtPos(textPage, pagePos.x(), pagePos.y(), CharacterHitTolerance, CharacterHitTolerance); if (hitIndex >= 0) { - QPointF charPos = getCharPosition(textPage, pageHeight, hitIndex); + QPointF charPos = getCharPosition(pdfPage, textPage, hitIndex); if (!charPos.isNull()) { - QRectF charBox = getCharBox(textPage, pageHeight, hitIndex); + QRectF charBox = getCharBox(pdfPage, textPage, hitIndex); // If the given position is past the end of the line, i.e. if the right edge of the found character's // bounding box is closer to it than the left edge is, we say that we "hit" the next character index after if (qAbs(charBox.right() - position.x()) < qAbs(charPos.x() - position.x())) { @@ -440,10 +545,14 @@ QPdfDocumentPrivate::TextPosition QPdfDocumentPrivate::hitTest(int page, QPointF ++hitIndex; } qCDebug(qLcDoc) << "on page" << page << "@" << position << "got char position" << charPos << "index" << hitIndex; - return { charPos, charBox.height(), hitIndex }; + result = { charPos, charBox.height(), hitIndex }; } } - return {}; + + FPDFText_ClosePage(textPage); + FPDF_ClosePage(pdfPage); + + return result; } /*! @@ -471,24 +580,39 @@ QPdfDocument::~QPdfDocument() { } -QPdfDocument::DocumentError QPdfDocument::load(const QString &fileName) +/*! + Loads the document contents from \a 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 @@ -505,22 +629,35 @@ QPdfDocument::DocumentError QPdfDocument::load(const QString &fileName) */ /*! - Returns the current status of the document. + \property QPdfDocument::status + + This property holds the current status of the document. */ QPdfDocument::Status QPdfDocument::status() const { return d->status; } +/*! + Loads the document contents from \a device. +*/ void QPdfDocument::load(QIODevice *device) { close(); - d->setStatus(QPdfDocument::Loading); + d->setStatus(QPdfDocument::Status::Loading); d->load(device, /*transfer ownership*/false); } +/*! + \property QPdfDocument::password + + This property holds the document password. + + If the document is protected by a password, the user must provide it, and + the application must set this property. Otherwise, it's not needed. +*/ void QPdfDocument::setPassword(const QString &password) { const QByteArray newPassword = password.toUtf8(); @@ -565,53 +702,36 @@ 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; const unsigned long len = FPDF_GetMetaText(d->doc, fieldName.constData(), nullptr, 0); - QVector<ushort> buf(len); - FPDF_GetMetaText(d->doc, fieldName.constData(), buf.data(), buf.length()); + QList<ushort> buf(len); + FPDF_GetMetaText(d->doc, fieldName.constData(), buf.data(), buf.size()); lock.unlock(); - QString text = QString::fromUtf16(buf.data()); + 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); @@ -630,20 +750,40 @@ QVariant QPdfDocument::metaData(MetaDataField field) const return QVariant(); } -QPdfDocument::DocumentError QPdfDocument::error() const +/*! + \enum QPdfDocument::Error + + This enum describes the error while attempting the last operation on the document. + + \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() +*/ + +/*! + Returns the type of error if \l status is \c Error, or \c NoError if there + is no error. +*/ +QPdfDocument::Error QPdfDocument::error() const { return d->lastError; } /*! - Closes the document. + Closes the document. */ void QPdfDocument::close() { if (!d->doc) return; - d->setStatus(Unloading); + d->setStatus(Status::Unloading); d->clear(); @@ -652,19 +792,24 @@ void QPdfDocument::close() emit passwordChanged(); } - d->setStatus(Null); + d->setStatus(Status::Null); } /*! - Returns the amount of pages for the loaded document or \c 0 if - no document is loaded. + \property QPdfDocument::pageCount + + This property holds the number of pages in the loaded document or \c 0 if + no document is loaded. */ int QPdfDocument::pageCount() const { return d->pageCount; } -QSizeF QPdfDocument::pageSize(int page) const +/*! + Returns the size of page \a page in points (1/72 of an inch). +*/ +QSizeF QPdfDocument::pagePointSize(int page) const { QSizeF result; if (!d->doc || !d->checkPageComplete(page)) @@ -677,6 +822,74 @@ 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}. + + \sa pageIndexForLabel() +*/ +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()); +} + +/*! + Returns the index of the page that has the \a label, or \c -1 if not found. + + \sa pageLabel() + \since 6.6 +*/ +int QPdfDocument::pageIndexForLabel(const QString &label) +{ + for (int i = 0; i < d->pageCount; ++i) { + if (pageLabel(i) == label) + return i; + } + return -1; +} + +/*! Renders the \a page into a QImage of size \a imageSize according to the provided \a renderOptions. @@ -704,37 +917,21 @@ QImage QPdfDocument::render(int page, QSize imageSize, QPdfDocumentRenderOptions result.fill(Qt::transparent); FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(result.width(), result.height(), FPDFBitmap_BGRA, result.bits(), result.bytesPerLine()); - int rotation = 0; - switch (renderOptions.rotation()) { - case QPdf::Rotate0: - rotation = 0; - break; - case QPdf::Rotate90: - rotation = 1; - break; - case QPdf::Rotate180: - rotation = 2; - break; - case QPdf::Rotate270: - 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()) { @@ -747,7 +944,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()), @@ -765,6 +962,7 @@ QImage QPdfDocument::render(int page, QSize imageSize, QPdfDocumentRenderOptions qCDebug(qLcDoc) << "page" << page << "region" << renderOptions.scaledClipRect() << "size" << imageSize << "took" << timer.elapsed() << "ms"; } else { + const auto rotation = QPdfDocumentPrivate::toFPDFRotation(renderOptions.rotation()); FPDF_RenderPageBitmap(bitmap, pdfPage, 0, 0, result.width(), result.height(), rotation, flags); qCDebug(qLcDoc) << "page" << page << "size" << imageSize << "took" << timer.elapsed() << "ms"; } @@ -783,31 +981,35 @@ QPdfSelection QPdfDocument::getSelection(int page, QPointF start, QPointF end) { const QPdfMutexLocker lock; FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page); - double pageHeight = FPDF_GetPageHeight(pdfPage); + const QPointF pageStart = d->mapViewToPage(pdfPage, start); + const QPointF pageEnd = d->mapViewToPage(pdfPage, end); FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage); - int startIndex = FPDFText_GetCharIndexAtPos(textPage, start.x(), pageHeight - start.y(), + int startIndex = FPDFText_GetCharIndexAtPos(textPage, pageStart.x(), pageStart.y(), CharacterHitTolerance, CharacterHitTolerance); - int endIndex = FPDFText_GetCharIndexAtPos(textPage, end.x(), pageHeight - end.y(), + int endIndex = FPDFText_GetCharIndexAtPos(textPage, pageEnd.x(), pageEnd.y(), CharacterHitTolerance, CharacterHitTolerance); + + QPdfSelection result; + if (startIndex >= 0 && endIndex != startIndex) { if (startIndex > endIndex) qSwap(startIndex, endIndex); // If the given end position is past the end of the line, i.e. if the right edge of the last character's // bounding box is closer to it than the left edge is, then extend the char range by one - QRectF endCharBox = d->getCharBox(textPage, pageHeight, endIndex); + QRectF endCharBox = d->getCharBox(pdfPage, textPage, endIndex); if (qAbs(endCharBox.right() - end.x()) < qAbs(endCharBox.x() - end.x())) ++endIndex; int count = endIndex - startIndex; QString text = d->getText(textPage, startIndex, count); - QVector<QPolygonF> bounds; + QList<QPolygonF> bounds; QRectF hull; int rectCount = FPDFText_CountRects(textPage, startIndex, endIndex - startIndex); for (int i = 0; i < rectCount; ++i) { double l, r, b, t; FPDFText_GetRect(textPage, i, &l, &t, &r, &b); - QRectF rect(l, pageHeight - t, r - l, t - b); + const QRectF rect = d->mapPageToView(pdfPage, l, t, r, b); if (hull.isNull()) hull = rect; else @@ -815,16 +1017,20 @@ QPdfSelection QPdfDocument::getSelection(int page, QPointF start, QPointF end) bounds << QPolygonF(rect); } qCDebug(qLcDoc) << page << start << "->" << end << "found" << startIndex << "->" << endIndex << text; - return QPdfSelection(text, bounds, hull, startIndex, endIndex); + result = QPdfSelection(text, bounds, hull, startIndex, endIndex); + } else { + qCDebug(qLcDoc) << page << start << "->" << end << "nothing found"; } - qCDebug(qLcDoc) << page << start << "->" << end << "nothing found"; - return QPdfSelection(); + FPDFText_ClosePage(textPage); + FPDF_ClosePage(pdfPage); + + return result; } /*! Returns information about the text on the given \a page that can be found - beginning at the given \a startIndex with at most \l maxLength characters. + beginning at the given \a startIndex with at most \a maxLength characters. */ QPdfSelection QPdfDocument::getSelectionAtIndex(int page, int startIndex, int maxLength) { @@ -833,22 +1039,21 @@ QPdfSelection QPdfDocument::getSelectionAtIndex(int page, int startIndex, int ma return {}; const QPdfMutexLocker lock; FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page); - double pageHeight = FPDF_GetPageHeight(pdfPage); FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage); int pageCount = FPDFText_CountChars(textPage); if (startIndex >= pageCount) return QPdfSelection(); - QVector<QPolygonF> bounds; + QList<QPolygonF> bounds; QRectF hull; int rectCount = 0; QString text; if (maxLength > 0) { text = d->getText(textPage, startIndex, maxLength); - rectCount = FPDFText_CountRects(textPage, startIndex, text.length()); + rectCount = FPDFText_CountRects(textPage, startIndex, text.size()); for (int i = 0; i < rectCount; ++i) { double l, r, b, t; FPDFText_GetRect(textPage, i, &l, &t, &r, &b); - QRectF rect(l, pageHeight - t, r - l, t - b); + const QRectF rect = d->mapPageToView(pdfPage, l, t, r, b); if (hull.isNull()) hull = rect; else @@ -857,10 +1062,14 @@ QPdfSelection QPdfDocument::getSelectionAtIndex(int page, int startIndex, int ma } } if (bounds.isEmpty()) - hull = QRectF(d->getCharPosition(textPage, pageHeight, startIndex), QSizeF()); + hull = QRectF(d->getCharPosition(pdfPage, textPage, startIndex), QSizeF()); qCDebug(qLcDoc) << "on page" << page << "at index" << startIndex << "maxLength" << maxLength - << "got" << text.length() << "chars," << rectCount << "rects within" << hull; - return QPdfSelection(text, bounds, hull, startIndex, startIndex + text.length()); + << "got" << text.size() << "chars," << rectCount << "rects within" << hull; + + FPDFText_ClosePage(textPage); + FPDF_ClosePage(pdfPage); + + return QPdfSelection(text, bounds, hull, startIndex, startIndex + text.size()); } /*! @@ -870,19 +1079,18 @@ QPdfSelection QPdfDocument::getAllText(int page) { const QPdfMutexLocker lock; FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page); - double pageHeight = FPDF_GetPageHeight(pdfPage); FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage); int count = FPDFText_CountChars(textPage); if (count < 1) return QPdfSelection(); QString text = d->getText(textPage, 0, count); - QVector<QPolygonF> bounds; + QList<QPolygonF> bounds; QRectF hull; int rectCount = FPDFText_CountRects(textPage, 0, count); for (int i = 0; i < rectCount; ++i) { double l, r, b, t; FPDFText_GetRect(textPage, i, &l, &t, &r, &b); - QRectF rect(l, pageHeight - t, r - l, t - b); + const QRectF rect = d->mapPageToView(pdfPage, l, t, r, b); if (hull.isNull()) hull = rect; else @@ -890,9 +1098,14 @@ QPdfSelection QPdfDocument::getAllText(int page) bounds << QPolygonF(rect); } qCDebug(qLcDoc) << "on page" << page << "got" << count << "chars," << rectCount << "rects within" << hull; + + FPDFText_ClosePage(textPage); + FPDF_ClosePage(pdfPage); + return QPdfSelection(text, bounds, hull, 0, count); } QT_END_NAMESPACE +#include "qpdfdocument.moc" #include "moc_qpdfdocument.cpp" diff --git a/src/pdf/qpdfdocument.h b/src/pdf/qpdfdocument.h new file mode 100644 index 000000000..8355246ae --- /dev/null +++ b/src/pdf/qpdfdocument.h @@ -0,0 +1,127 @@ +// 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 + +#include <QtPdf/qtpdfglobal.h> + +#include <QtCore/qobject.h> +#include <QtCore/QAbstractListModel> +#include <QtGui/qimage.h> +#include <QtPdf/qpdfdocumentrenderoptions.h> +#include <QtPdf/qpdfselection.h> + +QT_BEGIN_NAMESPACE + +class QPdfDocumentPrivate; +class QNetworkReply; + +class Q_PDF_EXPORT QPdfDocument : public QObject +{ + Q_OBJECT + + 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 class Status { + Null, + Loading, + Ready, + Unloading, + Error + }; + Q_ENUM(Status) + + enum class Error { + None, + Unknown, + DataNotYetAvailable, + FileNotFound, + InvalidFileFormat, + IncorrectPassword, + UnsupportedSecurityScheme + }; + Q_ENUM(Error) + + enum class MetaDataField { + Title, + Subject, + Author, + Keywords, + Producer, + Creator, + CreationDate, + ModificationDate + }; + Q_ENUM(MetaDataField) + + enum class PageModelRole { + Label = Qt::UserRole, + PointSize, + NRoles + }; + Q_ENUM(PageModelRole) + + QPdfDocument() : QPdfDocument(nullptr) {} + explicit QPdfDocument(QObject *parent); + ~QPdfDocument() override; + + Error load(const QString &fileName); + + Status status() const; + + void load(QIODevice *device); + void setPassword(const QString &password); + QString password() const; + + QVariant metaData(MetaDataField field) const; + + Error error() const; + + void close(); + + int pageCount() const; + + Q_INVOKABLE QSizeF pagePointSize(int page) const; + + Q_INVOKABLE QString pageLabel(int page); + Q_INVOKABLE int pageIndexForLabel(const QString &label); + + QAbstractListModel *pageModel(); + + QImage render(int page, QSize imageSize, QPdfDocumentRenderOptions options = QPdfDocumentRenderOptions()); + + Q_INVOKABLE QPdfSelection getSelection(int page, QPointF start, QPointF end); + Q_INVOKABLE QPdfSelection getSelectionAtIndex(int page, int startIndex, int maxLength); + Q_INVOKABLE QPdfSelection getAllText(int page); + +Q_SIGNALS: + void passwordChanged(); + void passwordRequired(); + void statusChanged(QPdfDocument::Status status); + void pageCountChanged(int pageCount); + void pageModelChanged(); + +private: + 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; +}; + +QT_END_NAMESPACE + +#endif // QPDFDOCUMENT_H diff --git a/src/pdf/api/qpdfdocument_p.h b/src/pdf/qpdfdocument_p.h index 9a737766b..cdb76d16f 100644 --- a/src/pdf/api/qpdfdocument_p.h +++ b/src/pdf/qpdfdocument_p.h @@ -1,38 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.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 @@ -49,6 +16,7 @@ // #include "qpdfdocument.h" +#include "qtpdfexports.h" #include "third_party/pdfium/public/fpdfview.h" #include "third_party/pdfium/public/fpdf_dataavail.h" @@ -58,21 +26,26 @@ #include <QtCore/qpointer.h> #include <QtNetwork/qnetworkreply.h> +#include <mutex> + QT_BEGIN_NAMESPACE -class QPdfMutexLocker : public QMutexLocker +class QPdfMutexLocker : public std::unique_lock<QRecursiveMutex> { public: QPdfMutexLocker(); }; -class Q_PDF_PRIVATE_EXPORT QPdfDocumentPrivate: public FPDF_FILEACCESS, public FX_FILEAVAIL, public FX_DOWNLOADHINTS +class QPdfPageModel; + +class Q_PDF_EXPORT QPdfDocumentPrivate: public FPDF_FILEACCESS, public FX_FILEAVAIL, public FX_DOWNLOADHINTS { public: QPdfDocumentPrivate(); ~QPdfDocumentPrivate(); QPdfDocument *q; + QPdfPageModel *pageModel = nullptr; FPDF_AVAIL avail; FPDF_DOCUMENT doc; @@ -85,7 +58,7 @@ public: QByteArray password; QPdfDocument::Status status; - QPdfDocument::DocumentError lastError; + QPdfDocument::Error lastError; int pageCount; void clear(); @@ -105,9 +78,37 @@ public: static int fpdf_GetBlock(void* param, unsigned long position, unsigned char* pBuf, unsigned long size); static void fpdf_AddSegment(struct _FX_DOWNLOADHINTS* pThis, size_t offset, size_t size); void updateLastError(); - QString getText(FPDF_TEXTPAGE textPage, int startIndex, int count); - QPointF getCharPosition(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex); - QRectF getCharBox(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex); + QString getText(FPDF_TEXTPAGE textPage, int startIndex, int count) const; + QPointF getCharPosition(FPDF_PAGE pdfPage, FPDF_TEXTPAGE textPage, int charIndex) const; + QRectF getCharBox(FPDF_PAGE pdfPage, FPDF_TEXTPAGE textPage, int charIndex) const; + QPointF mapPageToView(FPDF_PAGE pdfPage, double x, double y) const; + QRectF mapPageToView(FPDF_PAGE pdfPage, double left, double top, double right, double bottom) const; + QPointF mapViewToPage(FPDF_PAGE pdfPage, QPointF position) const; + + // FPDF takes the rotation parameter as an int. + // This enum is mapping the int values defined in fpdfview.h:956. + // (not using enum class to ensure int convertability) + enum QFPDFRotation { + Normal = 0, + ClockWise90 = 1, + ClockWise180 = 2, + CounterClockWise90 = 3 + }; + + static constexpr QFPDFRotation toFPDFRotation(QPdfDocumentRenderOptions::Rotation rotation) + { + switch (rotation) { + case QPdfDocumentRenderOptions::Rotation::None: + return QFPDFRotation::Normal; + case QPdfDocumentRenderOptions::Rotation::Clockwise90: + return QFPDFRotation::ClockWise90; + case QPdfDocumentRenderOptions::Rotation::Clockwise180: + return QFPDFRotation::ClockWise180; + case QPdfDocumentRenderOptions::Rotation::Clockwise270: + return QFPDFRotation::CounterClockWise90; + } + Q_UNREACHABLE(); + } struct TextPosition { QPointF position; diff --git a/src/pdf/qpdfdocumentrenderoptions.h b/src/pdf/qpdfdocumentrenderoptions.h new file mode 100644 index 000000000..af074d976 --- /dev/null +++ b/src/pdf/qpdfdocumentrenderoptions.h @@ -0,0 +1,81 @@ +// 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/qtpdfglobal.h> +#include <QtCore/qobject.h> +#include <QtCore/qrect.h> + +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 Rotation rotation() const noexcept { return static_cast<Rotation>(m_rotation); } + constexpr void setRotation(Rotation r) noexcept { m_rotation = quint32(r); } + + 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; } + + constexpr QSize scaledSize() const noexcept { return m_scaledSize; } + constexpr void setScaledSize(const QSize &s) noexcept { m_scaledSize = s; } + +private: + friend constexpr inline bool operator==(const QPdfDocumentRenderOptions &lhs, const QPdfDocumentRenderOptions &rhs) noexcept; + + QRect m_clipRect; + QSize m_scaledSize; + + quint32 m_renderFlags : 8; + quint32 m_rotation : 3; + quint32 m_reserved : 21; + quint32 m_reserved2 = 0; +}; + +Q_DECLARE_TYPEINFO(QPdfDocumentRenderOptions, Q_PRIMITIVE_TYPE); +Q_DECLARE_OPERATORS_FOR_FLAGS(QPdfDocumentRenderOptions::RenderFlags) + +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!=(const QPdfDocumentRenderOptions &lhs, const QPdfDocumentRenderOptions &rhs) noexcept +{ + return !operator==(lhs, rhs); +} + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QPdfDocumentRenderOptions) + +#endif // QPDFDOCUMENTRENDEROPTIONS_H diff --git a/src/pdf/qpdfdocumentrenderoptions.qdoc b/src/pdf/qpdfdocumentrenderoptions.qdoc index cc5083f9d..ad8e7bfdb 100644 --- a/src/pdf/qpdfdocumentrenderoptions.qdoc +++ b/src/pdf/qpdfdocumentrenderoptions.qdoc @@ -1,38 +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: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.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" @@ -49,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. @@ -63,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. @@ -71,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. @@ -79,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. @@ -96,10 +92,10 @@ QT_BEGIN_NAMESPACE */ /*! - \fn void QPdfDocumentRenderOptions::setScaledClipRect(QRect rect) + \fn void QPdfDocumentRenderOptions::setScaledClipRect(const QRect &r) - Sets the region \a rect to be clipped from the page after having been - scaled to \l scaledSize(). + Sets the rectangle region (\a r) to be clipped from the page after having + been scaled to \l scaledSize(). \sa scaledClipRect() */ @@ -107,15 +103,15 @@ QT_BEGIN_NAMESPACE /*! \fn QRect QPdfDocumentRenderOptions::scaledSize() const - Returns the \a size of the page to be rendered, in pixels. + Returns the size of the page to be rendered, in pixels. \sa setScaledSize() */ /*! - \fn void QPdfDocumentRenderOptions::setScaledSize(QSize size) + \fn void QPdfDocumentRenderOptions::setScaledSize(const QSize &s) - Sets the \a size of the page to be rendered, in pixels. + Sets the size (\a s) of the page to be rendered, in pixels. \sa scaledSize() */ 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..0c2867086 --- /dev/null +++ b/src/pdf/qpdflink.cpp @@ -0,0 +1,189 @@ +// 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 +{ + if (d->page <= 0) + return d->url.toString(); + return QPdfLinkModel::tr("Page %1 location %2, %3 zoom %4") + .arg(d->page).arg(d->location.x(), 0, 'f', 1).arg(d->location.y(), 0, 'f', 1) + .arg(d->zoom, 0, 'f', 0); +} + +/*! + 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 900d3cd9e..0a8b1e812 100644 --- a/src/pdf/qpdflinkmodel.cpp +++ b/src/pdf/qpdflinkmodel.cpp @@ -1,41 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.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.h" #include "qpdflinkmodel_p.h" -#include "qpdflinkmodel_p_p.h" #include "qpdfdocument_p.h" #include "third_party/pdfium/public/fpdf_doc.h" @@ -48,44 +16,85 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(qLcLink, "qt.pdf.links") +/*! + \class QPdfLinkModel + \since 6.6 + \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. +*/ + +/*! + \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 +*/ + +/*! + Constructs a new link model with parent object \a parent. +*/ QPdfLinkModel::QPdfLinkModel(QObject *parent) - : QAbstractListModel(*(new QPdfLinkModelPrivate()), parent) + : QAbstractListModel(parent), + d_ptr{std::make_unique<QPdfLinkModelPrivate>(this)} { + Q_D(QPdfLinkModel); QMetaEnum rolesMetaEnum = metaObject()->enumerator(metaObject()->indexOfEnumerator("Role")); - for (int r = Qt::UserRole; r < int(Role::_Count); ++r) - m_roleNames.insert(r, QByteArray(rolesMetaEnum.valueToKey(r)).toLower()); + for (int r = Qt::UserRole; r < int(Role::NRoles); ++r) + d->roleNames.insert(r, QByteArray(rolesMetaEnum.valueToKey(r)).toLower()); } +/*! + Destroys the model. +*/ QPdfLinkModel::~QPdfLinkModel() {} QHash<int, QByteArray> QPdfLinkModel::roleNames() const { - return m_roleNames; + Q_D(const QPdfLinkModel); + return d->roleNames; } +/*! + \reimp +*/ int QPdfLinkModel::rowCount(const QModelIndex &parent) const { Q_D(const QPdfLinkModel); - Q_UNUSED(parent) - return d->links.count(); + Q_UNUSED(parent); + return d->links.size(); } +/*! + \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) @@ -93,6 +102,10 @@ QVariant QPdfLinkModel::data(const QModelIndex &index, int role) const return QVariant(); } +/*! + \property QPdfLinkModel::document + \brief The document to load links from. +*/ QPdfDocument *QPdfLinkModel::document() const { Q_D(const QPdfLinkModel); @@ -115,6 +128,10 @@ void QPdfLinkModel::setDocument(QPdfDocument *document) d->update(); } +/*! + \property QPdfLinkModel::page + \brief The page to load links from. +*/ int QPdfLinkModel::page() const { Q_D(const QPdfLinkModel); @@ -132,8 +149,22 @@ void QPdfLinkModel::setPage(int page) d->update(); } -QPdfLinkModelPrivate::QPdfLinkModelPrivate() : QAbstractItemModelPrivate() +/*! + Returns a \l {QPdfLink::isValid()}{valid} link if found under the \a point + (given in units of points, 1/72 of an inch), or an invalid link if it is + not found. In other words, this function is useful for picking, to handle + mouse click or hover. +*/ +QPdfLink QPdfLinkModel::linkAt(QPointF point) const { + Q_D(const QPdfLinkModel); + for (const auto &link : std::as_const(d->links)) { + for (const auto &rect : link.rectangles()) { + if (rect.contains(point)) + return link; + } + } + return {}; } void QPdfLinkModelPrivate::update() @@ -148,7 +179,6 @@ void QPdfLinkModelPrivate::update() qCWarning(qLcLink) << "failed to load page" << page; return; } - double pageHeight = FPDF_GetPageHeight(pdfPage); q->beginResetModel(); links.clear(); @@ -166,42 +196,68 @@ 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, - rect.right - rect.left, rect.top - rect.bottom); + // In case horizontal/vertical coordinates are flipped, swap them. + if (rect.right < rect.left) + std::swap(rect.right, rect.left); + if (rect.bottom > rect.top) + std::swap(rect.bottom, rect.top); + + QPdfLink linkData; + // Use quad points if present; otherwise use the rect. + if (int quadPointsCount = FPDFLink_CountQuadPoints(linkAnnot) > 0) { + for (int i = 0; i < quadPointsCount; ++i) { + FS_QUADPOINTSF point; + if (FPDFLink_GetQuadPoints(linkAnnot, i, &point)) { + // Quadpoints are counter clockwise from bottom left (x1, y1) + QPolygonF poly; + poly << QPointF(point.x1, point.y1); + poly << QPointF(point.x2, point.y2); + poly << QPointF(point.x3, point.y3); + poly << QPointF(point.x4, point.y4); + QRectF bounds = poly.boundingRect(); + bounds = document->d->mapPageToView(pdfPage, bounds.left(), bounds.top(), bounds.right(), bounds.bottom()); + qCDebug(qLcLink) << "quadpoints" << i << "of" << quadPointsCount << ":" << poly << "mapped bounds" << bounds; + linkData.d->rects << bounds; + // QPdfLink could store polygons rather than rects, to get the benefit of quadpoints; + // so far we didn't bother. It would be an API change, and we'd need to use Shapes in PdfLinkDelegate.qml + } + } + } else { + linkData.d->rects << document->d->mapPageToView(pdfPage, rect.left, rect.top, rect.right, 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) { - qCWarning(qLcLink) << "skipping link with invalid page number"; + linkData.d->page = FPDFDest_GetDestPageIndex(doc, dest); + if (linkData.d->page < 0) { + qCWarning(qLcLink) << "skipping link with invalid page number" << linkData.d->page; continue; // while enumerating links } FPDF_BOOL hasX, hasY, hasZoom; 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 = document->d->mapPageToView(pdfPage, x, 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; } @@ -209,13 +265,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 @@ -234,23 +290,23 @@ 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"; } else { - QVector<unsigned short> buf(len); + QList<unsigned short> buf(len); int got = FPDFLink_GetURL(webLinks, i, buf.data(), len); Q_ASSERT(got == len); - linkData.url = QString::fromUtf16(buf.data(), got - 1); + 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 << document->d->mapPageToView(pdfPage, left, top, right, bottom); links << linkData; } } @@ -263,8 +319,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(); } @@ -273,21 +329,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.h b/src/pdf/qpdflinkmodel.h new file mode 100644 index 000000000..be2ce890c --- /dev/null +++ b/src/pdf/qpdflinkmodel.h @@ -0,0 +1,67 @@ +// 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_H +#define QPDFLINKMODEL_H + +#include <QtPdf/qtpdfglobal.h> +#include <QtPdf/qpdfdocument.h> +#include <QtPdf/qpdflink.h> + +#include <QtCore/QAbstractListModel> + +#include <memory> + +QT_BEGIN_NAMESPACE + +class QPdfLinkModelPrivate; + +class Q_PDF_EXPORT QPdfLinkModel : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(QPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged) + Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged) + +public: + enum class Role { + Link = Qt::UserRole, + Rectangle, + Url, + Page, + Location, + Zoom, + NRoles + }; + Q_ENUM(Role) + explicit QPdfLinkModel(QObject *parent = nullptr); + ~QPdfLinkModel() override; + + QPdfDocument *document() const; + + QHash<int, QByteArray> roleNames() const override; + int rowCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role) const override; + + int page() const; + + QPdfLink linkAt(QPointF point) const; + +public Q_SLOTS: + void setDocument(QPdfDocument *document); + void setPage(int page); + +Q_SIGNALS: + void documentChanged(); + void pageChanged(int page); + +private Q_SLOTS: + void onStatusChanged(QPdfDocument::Status status); + +private: + Q_DECLARE_PRIVATE(QPdfLinkModel) + const std::unique_ptr<QPdfLinkModelPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QPDFLINKMODEL_H diff --git a/src/pdf/qpdflinkmodel_p.h b/src/pdf/qpdflinkmodel_p.h new file mode 100644 index 000000000..ba46a6e00 --- /dev/null +++ b/src/pdf/qpdflinkmodel_p.h @@ -0,0 +1,42 @@ +// 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 + +// +// 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 "qpdflinkmodel.h" +#include <private/qabstractitemmodel_p.h> + +QT_BEGIN_NAMESPACE + +class QPdfLinkModelPrivate +{ + QPdfLinkModel *q_ptr; + Q_DECLARE_PUBLIC(QPdfLinkModel) + +public: + explicit QPdfLinkModelPrivate(QPdfLinkModel *qq) + : q_ptr(qq) {} + + void update(); + + QHash<int, QByteArray> roleNames; + QPdfDocument *document = nullptr; + QList<QPdfLink> links; + int page = 0; +}; + +QT_END_NAMESPACE + +#endif // QPDFLINKMODEL_P_H diff --git a/src/pdf/qpdfnamespace.qdoc b/src/pdf/qpdfnamespace.qdoc deleted file mode 100644 index 96bb090e9..000000000 --- a/src/pdf/qpdfnamespace.qdoc +++ /dev/null @@ -1,74 +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: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.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 497c1c2eb..000000000 --- a/src/pdf/qpdfpagenavigation.cpp +++ /dev/null @@ -1,314 +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: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qpdfpagenavigation.h" - -#include "qpdfdocument.h" - -#include <private/qobject_p.h> - -#include <QPointer> - -QT_BEGIN_NAMESPACE - -class QPdfPageNavigationPrivate : public QObjectPrivate -{ -public: - QPdfPageNavigationPrivate() - : QObjectPrivate() - { - } - - void update() - { - Q_Q(QPdfPageNavigation); - - 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->pageCountChanged(m_pageCount); - } - } else { - if (m_pageCount != 0) { - m_pageCount = 0; - emit q->pageCountChanged(m_pageCount); - } - } - - if (m_currentPage != 0) { - m_currentPage = 0; - emit q->currentPageChanged(m_currentPage); - } - - updatePrevNext(); - } - - void updatePrevNext() - { - Q_Q(QPdfPageNavigation); - - const bool hasPreviousPage = m_currentPage > 0; - const bool hasNextPage = m_currentPage < (m_pageCount - 1); - - if (m_canGoToPreviousPage != hasPreviousPage) { - m_canGoToPreviousPage = hasPreviousPage; - emit q->canGoToPreviousPageChanged(m_canGoToPreviousPage); - } - - if (m_canGoToNextPage != hasNextPage) { - m_canGoToNextPage = hasNextPage; - emit q->canGoToNextPageChanged(m_canGoToNextPage); - } - } - - void documentStatusChanged() - { - update(); - } - - Q_DECLARE_PUBLIC(QPdfPageNavigation) - - 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(*new QPdfPageNavigationPrivate, parent) -{ -} - -/*! - 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 -{ - Q_D(const QPdfPageNavigation); - - return d->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) -{ - Q_D(QPdfPageNavigation); - - if (d->m_document == document) - return; - - if (d->m_document) - disconnect(d->m_documentStatusChangedConnection); - - d->m_document = document; - emit documentChanged(d->m_document); - - if (d->m_document) - d->m_documentStatusChangedConnection = connect(d->m_document.data(), &QPdfDocument::statusChanged, this, [d](){ d->documentStatusChanged(); }); - - d->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 -{ - Q_D(const QPdfPageNavigation); - - return d->m_currentPage; -} - -/*! - \fn void QPdfPageNavigation::setCurrentPage(int page) - - Sets the current \a page number. -*/ -void QPdfPageNavigation::setCurrentPage(int newPage) -{ - Q_D(QPdfPageNavigation); - - if (newPage < 0 || newPage >= d->m_pageCount) - return; - - if (d->m_currentPage == newPage) - return; - - d->m_currentPage = newPage; - emit currentPageChanged(d->m_currentPage); - - d->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 -{ - Q_D(const QPdfPageNavigation); - - return d->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 -{ - Q_D(const QPdfPageNavigation); - - return d->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 -{ - Q_D(const QPdfPageNavigation); - - return d->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() -{ - Q_D(QPdfPageNavigation); - - if (d->m_currentPage > 0) - setCurrentPage(d->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() -{ - Q_D(QPdfPageNavigation); - - if (d->m_currentPage < d->m_pageCount - 1) - setCurrentPage(d->m_currentPage + 1); -} - -QT_END_NAMESPACE - -#include "moc_qpdfpagenavigation.cpp" diff --git a/src/pdf/qpdfpagenavigator.cpp b/src/pdf/qpdfpagenavigator.cpp new file mode 100644 index 000000000..e077e2184 --- /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.size() - 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.size()) + 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.size()) + 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.size()) + return 1; + return d->pageHistory.at(d->currentHistoryIndex)->zoom; +} + +QPdfLink QPdfPageNavigator::currentLink() const +{ + if (d->currentHistoryIndex < 0 || d->currentHistoryIndex >= d->pageHistory.size()) + 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.size() - d->currentHistoryIndex - 1); + d->pageHistory.append(destination.d); + d->currentHistoryIndex = d->pageHistory.size() - 1; + } + if (zoomChange) + emit currentZoomChanged(currentZoom()); + if (pageChange) + emit currentPageChanged(currentPage()); + if (locationChange) + emit currentLocationChanged(currentLocation()); + if (d->changing) + return; + if (backAvailableWas != backAvailable()) + emit backAvailableChanged(backAvailable()); + if (forwardAvailableWas != forwardAvailable()) + 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.size() - d->currentHistoryIndex - 1); + d->pageHistory.append(QExplicitlySharedDataPointer<QPdfLinkPrivate>(new QPdfLinkPrivate(page, location, zoom))); + d->currentHistoryIndex = d->pageHistory.size() - 1; + } + if (zoomChange) + emit currentZoomChanged(currentZoom()); + if (pageChange) + emit currentPageChanged(currentPage()); + if (locationChange) + emit currentLocationChanged(currentLocation()); + if (d->changing) + return; + if (backAvailableWas != backAvailable()) + emit backAvailableChanged(backAvailable()); + if (forwardAvailableWas != forwardAvailable()) + 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.size()) + 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.size() - 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 31d9f4e1e..771fc67ef 100644 --- a/src/pdf/qpdfpagerenderer.cpp +++ b/src/pdf/qpdfpagerenderer.cpp @@ -1,44 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.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" #include <private/qobject_p.h> #include <QMutex> -#include <QPdfDocument> #include <QPointer> #include <QThread> @@ -67,10 +33,8 @@ private: QMutex m_mutex; }; -class QPdfPageRendererPrivate : public QObjectPrivate +class QPdfPageRendererPrivate { - Q_DECLARE_PUBLIC(QPdfPageRenderer) - public: QPdfPageRendererPrivate(); ~QPdfPageRendererPrivate(); @@ -90,8 +54,8 @@ public: QPdfDocumentRenderOptions options; }; - QVector<PageRequest> m_requests; - QVector<PageRequest> m_pendingRequests; + QList<PageRequest> m_requests; + QList<PageRequest> m_pendingRequests; quint64 m_requestIdCounter = 1; QThread *m_renderThread = nullptr; @@ -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); @@ -133,12 +97,7 @@ void RenderWorker::requestPage(quint64 requestId, int pageNumber, QSize imageSiz emit pageRendered(pageNumber, imageSize, image, options, requestId); } - -QPdfPageRendererPrivate::QPdfPageRendererPrivate() - : QObjectPrivate() - , m_renderWorker(new RenderWorker) -{ -} +QPdfPageRendererPrivate::QPdfPageRendererPrivate() : m_renderWorker(new RenderWorker) { } QPdfPageRendererPrivate::~QPdfPageRendererPrivate() { @@ -194,18 +153,17 @@ void QPdfPageRendererPrivate::requestFinished(int page, QSize imageSize, const Q Constructs a page renderer object with parent object \a parent. */ QPdfPageRenderer::QPdfPageRenderer(QObject *parent) - : QObject(*new QPdfPageRendererPrivate(), parent) + : QObject(parent), d_ptr(new QPdfPageRendererPrivate) { - Q_D(QPdfPageRenderer); - qRegisterMetaType<QPdfDocumentRenderOptions>(); - connect(d->m_renderWorker.data(), &RenderWorker::pageRendered, this, - [this,d](int page, QSize imageSize, const QImage &image, QPdfDocumentRenderOptions options, quint64 requestId) { - d->requestFinished(page, imageSize, image, options, requestId); + connect(d_ptr->m_renderWorker.data(), &RenderWorker::pageRendered, this, + [this](int page, QSize imageSize, const QImage &image, + QPdfDocumentRenderOptions options, quint64 requestId) { + d_ptr->requestFinished(page, imageSize, image, options, requestId); emit pageRendered(page, imageSize, image, options, requestId); - d->handleNextRequest(); - }); + d_ptr->handleNextRequest(); + }); } /*! @@ -242,9 +200,7 @@ QPdfPageRenderer::~QPdfPageRenderer() */ QPdfPageRenderer::RenderMode QPdfPageRenderer::renderMode() const { - Q_D(const QPdfPageRenderer); - - return d->m_renderMode; + return d_ptr->m_renderMode; } /*! @@ -254,26 +210,24 @@ QPdfPageRenderer::RenderMode QPdfPageRenderer::renderMode() const */ void QPdfPageRenderer::setRenderMode(RenderMode mode) { - Q_D(QPdfPageRenderer); - - if (d->m_renderMode == mode) + if (d_ptr->m_renderMode == mode) return; - d->m_renderMode = mode; - emit renderModeChanged(d->m_renderMode); + d_ptr->m_renderMode = mode; + emit renderModeChanged(d_ptr->m_renderMode); - if (d->m_renderMode == RenderMode::MultiThreaded) { - d->m_renderThread = new QThread; - d->m_renderWorker->moveToThread(d->m_renderThread); - d->m_renderThread->start(); + if (d_ptr->m_renderMode == RenderMode::MultiThreaded) { + d_ptr->m_renderThread = new QThread; + d_ptr->m_renderWorker->moveToThread(d_ptr->m_renderThread); + d_ptr->m_renderThread->start(); } else { - d->m_renderThread->quit(); - d->m_renderThread->wait(); - delete d->m_renderThread; - d->m_renderThread = nullptr; + d_ptr->m_renderThread->quit(); + d_ptr->m_renderThread->wait(); + delete d_ptr->m_renderThread; + d_ptr->m_renderThread = nullptr; // pulling the object from another thread should be fine, once that thread is deleted - d->m_renderWorker->moveToThread(this->thread()); + d_ptr->m_renderWorker->moveToThread(this->thread()); } } @@ -294,9 +248,7 @@ void QPdfPageRenderer::setRenderMode(RenderMode mode) */ QPdfDocument* QPdfPageRenderer::document() const { - Q_D(const QPdfPageRenderer); - - return d->m_document; + return d_ptr->m_document; } /*! @@ -306,15 +258,13 @@ QPdfDocument* QPdfPageRenderer::document() const */ void QPdfPageRenderer::setDocument(QPdfDocument *document) { - Q_D(QPdfPageRenderer); - - if (d->m_document == document) + if (d_ptr->m_document == document) return; - d->m_document = document; - emit documentChanged(d->m_document); + d_ptr->m_document = document; + emit documentChanged(d_ptr->m_document); - d->m_renderWorker->setDocument(d->m_document); + d_ptr->m_renderWorker->setDocument(d_ptr->m_document); } /*! @@ -329,19 +279,17 @@ void QPdfPageRenderer::setDocument(QPdfDocument *document) quint64 QPdfPageRenderer::requestPage(int pageNumber, QSize imageSize, QPdfDocumentRenderOptions options) { - Q_D(QPdfPageRenderer); - - if (!d->m_document || d->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->m_pendingRequests)) { + for (const auto &request : std::as_const(d_ptr->m_pendingRequests)) { if (request.pageNumber == pageNumber && request.imageSize == imageSize && request.options == options) return request.id; } - const auto id = d->m_requestIdCounter++; + const auto id = d_ptr->m_requestIdCounter++; QPdfPageRendererPrivate::PageRequest request; request.id = id; @@ -349,9 +297,9 @@ quint64 QPdfPageRenderer::requestPage(int pageNumber, QSize imageSize, request.imageSize = imageSize; request.options = options; - d->m_requests.append(request); + d_ptr->m_requests.append(request); - d->handleNextRequest(); + d_ptr->handleNextRequest(); return id; } @@ -359,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 new file mode 100644 index 000000000..cb9be06fe --- /dev/null +++ b/src/pdf/qpdfpagerenderer.h @@ -0,0 +1,60 @@ +// 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 + +#include <QtPdf/qtpdfglobal.h> + +#include <QtCore/qobject.h> +#include <QtCore/qsize.h> +#include <QtPdf/qpdfdocument.h> +#include <QtPdf/qpdfdocumentrenderoptions.h> + +QT_BEGIN_NAMESPACE + +class QPdfPageRendererPrivate; + +class Q_PDF_EXPORT QPdfPageRenderer : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged) + Q_PROPERTY(RenderMode renderMode READ renderMode WRITE setRenderMode NOTIFY renderModeChanged) + +public: + enum class RenderMode + { + MultiThreaded, + SingleThreaded + }; + Q_ENUM(RenderMode) + + QPdfPageRenderer() : QPdfPageRenderer(nullptr) {} + explicit QPdfPageRenderer(QObject *parent); + ~QPdfPageRenderer() override; + + RenderMode renderMode() const; + void setRenderMode(RenderMode mode); + + QPdfDocument* document() const; + void setDocument(QPdfDocument *document); + + quint64 requestPage(int pageNumber, QSize imageSize, + QPdfDocumentRenderOptions options = QPdfDocumentRenderOptions()); + +Q_SIGNALS: + void documentChanged(QPdfDocument *document); + void renderModeChanged(QPdfPageRenderer::RenderMode renderMode); + + void pageRendered(int pageNumber, QSize imageSize, const QImage &image, + QPdfDocumentRenderOptions options, quint64 requestId); + +private: + QScopedPointer<QPdfPageRendererPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/pdf/qpdfsearchmodel.cpp b/src/pdf/qpdfsearchmodel.cpp index 27b7833fc..a81ae77dc 100644 --- a/src/pdf/qpdfsearchmodel.cpp +++ b/src/pdf/qpdfsearchmodel.cpp @@ -1,47 +1,13 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.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 "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" +#include "third_party/pdfium/public/fpdfview.h" #include <QtCore/qelapsedtimer.h> #include <QtCore/qloggingcategory.h> @@ -53,35 +19,85 @@ Q_LOGGING_CATEGORY(qLcS, "qt.pdf.search") 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; roleName[0] = QChar::toLower(roleName[0]); m_roleNames.insert(r, roleName); } + connect(this, &QAbstractListModel::dataChanged, this, &QPdfSearchModel::countChanged); + connect(this, &QAbstractListModel::modelReset, this, &QPdfSearchModel::countChanged); + connect(this, &QAbstractListModel::rowsRemoved, this, &QPdfSearchModel::countChanged); + connect(this, &QAbstractListModel::rowsInserted, this, &QPdfSearchModel::countChanged); } +/*! + 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); - Q_UNUSED(parent) + Q_UNUSED(parent); return d->rowCountSoFar; } +/*! + \reimp +*/ QVariant QPdfSearchModel::data(const QModelIndex &index, int role) const { Q_D(const QPdfSearchModel); @@ -99,7 +115,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) { @@ -111,19 +127,33 @@ QVariant QPdfSearchModel::data(const QModelIndex &index, int role) const return QVariant(); } +/*! + \since 6.8 + \property QPdfSearchModel::count + \brief the number of search results found +*/ +int QPdfSearchModel::count() const +{ + return rowCount(QModelIndex()); +} + void QPdfSearchModel::updatePage(int page) { Q_D(QPdfSearchModel); d->doSearch(page); } +/*! + \property QPdfSearchModel::searchString + \brief the string to search for +*/ QString QPdfSearchModel::searchString() const { Q_D(const QPdfSearchModel); return d->searchString; } -void QPdfSearchModel::setSearchString(QString searchString) +void QPdfSearchModel::setSearchString(const QString &searchString) { Q_D(QPdfSearchModel); if (d->searchString == searchString) @@ -136,24 +166,35 @@ void QPdfSearchModel::setSearchString(QString searchString) endResetModel(); } -QVector<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); - if (d->searchResults.count() <= page) + if (d->searchResults.size() <= page) return {}; 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(); + if (pi.page < 0 || index < 0) + return {}; return d->searchResults[pi.page][pi.index]; } +/*! + \property QPdfSearchModel::document + \brief the document to search +*/ QPdfDocument *QPdfSearchModel::document() const { Q_D(const QPdfSearchModel); @@ -166,6 +207,10 @@ void QPdfSearchModel::setDocument(QPdfDocument *document) if (d->document == document) return; + disconnect(d->documentConnection); + d->documentConnection = connect(document, &QPdfDocument::pageCountChanged, this, + [this]() { d_func()->clearResults(); }); + d->document = document; d->clearResults(); emit documentChanged(); @@ -178,7 +223,7 @@ void QPdfSearchModel::timerEvent(QTimerEvent *event) return; if (!d->document || d->nextPageToUpdate >= d->document->pageCount()) { if (d->document) - qCDebug(qLcS, "done updating search results on %d pages", d->searchResults.count()); + qCDebug(qLcS) << "done updating search results on" << d->searchResults.size() << "pages"; killTimer(d->updateTimerId); d->updateTimerId = -1; } @@ -198,9 +243,6 @@ void QPdfSearchModelPrivate::clearResults() if (document) { searchResults.resize(document->pageCount()); pagesSearched.resize(document->pageCount()); - } else { - searchResults.resize(0); - pagesSearched.resize(0); } nextPageToUpdate = 0; updateTimerId = q->startTimer(UpdateTimerInterval); @@ -208,7 +250,7 @@ void QPdfSearchModelPrivate::clearResults() bool QPdfSearchModelPrivate::doSearch(int page) { - if (page < 0 || page >= pagesSearched.count() || searchString.isEmpty()) + if (page < 0 || page >= pagesSearched.size() || searchString.isEmpty()) return false; if (pagesSearched[page]) return true; @@ -222,7 +264,6 @@ bool QPdfSearchModelPrivate::doSearch(int page) qWarning() << "failed to load page" << page; return false; } - double pageHeight = FPDF_GetPageHeight(pdfPage); FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage); if (!textPage) { qWarning() << "failed to load text of page" << page; @@ -230,18 +271,22 @@ bool QPdfSearchModelPrivate::doSearch(int page) return false; } FPDF_SCHHANDLE sh = FPDFText_FindStart(textPage, searchString.utf16(), 0, 0); - QVector<QPdfSearchResult> newSearchResults; + QList<QPdfLink> newSearchResults; + constexpr double CharacterHitTolerance = 6.0; while (FPDFText_FindNext(sh)) { int idx = FPDFText_GetSchResultIndex(sh); int count = FPDFText_GetSchCount(sh); int rectCount = FPDFText_CountRects(textPage, idx, count); - QVector<QRectF> rects; + QList<QRectF> rects; int startIndex = -1; int endIndex = -1; for (int r = 0; r < rectCount; ++r) { + // get bounding box of search result in page coordinates double left, top, right, bottom; FPDFText_GetRect(textPage, r, &left, &top, &right, &bottom); - rects << QRectF(left, pageHeight - top, right - left, top - bottom); + // deal with any internal PDF transforms and + // convert to the 1x (pixels = points) 4th-quadrant coordinate system + rects << document->d->mapPageToView(pdfPage, left, top, right, bottom); if (r == 0) { startIndex = FPDFText_GetCharIndexAtPos(textPage, left, top, CharacterHitTolerance, CharacterHitTolerance); @@ -250,7 +295,8 @@ bool QPdfSearchModelPrivate::doSearch(int page) endIndex = FPDFText_GetCharIndexAtPos(textPage, right, top, CharacterHitTolerance, CharacterHitTolerance); } - qCDebug(qLcS) << rects.last() << "char idx" << startIndex << "->" << endIndex; + qCDebug(qLcS) << rects.last() << "char idx" << startIndex << "->" << endIndex + << "from page rect" << left << top << right << bottom; } QString contextBefore, contextAfter; if (startIndex >= 0 || endIndex >= 0) { @@ -258,10 +304,11 @@ bool QPdfSearchModelPrivate::doSearch(int page) endIndex += ContextChars; int count = endIndex - startIndex + 1; if (count > 0) { - QVector<ushort> buf(count + 1); + QList<ushort> buf(count + 1); int len = FPDFText_GetText(textPage, startIndex, count, buf.data()); Q_ASSERT(len - 1 <= count); // len is number of characters written, including the terminator - QString context = QString::fromUtf16(buf.constData(), len - 1); + QString context = QString::fromUtf16( + reinterpret_cast<const char16_t *>(buf.constData()), len - 1); context = context.replace(QLatin1Char('\n'), QStringLiteral("\u23CE")); context = context.remove(QLatin1Char('\r')); // try to find the search string near the middle of the context if possible @@ -271,25 +318,25 @@ bool QPdfSearchModelPrivate::doSearch(int page) if (si < 0) qWarning() << "search string" << searchString << "not found in context" << context; contextBefore = context.mid(0, si); - contextAfter = context.mid(si + searchString.length()); + contextAfter = context.mid(si + searchString.size()); } } if (!rects.isEmpty()) - newSearchResults << QPdfSearchResult(page, rects, contextBefore, contextAfter); + newSearchResults << QPdfLink(page, rects, contextBefore, contextAfter); } FPDFText_FindClose(sh); FPDFText_ClosePage(textPage); FPDF_ClosePage(pdfPage); qCDebug(qLcS) << searchString << "took" << timer.elapsed() << "ms to find" - << newSearchResults.count() << "results on page" << page; + << newSearchResults.size() << "results on page" << page; pagesSearched[page] = true; searchResults[page] = newSearchResults; - if (newSearchResults.count() > 0) { + if (newSearchResults.size() > 0) { int rowsBefore = rowsBeforePage(page); - qCDebug(qLcS) << "from row" << rowsBefore << "rowCount" << rowCountSoFar << "increasing by" << newSearchResults.count(); - rowCountSoFar += newSearchResults.count(); - q->beginInsertRows(QModelIndex(), rowsBefore, rowsBefore + newSearchResults.count() - 1); + qCDebug(qLcS) << "from row" << rowsBefore << "rowCount" << rowCountSoFar << "increasing by" << newSearchResults.size(); + rowCountSoFar += newSearchResults.size(); + q->beginInsertRows(QModelIndex(), rowsBefore, rowsBefore + newSearchResults.size() - 1); q->endInsertRows(); } return true; @@ -297,13 +344,15 @@ 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; for (int page = 0; page < pageCount; ++page) { if (!pagesSearched[page]) doSearch(page); - totalSoFar += searchResults[page].count(); + totalSoFar += searchResults[page].size(); if (totalSoFar > resultIndex) return {page, resultIndex - previousTotalSoFar}; previousTotalSoFar = totalSoFar; @@ -315,7 +364,7 @@ int QPdfSearchModelPrivate::rowsBeforePage(int page) { int ret = 0; for (int i = 0; i < page; ++i) - ret += searchResults[i].count(); + ret += searchResults[i].size(); return ret; } diff --git a/src/pdf/qpdfsearchmodel.h b/src/pdf/qpdfsearchmodel.h new file mode 100644 index 000000000..04f8b9140 --- /dev/null +++ b/src/pdf/qpdfsearchmodel.h @@ -0,0 +1,70 @@ +// 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 + +#include <QtPdf/qtpdfglobal.h> + +#include <QtCore/qabstractitemmodel.h> +#include <QtPdf/qpdfdocument.h> +#include <QtPdf/qpdflink.h> + +QT_BEGIN_NAMESPACE + +class QPdfSearchModelPrivate; + +class Q_PDF_EXPORT QPdfSearchModel : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(QPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged) + Q_PROPERTY(QString searchString READ searchString WRITE setSearchString NOTIFY searchStringChanged) + Q_PROPERTY(int count READ count NOTIFY countChanged REVISION(6, 8) FINAL) + +public: + enum class Role : int { + Page = Qt::UserRole, + IndexOnPage, + Location, + ContextBefore, + ContextAfter, + NRoles + }; + Q_ENUM(Role) + QPdfSearchModel() : QPdfSearchModel(nullptr) {} + explicit QPdfSearchModel(QObject *parent); + ~QPdfSearchModel() override; + + QList<QPdfLink> resultsOnPage(int page) const; + QPdfLink resultAtIndex(int index) const; + + QPdfDocument *document() const; + QString searchString() const; + + QHash<int, QByteArray> roleNames() const override; + int rowCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role) const override; + + int count() const; + +public Q_SLOTS: + void setSearchString(const QString &searchString); + void setDocument(QPdfDocument *document); + +Q_SIGNALS: + void documentChanged(); + void searchStringChanged(); + Q_REVISION(6, 8) void countChanged(); + +protected: + void updatePage(int page); + void timerEvent(QTimerEvent *event) override; + +private: + QHash<int, QByteArray> m_roleNames; + Q_DECLARE_PRIVATE(QPdfSearchModel) +}; + +QT_END_NAMESPACE + +#endif // QPDFSEARCHMODEL_H diff --git a/src/pdf/qpdfsearchmodel_p.h b/src/pdf/qpdfsearchmodel_p.h new file mode 100644 index 000000000..5ffa08f5d --- /dev/null +++ b/src/pdf/qpdfsearchmodel_p.h @@ -0,0 +1,54 @@ +// 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 + +// +// 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 "qpdfsearchmodel.h" +#include <private/qabstractitemmodel_p.h> + +#include "third_party/pdfium/public/fpdfview.h" + +QT_BEGIN_NAMESPACE + +class QPdfSearchModelPrivate : public QAbstractItemModelPrivate +{ + Q_DECLARE_PUBLIC(QPdfSearchModel) + +public: + QPdfSearchModelPrivate(); + void clearResults(); + bool doSearch(int page); + + struct PageAndIndex { + int page; + int index; + }; + PageAndIndex pageAndIndexForResult(int resultIndex); + int rowsBeforePage(int page); + + QPdfDocument *document = nullptr; + QString searchString; + QList<bool> pagesSearched; + QList<QList<QPdfLink>> searchResults; + int rowCountSoFar = 0; + int updateTimerId = -1; + int nextPageToUpdate = 0; + + QMetaObject::Connection documentConnection; +}; + +QT_END_NAMESPACE + +#endif // QPDFSEARCHMODEL_P_H diff --git a/src/pdf/qpdfsearchresult.cpp b/src/pdf/qpdfsearchresult.cpp deleted file mode 100644 index 53da1c165..000000000 --- a/src/pdf/qpdfsearchresult.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qpdfsearchresult.h" -#include "qpdfsearchresult_p.h" - -QT_BEGIN_NAMESPACE - -QPdfSearchResult::QPdfSearchResult() : - QPdfSearchResult(new QPdfSearchResultPrivate()) { } - -QPdfSearchResult::QPdfSearchResult(int page, QVector<QRectF> rects, QString contextBefore, QString contextAfter) : - QPdfSearchResult(new QPdfSearchResultPrivate(page, rects, contextBefore, contextAfter)) { } - -QPdfSearchResult::QPdfSearchResult(QPdfSearchResultPrivate *d) : - QPdfDestination(static_cast<QPdfDestinationPrivate *>(d)) { } - -QString QPdfSearchResult::contextBefore() const -{ - return static_cast<QPdfSearchResultPrivate *>(d.data())->contextBefore; -} - -QString QPdfSearchResult::contextAfter() const -{ - return static_cast<QPdfSearchResultPrivate *>(d.data())->contextAfter; -} - -QVector<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/qpdfselection.cpp b/src/pdf/qpdfselection.cpp index 5f0ee3b20..df30eb353 100644 --- a/src/pdf/qpdfselection.cpp +++ b/src/pdf/qpdfselection.cpp @@ -1,38 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.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" @@ -67,7 +34,7 @@ QPdfSelection::QPdfSelection() \a text string, and which take up space on the page within the polygon regions given in \a bounds. */ -QPdfSelection::QPdfSelection(const QString &text, QVector<QPolygonF> bounds, QRectF boundingRect, int startIndex, int endIndex) +QPdfSelection::QPdfSelection(const QString &text, QList<QPolygonF> bounds, QRectF boundingRect, int startIndex, int endIndex) : d(new QPdfSelectionPrivate(text, bounds, boundingRect, startIndex, endIndex)) { } @@ -77,25 +44,10 @@ QPdfSelection::QPdfSelection(QPdfSelectionPrivate *d) { } -QPdfSelection::QPdfSelection(const QPdfSelection &other) - : d(other.d) -{ -} - -QPdfSelection::QPdfSelection(QPdfSelection &&other) noexcept - : d(std::move(other.d)) -{ -} - -QPdfSelection::~QPdfSelection() -{ -} - -QPdfSelection &QPdfSelection::operator=(const QPdfSelection &other) -{ - d = other.d; - return *this; -} +QPdfSelection::~QPdfSelection() = default; +QPdfSelection::QPdfSelection(const QPdfSelection &other) = default; +QPdfSelection::QPdfSelection(QPdfSelection &&other) noexcept = default; +QPdfSelection &QPdfSelection::operator=(const QPdfSelection &other) = default; /*! \property QPdfSelection::valid @@ -119,7 +71,7 @@ bool QPdfSelection::isValid() const are always rectangles; but in the future it may be possible to represent more complex regions. */ -QVector<QPolygonF> QPdfSelection::bounds() const +QList<QPolygonF> QPdfSelection::bounds() const { return d->bounds; } @@ -135,7 +87,7 @@ QString QPdfSelection::text() const } /*! - \property rect QPdfSelection::boundingRectangle + \property QPdfSelection::boundingRectangle This property holds the overall bounding rectangle (convex hull) around \l bounds. */ @@ -145,7 +97,7 @@ QRectF QPdfSelection::boundingRectangle() const } /*! - \property int QPdfSelection::startIndex + \property QPdfSelection::startIndex This property holds the index at the beginning of \l text within the full text on the page. */ @@ -155,7 +107,7 @@ int QPdfSelection::startIndex() const } /*! - \property int QPdfSelection::endIndex + \property QPdfSelection::endIndex This property holds the index at the end of \l text within the full text on the page. */ @@ -166,7 +118,8 @@ int QPdfSelection::endIndex() const #if QT_CONFIG(clipboard) /*! - Copies \l text to the \l {QGuiApplication::clipboard()}{system clipboard}. + Copies \l text to the \l {QGuiApplication::clipboard()}{system clipboard} + depending on the \a mode selected. */ void QPdfSelection::copyToClipboard(QClipboard::Mode mode) const { diff --git a/src/pdf/qpdfselection.h b/src/pdf/qpdfselection.h new file mode 100644 index 000000000..8fcfaf2d8 --- /dev/null +++ b/src/pdf/qpdfselection.h @@ -0,0 +1,62 @@ +// 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 + +#include <QtPdf/qtpdfglobal.h> + +#include <QtCore/qobject.h> +#include <QtCore/qshareddata.h> +#include <QtGui/qclipboard.h> +#include <QtGui/qpolygon.h> + +QT_BEGIN_NAMESPACE + +class QPdfSelectionPrivate; + +class QPdfSelection +{ + Q_GADGET_EXPORT(Q_PDF_EXPORT) + Q_PROPERTY(bool valid READ isValid) + Q_PROPERTY(QList<QPolygonF> bounds READ bounds) + Q_PROPERTY(QRectF boundingRectangle READ boundingRectangle) + Q_PROPERTY(QString text READ text) + Q_PROPERTY(int startIndex READ startIndex) + Q_PROPERTY(int endIndex READ endIndex) + +public: + Q_PDF_EXPORT ~QPdfSelection(); + Q_PDF_EXPORT QPdfSelection(const QPdfSelection &other); + Q_PDF_EXPORT QPdfSelection &operator=(const QPdfSelection &other); + + Q_PDF_EXPORT QPdfSelection(QPdfSelection &&other) noexcept; + QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QPdfSelection) + + void swap(QPdfSelection &other) noexcept { d.swap(other.d); } + + Q_PDF_EXPORT bool isValid() const; + Q_PDF_EXPORT QList<QPolygonF> bounds() const; + Q_PDF_EXPORT QString text() const; + Q_PDF_EXPORT QRectF boundingRectangle() const; + Q_PDF_EXPORT int startIndex() const; + Q_PDF_EXPORT int endIndex() const; +#if QT_CONFIG(clipboard) + Q_PDF_EXPORT void copyToClipboard(QClipboard::Mode mode = QClipboard::Clipboard) const; +#endif + +private: + QPdfSelection(); + QPdfSelection(const QString &text, QList<QPolygonF> bounds, QRectF boundingRect, int startIndex, int endIndex); + QPdfSelection(QPdfSelectionPrivate *d); + friend class QPdfDocument; + friend class QQuickPdfSelection; + +private: + QExplicitlySharedDataPointer<QPdfSelectionPrivate> d; +}; +Q_DECLARE_SHARED(QPdfSelection) + +QT_END_NAMESPACE + +#endif // QPDFSELECTION_H diff --git a/src/pdf/qpdfselection_p.h b/src/pdf/qpdfselection_p.h new file mode 100644 index 000000000..541480746 --- /dev/null +++ b/src/pdf/qpdfselection_p.h @@ -0,0 +1,45 @@ +// 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 + +// +// 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 "qpdfselection.h" + +#include <QList> +#include <QPolygonF> + +QT_BEGIN_NAMESPACE + +class QPdfSelectionPrivate : public QSharedData +{ +public: + QPdfSelectionPrivate() = default; + QPdfSelectionPrivate(const QString &text, QList<QPolygonF> bounds, QRectF boundingRect, int startIndex, int endIndex) + : text(text), + bounds(bounds), + boundingRect(boundingRect), + startIndex(startIndex), + endIndex(endIndex) { } + + QString text; + QList<QPolygonF> bounds; + QRectF boundingRect; + int startIndex; + int endIndex; +}; + +QT_END_NAMESPACE + +#endif // QPDFSELECTION_P_H diff --git a/src/pdf/qtpdf.gni b/src/pdf/qtpdf.gni deleted file mode 100644 index c31f3e9a0..000000000 --- a/src/pdf/qtpdf.gni +++ /dev/null @@ -1,7 +0,0 @@ -include_dirs = [ -] - -deps = [ - "//third_party/pdfium" -] - diff --git a/src/pdf/qtpdfglobal.h b/src/pdf/qtpdfglobal.h new file mode 100644 index 000000000..2d0900029 --- /dev/null +++ b/src/pdf/qtpdfglobal.h @@ -0,0 +1,11 @@ +// 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 + +#include <QtCore/qglobal.h> +#include <QtPdf/qtpdfexports.h> + +#endif // QTPDFGLOBAL_H + diff --git a/src/pdf/quick/plugin.cpp b/src/pdf/quick/plugin.cpp deleted file mode 100644 index b082fcb4a..000000000 --- a/src/pdf/quick/plugin.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtQml/qqml.h> -#include <QtQml/qqmlcomponent.h> -#include <QtQml/qqmlengine.h> -#include <QtQml/qqmlextensionplugin.h> -#include "qquickpdfdocument_p.h" -#include "qquickpdflinkmodel_p.h" -#include "qquickpdfnavigationstack_p.h" -#include "qquickpdfsearchmodel_p.h" -#include "qquickpdfselection_p.h" -#include "qquicktableviewextra_p.h" - -QT_BEGIN_NAMESPACE - -/*! - \qmlmodule QtQuick.Pdf 5.15 - \title Qt Quick PDF QML Types - \ingroup qmlmodules - \brief Provides QML types for handling PDF documents. - - This QML module contains types for handling PDF documents. - - To use the types in this module, import the module with the following line: - - \code - import QtQuick.Pdf 5.15 - \endcode -*/ - -class QtQuick2PdfPlugin : public QQmlExtensionPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) - -public: - QtQuick2PdfPlugin() : QQmlExtensionPlugin() { } - - void initializeEngine(QQmlEngine *engine, const char *uri) override { - Q_UNUSED(uri); -#ifdef QT_STATIC - Q_UNUSED(engine); -#else - engine->addImportPath(QStringLiteral("qrc:/")); -#endif - } - - void registerTypes(const char *uri) override { - Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Pdf")); - - // Register the latest version, even if there are no new types or new revisions for existing types yet. - qmlRegisterModule(uri, 2, QT_VERSION_MINOR); - - qmlRegisterType<QQuickPdfDocument>(uri, 5, 15, "PdfDocument"); - qmlRegisterType<QQuickPdfLinkModel>(uri, 5, 15, "PdfLinkModel"); - qmlRegisterType<QQuickPdfNavigationStack>(uri, 5, 15, "PdfNavigationStack"); - qmlRegisterType<QQuickPdfSearchModel>(uri, 5, 15, "PdfSearchModel"); - qmlRegisterType<QQuickPdfSelection>(uri, 5, 15, "PdfSelection"); - qmlRegisterType<QQuickTableViewExtra>(uri, 5, 15, "TableViewExtra"); - - qmlRegisterType(QUrl("qrc:/qt-project.org/qtpdf/qml/PdfPageView.qml"), uri, 5, 15, "PdfPageView"); - qmlRegisterType(QUrl("qrc:/qt-project.org/qtpdf/qml/PdfMultiPageView.qml"), uri, 5, 15, "PdfMultiPageView"); - qmlRegisterType(QUrl("qrc:/qt-project.org/qtpdf/qml/PdfScrollablePageView.qml"), uri, 5, 15, "PdfScrollablePageView"); - } -}; - -QT_END_NAMESPACE - -#include "plugin.moc" diff --git a/src/pdf/quick/plugins.qmltypes b/src/pdf/quick/plugins.qmltypes deleted file mode 100644 index a30361d33..000000000 --- a/src/pdf/quick/plugins.qmltypes +++ /dev/null @@ -1,52 +0,0 @@ -import QtQuick.tooling 1.2 - -// This file describes the plugin-supplied types contained in the library. -// It is used for QML tooling purposes only. -// -// This file was auto-generated by: -// 'qmlplugindump -nonrelocatable QtQuick.Pdf 5.14' - -Module { - dependencies: [ - "QtGraphicalEffects 1.12", - "QtQuick 2.14", - "QtQuick.Controls 2.14", - "QtQuick.Controls.Fusion 2.14", - "QtQuick.Controls.Fusion.impl 2.14", - "QtQuick.Controls.Imagine 2.14", - "QtQuick.Controls.Imagine.impl 2.14", - "QtQuick.Controls.Material 2.14", - "QtQuick.Controls.Material.impl 2.14", - "QtQuick.Controls.Universal 2.14", - "QtQuick.Controls.Universal.impl 2.12", - "QtQuick.Controls.impl 2.14", - "QtQuick.Shapes 1.14", - "QtQuick.Templates 2.14", - "QtQuick.Window 2.2" - ] - Component { - name: "QQuickPdfDocument" - prototype: "QObject" - exports: ["QtQuick.Pdf/PdfDocument 5.14"] - exportMetaObjectRevisions: [0] - Property { name: "source"; type: "QUrl" } - Property { name: "pageCount"; type: "int"; isReadonly: true } - Property { name: "password"; type: "string" } - Property { name: "status"; type: "QPdfDocument::Status"; isReadonly: true } - Property { name: "title"; type: "string"; isReadonly: true } - Property { name: "subject"; type: "string"; isReadonly: true } - Property { name: "author"; type: "string"; isReadonly: true } - Property { name: "keywords"; type: "string"; isReadonly: true } - Property { name: "producer"; type: "string"; isReadonly: true } - Property { name: "creator"; type: "string"; isReadonly: true } - Property { name: "creationDate"; type: "QDateTime"; isReadonly: true } - Property { name: "modificationDate"; type: "QDateTime"; isReadonly: true } - Signal { name: "passwordRequired" } - Signal { name: "metaDataLoaded" } - Method { - name: "pagePointSize" - type: "QSizeF" - Parameter { name: "page"; type: "int" } - } - } -} diff --git a/src/pdf/quick/qml/+material/PdfStyle.qml b/src/pdf/quick/qml/+material/PdfStyle.qml deleted file mode 100644 index 12df30466..000000000 --- a/src/pdf/quick/qml/+material/PdfStyle.qml +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -import QtQml 2.14 -import QtQuick.Controls 2.14 -import QtQuick.Controls.Material 2.14 -import QtQuick.Shapes 1.14 - -QtObject { - property Control prototypeControl: Control { } - function withAlpha(color, alpha) { - return Qt.hsla(color.hslHue, color.hslSaturation, color.hslLightness, alpha) - } - property color selectionColor: withAlpha(prototypeControl.palette.highlight, 0.5) - property color pageSearchResultsColor: withAlpha(Qt.lighter(Material.accentColor, 1.5), 0.5) - property color currentSearchResultStrokeColor: Material.accentColor - property real currentSearchResultStrokeWidth: 2 - property color linkUnderscoreColor: prototypeControl.palette.link - property real linkUnderscoreStrokeWidth: 1 - property var linkUnderscoreStrokeStyle: ShapePath.DashLine - property var linkUnderscoreDashPattern: [ 1, 4 ] -} diff --git a/src/pdf/quick/qml/+universal/PdfStyle.qml b/src/pdf/quick/qml/+universal/PdfStyle.qml deleted file mode 100644 index e92f2a080..000000000 --- a/src/pdf/quick/qml/+universal/PdfStyle.qml +++ /dev/null @@ -1,55 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -import QtQml 2.14 -import QtQuick 2.14 -import QtQuick.Controls 2.14 -import QtQuick.Controls.Universal 2.14 -import QtQuick.Shapes 1.14 - -QtObject { - property Control prototypeControl: Control { } - function withAlpha(color, alpha) { - return Qt.hsla(color.hslHue, color.hslSaturation, color.hslLightness, alpha) - } - property color selectionColor: withAlpha(prototypeControl.palette.highlight, 0.5) - property color pageSearchResultsColor: withAlpha(Qt.lighter(Universal.accent, 1.5), 0.5) - property color currentSearchResultStrokeColor: Universal.accent - property real currentSearchResultStrokeWidth: 2 - property color linkUnderscoreColor: prototypeControl.palette.link - property real linkUnderscoreStrokeWidth: 1 - property var linkUnderscoreStrokeStyle: ShapePath.DashLine - property var linkUnderscoreDashPattern: [ 1, 4 ] -} diff --git a/src/pdf/quick/qml/PdfMultiPageView.qml b/src/pdf/quick/qml/PdfMultiPageView.qml deleted file mode 100644 index 71485c214..000000000 --- a/src/pdf/quick/qml/PdfMultiPageView.qml +++ /dev/null @@ -1,434 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -import QtQuick 2.14 -import QtQuick.Controls 2.14 -import QtQuick.Layouts 1.14 -import QtQuick.Pdf 5.15 -import QtQuick.Shapes 1.14 -import QtQuick.Window 2.14 - -Item { - // public API - // TODO 5.15: required property - property var document: undefined - property bool debug: false - - property string selectedText - function selectAll() { - var currentItem = tableHelper.itemAtCell(tableHelper.cellAtPos(root.width / 2, root.height / 2)) - if (currentItem) - currentItem.selection.selectAll() - } - function copySelectionToClipboard() { - var currentItem = tableHelper.itemAtCell(tableHelper.cellAtPos(root.width / 2, root.height / 2)) - if (debug) - console.log("currentItem", currentItem, "sel", currentItem.selection.text) - if (currentItem) - currentItem.selection.copyToClipboard() - } - - // page navigation - property alias currentPage: navigationStack.currentPage - property alias backEnabled: navigationStack.backAvailable - property alias forwardEnabled: navigationStack.forwardAvailable - function back() { navigationStack.back() } - function forward() { navigationStack.forward() } - function goToPage(page) { - if (page === navigationStack.currentPage) - return - goToLocation(page, Qt.point(-1, -1), 0) - } - function goToLocation(page, location, zoom) { - if (zoom > 0) { - navigationStack.jumping = true // don't call navigationStack.update() because we will push() instead - root.renderScale = zoom - tableView.forceLayout() // but do ensure that the table layout is correct before we try to jump - navigationStack.jumping = false - } - navigationStack.push(page, location, zoom) // actually jump - } - property vector2d jumpLocationMargin: Qt.vector2d(10, 10) // px from top-left corner - property int currentPageRenderingStatus: Image.Null - - // page scaling - property real renderScale: 1 - property real pageRotation: 0 - function resetScale() { root.renderScale = 1 } - function scaleToWidth(width, height) { - root.renderScale = width / (tableView.rot90 ? tableView.firstPagePointSize.height : tableView.firstPagePointSize.width) - } - function scaleToPage(width, height) { - var windowAspect = width / height - var pageAspect = tableView.firstPagePointSize.width / tableView.firstPagePointSize.height - if (tableView.rot90) { - if (windowAspect > pageAspect) { - root.renderScale = height / tableView.firstPagePointSize.width - } else { - root.renderScale = width / tableView.firstPagePointSize.height - } - } else { - if (windowAspect > pageAspect) { - root.renderScale = height / tableView.firstPagePointSize.height - } else { - root.renderScale = width / tableView.firstPagePointSize.width - } - } - } - - // text search - property alias searchModel: searchModel - property alias searchString: searchModel.searchString - function searchBack() { --searchModel.currentResult } - function searchForward() { ++searchModel.currentResult } - - id: root - PdfStyle { id: style } - TableView { - id: tableView - anchors.fill: parent - anchors.leftMargin: 2 - model: modelInUse && root.document !== undefined ? root.document.pageCount : 0 - // workaround to make TableView do scheduleRebuildTable(RebuildOption::All) in cases when forceLayout() doesn't - property bool modelInUse: true - function rebuild() { - modelInUse = false - modelInUse = true - } - // end workaround - rowSpacing: 6 - property real rotationNorm: Math.round((360 + (root.pageRotation % 360)) % 360) - property bool rot90: rotationNorm == 90 || rotationNorm == 270 - onRot90Changed: forceLayout() - property size firstPagePointSize: document === undefined ? Qt.size(0, 0) : document.pagePointSize(0) - property real pageHolderWidth: Math.max(root.width, document === undefined ? 0 : - (rot90 ? document.maxPageHeight : document.maxPageWidth) * root.renderScale) - contentWidth: document === undefined ? 0 : pageHolderWidth + vscroll.width + 2 - rowHeightProvider: function(row) { return (rot90 ? document.pagePointSize(row).width : document.pagePointSize(row).height) * root.renderScale } - TableViewExtra { - id: tableHelper - tableView: tableView - } - delegate: Rectangle { - id: pageHolder - color: root.debug ? "beige" : "transparent" - Text { - visible: root.debug - anchors { right: parent.right; verticalCenter: parent.verticalCenter } - rotation: -90; text: pageHolder.width.toFixed(1) + "x" + pageHolder.height.toFixed(1) + "\n" + - image.width.toFixed(1) + "x" + image.height.toFixed(1) - } - implicitWidth: tableView.pageHolderWidth - implicitHeight: tableView.rot90 ? image.width : image.height - property alias selection: selection - Rectangle { - id: paper - width: image.width - height: image.height - rotation: root.pageRotation - anchors.centerIn: pinch.active ? undefined : parent - property size pagePointSize: document.pagePointSize(index) - property real pageScale: image.paintedWidth / pagePointSize.width - Image { - id: image - source: document.source - currentFrame: index - asynchronous: true - fillMode: Image.PreserveAspectFit - width: paper.pagePointSize.width * root.renderScale - height: paper.pagePointSize.height * root.renderScale - property real renderScale: root.renderScale - property real oldRenderScale: 1 - onRenderScaleChanged: { - image.sourceSize.width = paper.pagePointSize.width * renderScale - image.sourceSize.height = 0 - paper.scale = 1 - searchHighlights.update() - } - onStatusChanged: { - if (index === navigationStack.currentPage) - root.currentPageRenderingStatus = status - } - } - Shape { - anchors.fill: parent - visible: image.status === Image.Ready - onVisibleChanged: searchHighlights.update() - ShapePath { - strokeWidth: -1 - fillColor: style.pageSearchResultsColor - scale: Qt.size(paper.pageScale, paper.pageScale) - PathMultiline { - id: searchHighlights - function update() { - // paths could be a binding, but we need to be able to "kick" it sometimes - paths = searchModel.boundingPolygonsOnPage(index) - } - } - } - Connections { - target: searchModel - // whenever the highlights on the _current_ page change, they actually need to change on _all_ pages - // (usually because the search string has changed) - function onCurrentPageBoundingPolygonsChanged() { searchHighlights.update() } - } - ShapePath { - strokeWidth: -1 - fillColor: style.selectionColor - scale: Qt.size(paper.pageScale, paper.pageScale) - PathMultiline { - paths: selection.geometry - } - } - } - Shape { - anchors.fill: parent - visible: image.status === Image.Ready && searchModel.currentPage === index - ShapePath { - strokeWidth: style.currentSearchResultStrokeWidth - strokeColor: style.currentSearchResultStrokeColor - fillColor: "transparent" - scale: Qt.size(paper.pageScale, paper.pageScale) - PathMultiline { - paths: searchModel.currentResultBoundingPolygons - } - } - } - PinchHandler { - id: pinch - minimumScale: 0.1 - maximumScale: root.renderScale < 4 ? 2 : 1 - minimumRotation: root.pageRotation - maximumRotation: root.pageRotation - enabled: image.sourceSize.width < 5000 - onActiveChanged: - if (active) { - paper.z = 10 - } else { - paper.z = 0 - var centroidInPoints = Qt.point(pinch.centroid.position.x / root.renderScale, - pinch.centroid.position.y / root.renderScale) - var centroidInFlickable = tableView.mapFromItem(paper, pinch.centroid.position.x, pinch.centroid.position.y) - var newSourceWidth = image.sourceSize.width * paper.scale - var ratio = newSourceWidth / image.sourceSize.width - if (root.debug) - console.log("pinch ended on page", index, "with centroid", pinch.centroid.position, centroidInPoints, "wrt flickable", centroidInFlickable, - "page at", pageHolder.x.toFixed(2), pageHolder.y.toFixed(2), - "contentX/Y were", tableView.contentX.toFixed(2), tableView.contentY.toFixed(2)) - if (ratio > 1.1 || ratio < 0.9) { - var centroidOnPage = Qt.point(centroidInPoints.x * root.renderScale * ratio, centroidInPoints.y * root.renderScale * ratio) - paper.scale = 1 - paper.x = 0 - paper.y = 0 - root.renderScale *= ratio - tableView.forceLayout() - if (tableView.rotationNorm == 0) { - tableView.contentX = pageHolder.x + tableView.originX + centroidOnPage.x - centroidInFlickable.x - tableView.contentY = pageHolder.y + tableView.originY + centroidOnPage.y - centroidInFlickable.y - } else if (tableView.rotationNorm == 90) { - tableView.contentX = pageHolder.x + tableView.originX + image.height - centroidOnPage.y - centroidInFlickable.x - tableView.contentY = pageHolder.y + tableView.originY + centroidOnPage.x - centroidInFlickable.y - } else if (tableView.rotationNorm == 180) { - tableView.contentX = pageHolder.x + tableView.originX + image.width - centroidOnPage.x - centroidInFlickable.x - tableView.contentY = pageHolder.y + tableView.originY + image.height - centroidOnPage.y - centroidInFlickable.y - } else if (tableView.rotationNorm == 270) { - tableView.contentX = pageHolder.x + tableView.originX + centroidOnPage.y - centroidInFlickable.x - tableView.contentY = pageHolder.y + tableView.originY + image.width - centroidOnPage.x - centroidInFlickable.y - } - if (root.debug) - console.log("contentX/Y adjusted to", tableView.contentX.toFixed(2), tableView.contentY.toFixed(2), "y @top", pageHolder.y) - tableView.returnToBounds() - } - } - grabPermissions: PointerHandler.CanTakeOverFromAnything - } - DragHandler { - id: textSelectionDrag - acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus - target: null - } - TapHandler { - id: mouseClickHandler - acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus - } - TapHandler { - id: touchTapHandler - acceptedDevices: PointerDevice.TouchScreen - onTapped: { - selection.clear() - selection.forceActiveFocus() - } - } - Repeater { - model: PdfLinkModel { - id: linkModel - document: root.document - page: image.currentFrame - } - delegate: Shape { - x: rect.x * paper.pageScale - y: rect.y * paper.pageScale - width: rect.width * paper.pageScale - height: rect.height * paper.pageScale - visible: image.status === Image.Ready - ShapePath { - strokeWidth: style.linkUnderscoreStrokeWidth - strokeColor: style.linkUnderscoreColor - strokeStyle: style.linkUnderscoreStrokeStyle - dashPattern: style.linkUnderscoreDashPattern - startX: 0; startY: height - PathLine { x: width; y: height } - } - MouseArea { // TODO switch to TapHandler / HoverHandler in 5.15 - id: linkMA - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - onClicked: { - if (page >= 0) - root.goToLocation(page, location, zoom) - else - Qt.openUrlExternally(url) - } - } - ToolTip { - visible: linkMA.containsMouse - delay: 1000 - text: page >= 0 ? - ("page " + (page + 1) + - " location " + location.x.toFixed(1) + ", " + location.y.toFixed(1) + - " zoom " + zoom) : url - } - } - } - PdfSelection { - id: selection - anchors.fill: parent - document: root.document - page: image.currentFrame - renderScale: image.renderScale - fromPoint: textSelectionDrag.centroid.pressPosition - toPoint: textSelectionDrag.centroid.position - hold: !textSelectionDrag.active && !mouseClickHandler.pressed - onTextChanged: root.selectedText = text - focus: true - } - } - } - ScrollBar.vertical: ScrollBar { - id: vscroll - property bool moved: false - onPositionChanged: moved = true - onActiveChanged: { - var cell = tableHelper.cellAtPos(root.width / 2, root.height / 2) - var currentItem = tableHelper.itemAtCell(cell) - var currentLocation = Qt.point(0, 0) - if (currentItem) { // maybe the delegate wasn't loaded yet - currentLocation = Qt.point((tableView.contentX - currentItem.x + jumpLocationMargin.x) / root.renderScale, - (tableView.contentY - currentItem.y + jumpLocationMargin.y) / root.renderScale) - } - if (active) { - moved = false - // emitJumped false to avoid interrupting a pinch if TableView thinks it should scroll at the same time - navigationStack.push(cell.y, currentLocation, root.renderScale, false) - } else if (moved) { - navigationStack.update(cell.y, currentLocation, root.renderScale) - } - } - } - ScrollBar.horizontal: ScrollBar { } - } - onRenderScaleChanged: { - // if navigationStack.jumped changes the scale, don't turn around and update the stack again; - // and don't force layout either, because positionViewAtCell() will do that - if (navigationStack.jumping) - return - // make TableView rebuild from scratch, because otherwise it doesn't know the delegates are changing size - tableView.rebuild() - var cell = tableHelper.cellAtPos(root.width / 2, root.height / 2) - var currentItem = tableHelper.itemAtCell(cell) - if (currentItem) { - var currentLocation = Qt.point((tableView.contentX - currentItem.x + jumpLocationMargin.x) / root.renderScale, - (tableView.contentY - currentItem.y + jumpLocationMargin.y) / root.renderScale) - navigationStack.update(cell.y, currentLocation, renderScale) - } - } - PdfNavigationStack { - id: navigationStack - property bool jumping: false - property int previousPage: 0 - onJumped: { - jumping = true - root.renderScale = zoom - if (location.y < 0) { - // invalid to indicate that a specific location was not needed, - // so attempt to position the new page just as the current page is - var currentYOffset = 0 - var previousPageDelegate = tableHelper.itemAtCell(0, previousPage) - if (previousPageDelegate) - currentYOffset = tableView.contentY - previousPageDelegate.y - tableHelper.positionViewAtRow(page, Qt.AlignTop, currentYOffset) - if (root.debug) { - console.log("going from page", previousPage, "to", page, "offset", currentYOffset, - "ended up @", tableView.contentX.toFixed(1) + ", " + tableView.contentY.toFixed(1)) - } - } else { - // jump to a page and position the given location relative to the top-left corner of the viewport - var pageSize = root.document.pagePointSize(page) - pageSize.width *= root.renderScale - pageSize.height *= root.renderScale - var xOffsetLimit = Math.max(0, pageSize.width - root.width) / 2 - var offset = Qt.point(Math.max(-xOffsetLimit, Math.min(xOffsetLimit, - location.x * root.renderScale - jumpLocationMargin.x)), - Math.max(0, location.y * root.renderScale - jumpLocationMargin.y)) - tableHelper.positionViewAtCell(0, page, Qt.AlignLeft | Qt.AlignTop, offset) - if (root.debug) { - console.log("going to zoom", zoom, "loc", location, "on page", page, - "ended up @", tableView.contentX.toFixed(1) + ", " + tableView.contentY.toFixed(1)) - } - } - jumping = false - previousPage = page - } - onCurrentPageChanged: searchModel.currentPage = currentPage - } - PdfSearchModel { - id: searchModel - document: root.document === undefined ? null : root.document - // TODO maybe avoid jumping if the result is already fully visible in the viewport - onCurrentResultBoundingRectChanged: root.goToLocation(currentPage, - Qt.point(currentResultBoundingRect.x, currentResultBoundingRect.y), 0) - } -} diff --git a/src/pdf/quick/qml/PdfPageView.qml b/src/pdf/quick/qml/PdfPageView.qml deleted file mode 100644 index b90ad2d7f..000000000 --- a/src/pdf/quick/qml/PdfPageView.qml +++ /dev/null @@ -1,276 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -import QtQuick 2.14 -import QtQuick.Controls 2.14 -import QtQuick.Pdf 5.15 -import QtQuick.Shapes 1.14 -import Qt.labs.animation 1.0 - -Rectangle { - // public API - // TODO 5.15: required property - property var document: undefined - property alias status: image.status - - property alias selectedText: selection.text - function selectAll() { - selection.selectAll() - } - function copySelectionToClipboard() { - selection.copyToClipboard() - } - - // page navigation - property alias currentPage: navigationStack.currentPage - property alias backEnabled: navigationStack.backAvailable - property alias forwardEnabled: navigationStack.forwardAvailable - function back() { navigationStack.back() } - function forward() { navigationStack.forward() } - function goToPage(page) { goToLocation(page, Qt.point(0, 0), 0) } - function goToLocation(page, location, zoom) { - if (zoom > 0) - root.renderScale = zoom - navigationStack.push(page, location, zoom) - } - - // page scaling - property real renderScale: 1 - property alias sourceSize: image.sourceSize - function resetScale() { - image.sourceSize.width = 0 - image.sourceSize.height = 0 - root.x = 0 - root.y = 0 - root.scale = 1 - } - function scaleToWidth(width, height) { - var halfRotation = Math.abs(root.rotation % 180) - image.sourceSize = Qt.size((halfRotation > 45 && halfRotation < 135) ? height : width, 0) - root.x = 0 - root.y = 0 - image.centerInSize = Qt.size(width, height) - image.centerOnLoad = true - image.vCenterOnLoad = (halfRotation > 45 && halfRotation < 135) - root.scale = 1 - } - function scaleToPage(width, height) { - var windowAspect = width / height - var halfRotation = Math.abs(root.rotation % 180) - var pagePointSize = document.pagePointSize(navigationStack.currentPage) - if (halfRotation > 45 && halfRotation < 135) { - // rotated 90 or 270º - var pageAspect = pagePointSize.height / pagePointSize.width - if (windowAspect > pageAspect) { - image.sourceSize = Qt.size(height, 0) - } else { - image.sourceSize = Qt.size(0, width) - } - } else { - var pageAspect = pagePointSize.width / pagePointSize.height - if (windowAspect > pageAspect) { - image.sourceSize = Qt.size(0, height) - } else { - image.sourceSize = Qt.size(width, 0) - } - } - image.centerInSize = Qt.size(width, height) - image.centerOnLoad = true - image.vCenterOnLoad = true - root.scale = 1 - } - - // text search - property alias searchModel: searchModel - property alias searchString: searchModel.searchString - function searchBack() { --searchModel.currentResult } - function searchForward() { ++searchModel.currentResult } - - // implementation - id: root - width: image.width - height: image.height - - PdfSelection { - id: selection - document: root.document - page: navigationStack.currentPage - fromPoint: Qt.point(textSelectionDrag.centroid.pressPosition.x / image.pageScale, textSelectionDrag.centroid.pressPosition.y / image.pageScale) - toPoint: Qt.point(textSelectionDrag.centroid.position.x / image.pageScale, textSelectionDrag.centroid.position.y / image.pageScale) - hold: !textSelectionDrag.active && !tapHandler.pressed - } - - PdfSearchModel { - id: searchModel - document: root.document === undefined ? null : root.document - onCurrentPageChanged: root.goToPage(currentPage) - } - - PdfNavigationStack { - id: navigationStack - onCurrentPageChanged: searchModel.currentPage = currentPage - // TODO onCurrentLocationChanged: position currentLocation.x and .y in middle // currentPageChanged() MUST occur first! - onCurrentZoomChanged: root.renderScale = currentZoom - // TODO deal with horizontal location (need WheelHandler or Flickable probably) - } - - Image { - id: image - currentFrame: navigationStack.currentPage - source: document.status === PdfDocument.Ready ? document.source : "" - asynchronous: true - fillMode: Image.PreserveAspectFit - property bool centerOnLoad: false - property bool vCenterOnLoad: false - property size centerInSize - property real pageScale: image.paintedWidth / document.pagePointSize(navigationStack.currentPage).width - function reRenderIfNecessary() { - var newSourceWidth = image.sourceSize.width * root.scale - var ratio = newSourceWidth / image.sourceSize.width - if (ratio > 1.1 || ratio < 0.9) { - image.sourceSize.width = newSourceWidth - image.sourceSize.height = 0 - root.scale = 1 - } - } - onStatusChanged: - if (status == Image.Ready && centerOnLoad) { - root.x = (centerInSize.width - image.implicitWidth) / 2 - root.y = vCenterOnLoad ? (centerInSize.height - image.implicitHeight) / 2 : 0 - centerOnLoad = false - vCenterOnLoad = false - } - } - onRenderScaleChanged: { - image.sourceSize.width = document.pagePointSize(navigationStack.currentPage).width * renderScale - image.sourceSize.height = 0 - root.scale = 1 - } - - Shape { - anchors.fill: parent - opacity: 0.25 - visible: image.status === Image.Ready - ShapePath { - strokeWidth: 1 - strokeColor: "cyan" - fillColor: "steelblue" - scale: Qt.size(image.pageScale, image.pageScale) - PathMultiline { - paths: searchModel.currentPageBoundingPolygons - } - } - ShapePath { - strokeWidth: 1 - strokeColor: "orange" - fillColor: "cyan" - scale: Qt.size(image.pageScale, image.pageScale) - PathMultiline { - paths: searchModel.currentResultBoundingPolygons - } - } - ShapePath { - fillColor: "orange" - scale: Qt.size(image.pageScale, image.pageScale) - PathMultiline { - paths: selection.geometry - } - } - } - - Repeater { - model: PdfLinkModel { - id: linkModel - document: root.document - page: navigationStack.currentPage - } - delegate: Rectangle { - color: "transparent" - border.color: "lightgrey" - x: rect.x * image.pageScale - y: rect.y * image.pageScale - width: rect.width * image.pageScale - height: rect.height * image.pageScale - MouseArea { // TODO switch to TapHandler / HoverHandler in 5.15 - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (page >= 0) - navigationStack.push(page, Qt.point(0, 0), root.renderScale) - else - Qt.openUrlExternally(url) - } - } - } - } - - PinchHandler { - id: pinch - minimumScale: 0.1 - maximumScale: 10 - minimumRotation: 0 - maximumRotation: 0 - onActiveChanged: if (!active) image.reRenderIfNecessary() - grabPermissions: PinchHandler.TakeOverForbidden // don't allow takeover if pinch has started - } - DragHandler { - id: pageMovingTouchDrag - acceptedDevices: PointerDevice.TouchScreen - } - DragHandler { - id: pageMovingMiddleMouseDrag - acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus - acceptedButtons: Qt.MiddleButton - snapMode: DragHandler.NoSnap - } - DragHandler { - id: textSelectionDrag - acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus - target: null - } - TapHandler { - id: tapHandler - acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus - } - // prevent it from being scrolled out of view - BoundaryRule on x { - minimum: 100 - root.width - maximum: root.parent.width - 100 - } - BoundaryRule on y { - minimum: 100 - root.height - maximum: root.parent.height - 100 - } -} diff --git a/src/pdf/quick/qml/PdfScrollablePageView.qml b/src/pdf/quick/qml/PdfScrollablePageView.qml deleted file mode 100644 index 51d9e530d..000000000 --- a/src/pdf/quick/qml/PdfScrollablePageView.qml +++ /dev/null @@ -1,307 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -import QtQuick 2.14 -import QtQuick.Controls 2.14 -import QtQuick.Pdf 5.15 -import QtQuick.Shapes 1.14 -import Qt.labs.animation 1.0 - -Flickable { - // public API - // TODO 5.15: required property - property var document: undefined - property bool debug: false - property alias status: image.status - - property alias selectedText: selection.text - function selectAll() { - selection.selectAll() - } - function copySelectionToClipboard() { - selection.copyToClipboard() - } - - // page navigation - property alias currentPage: navigationStack.currentPage - property alias backEnabled: navigationStack.backAvailable - property alias forwardEnabled: navigationStack.forwardAvailable - function back() { navigationStack.back() } - function forward() { navigationStack.forward() } - function goToPage(page) { - if (page === navigationStack.currentPage) - return - goToLocation(page, Qt.point(0, 0), 0) - } - function goToLocation(page, location, zoom) { - if (zoom > 0) - root.renderScale = zoom - navigationStack.push(page, location, zoom) - } - - // page scaling - property real renderScale: 1 - property real pageRotation: 0 - property alias sourceSize: image.sourceSize - function resetScale() { - paper.scale = 1 - root.renderScale = 1 - } - function scaleToWidth(width, height) { - var pagePointSize = document.pagePointSize(navigationStack.currentPage) - root.renderScale = root.width / (paper.rot90 ? pagePointSize.height : pagePointSize.width) - if (debug) - console.log("scaling", pagePointSize, "to fit", root.width, "rotated?", paper.rot90, "scale", root.renderScale) - root.contentX = 0 - root.contentY = 0 - } - function scaleToPage(width, height) { - var pagePointSize = document.pagePointSize(navigationStack.currentPage) - root.renderScale = Math.min( - root.width / (paper.rot90 ? pagePointSize.height : pagePointSize.width), - root.height / (paper.rot90 ? pagePointSize.width : pagePointSize.height) ) - root.contentX = 0 - root.contentY = 0 - } - - // text search - property alias searchModel: searchModel - property alias searchString: searchModel.searchString - function searchBack() { --searchModel.currentResult } - function searchForward() { ++searchModel.currentResult } - - // implementation - id: root - PdfStyle { id: style } - contentWidth: paper.width - contentHeight: paper.height - ScrollBar.vertical: ScrollBar { - onActiveChanged: - if (!active ) { - var currentLocation = Qt.point((root.contentX + root.width / 2) / root.renderScale, - (root.contentY + root.height / 2) / root.renderScale) - navigationStack.update(navigationStack.currentPage, currentLocation, root.renderScale) - } - } - ScrollBar.horizontal: ScrollBar { - onActiveChanged: - if (!active ) { - var currentLocation = Qt.point((root.contentX + root.width / 2) / root.renderScale, - (root.contentY + root.height / 2) / root.renderScale) - navigationStack.update(navigationStack.currentPage, currentLocation, root.renderScale) - } - } - - onRenderScaleChanged: { - image.sourceSize.width = document.pagePointSize(navigationStack.currentPage).width * renderScale - image.sourceSize.height = 0 - paper.scale = 1 - var currentLocation = Qt.point((root.contentX + root.width / 2) / root.renderScale, - (root.contentY + root.height / 2) / root.renderScale) - navigationStack.update(navigationStack.currentPage, currentLocation, root.renderScale) - } - - PdfSearchModel { - id: searchModel - document: root.document === undefined ? null : root.document - // TODO maybe avoid jumping if the result is already fully visible in the viewport - onCurrentResultBoundingRectChanged: root.goToLocation(currentPage, - Qt.point(currentResultBoundingRect.x, currentResultBoundingRect.y), 0) - } - - PdfNavigationStack { - id: navigationStack - onJumped: { - root.renderScale = zoom - var dx = Math.max(0, location.x * root.renderScale - root.width / 2) - root.contentX - var dy = Math.max(0, location.y * root.renderScale - root.height / 2) - root.contentY - // don't jump if location is in the viewport already, i.e. if the "error" between desired and actual contentX/Y is small - if (Math.abs(dx) > root.width / 3) - root.contentX += dx - if (Math.abs(dy) > root.height / 3) - root.contentY += dy - if (root.debug) { - console.log("going to zoom", zoom, "loc", location, - "on page", page, "ended up @", root.contentX + ", " + root.contentY) - } - } - onCurrentPageChanged: searchModel.currentPage = currentPage - } - - Rectangle { - id: paper - width: rot90 ? image.height : image.width - height: rot90 ? image.width : image.height - property real rotationModulus: Math.abs(root.pageRotation % 180) - property bool rot90: rotationModulus > 45 && rotationModulus < 135 - - Image { - id: image - currentFrame: navigationStack.currentPage - source: document.status === PdfDocument.Ready ? document.source : "" - asynchronous: true - fillMode: Image.PreserveAspectFit - rotation: root.pageRotation - anchors.centerIn: parent - property real pageScale: image.paintedWidth / document.pagePointSize(navigationStack.currentPage).width - - Shape { - anchors.fill: parent - visible: image.status === Image.Ready - ShapePath { - strokeWidth: -1 - fillColor: style.pageSearchResultsColor - scale: Qt.size(image.pageScale, image.pageScale) - PathMultiline { - paths: searchModel.currentPageBoundingPolygons - } - } - ShapePath { - strokeWidth: style.currentSearchResultStrokeWidth - strokeColor: style.currentSearchResultStrokeColor - fillColor: "transparent" - scale: Qt.size(image.pageScale, image.pageScale) - PathMultiline { - paths: searchModel.currentResultBoundingPolygons - } - } - ShapePath { - fillColor: style.selectionColor - scale: Qt.size(image.pageScale, image.pageScale) - PathMultiline { - paths: selection.geometry - } - } - } - - Repeater { - model: PdfLinkModel { - id: linkModel - document: root.document - page: navigationStack.currentPage - } - delegate: Shape { - x: rect.x * image.pageScale - y: rect.y * image.pageScale - width: rect.width * image.pageScale - height: rect.height * image.pageScale - ShapePath { - strokeWidth: style.linkUnderscoreStrokeWidth - strokeColor: style.linkUnderscoreColor - strokeStyle: style.linkUnderscoreStrokeStyle - dashPattern: style.linkUnderscoreDashPattern - startX: 0; startY: height - PathLine { x: width; y: height } - } - MouseArea { // TODO switch to TapHandler / HoverHandler in 5.15 - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (page >= 0) - navigationStack.push(page, Qt.point(0, 0), root.renderScale) - else - Qt.openUrlExternally(url) - } - } - } - } - DragHandler { - id: textSelectionDrag - acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus - target: null - } - TapHandler { - id: mouseClickHandler - acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus - } - TapHandler { - id: touchTapHandler - acceptedDevices: PointerDevice.TouchScreen - onTapped: { - selection.clear() - selection.focus = true - } - } - } - - PdfSelection { - id: selection - anchors.fill: parent - document: root.document - page: navigationStack.currentPage - renderScale: image.pageScale - fromPoint: textSelectionDrag.centroid.pressPosition - toPoint: textSelectionDrag.centroid.position - hold: !textSelectionDrag.active && !mouseClickHandler.pressed - focus: true - } - - PinchHandler { - id: pinch - minimumScale: 0.1 - maximumScale: root.renderScale < 4 ? 2 : 1 - minimumRotation: 0 - maximumRotation: 0 - enabled: image.sourceSize.width < 5000 - onActiveChanged: - if (!active) { - var centroidInPoints = Qt.point(pinch.centroid.position.x / root.renderScale, - pinch.centroid.position.y / root.renderScale) - var centroidInFlickable = root.mapFromItem(paper, pinch.centroid.position.x, pinch.centroid.position.y) - var newSourceWidth = image.sourceSize.width * paper.scale - var ratio = newSourceWidth / image.sourceSize.width - if (root.debug) - console.log("pinch ended with centroid", pinch.centroid.position, centroidInPoints, "wrt flickable", centroidInFlickable, - "page at", paper.x.toFixed(2), paper.y.toFixed(2), - "contentX/Y were", root.contentX.toFixed(2), root.contentY.toFixed(2)) - if (ratio > 1.1 || ratio < 0.9) { - var centroidOnPage = Qt.point(centroidInPoints.x * root.renderScale * ratio, centroidInPoints.y * root.renderScale * ratio) - paper.scale = 1 - paper.x = 0 - paper.y = 0 - root.contentX = centroidOnPage.x - centroidInFlickable.x - root.contentY = centroidOnPage.y - centroidInFlickable.y - root.renderScale *= ratio // onRenderScaleChanged calls navigationStack.update() so we don't need to here - if (root.debug) - console.log("contentX/Y adjusted to", root.contentX.toFixed(2), root.contentY.toFixed(2)) - } else { - paper.x = 0 - paper.y = 0 - } - } - grabPermissions: PointerHandler.CanTakeOverFromAnything - } - } -} diff --git a/src/pdf/quick/qml/PdfStyle.qml b/src/pdf/quick/qml/PdfStyle.qml deleted file mode 100644 index 090465ce6..000000000 --- a/src/pdf/quick/qml/PdfStyle.qml +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -import QtQml 2.14 -import QtQuick 2.14 -import QtQuick.Controls 2.14 -import QtQuick.Shapes 1.14 - -QtObject { - property Control prototypeControl: Control { } - function withAlpha(color, alpha) { - return Qt.hsla(color.hslHue, color.hslSaturation, color.hslLightness, alpha) - } - property color selectionColor: withAlpha(prototypeControl.palette.highlight, 0.5) - property color pageSearchResultsColor: "#80B0C4DE" - property color currentSearchResultStrokeColor: "cyan" - property real currentSearchResultStrokeWidth: 2 - property color linkUnderscoreColor: prototypeControl.palette.link - property real linkUnderscoreStrokeWidth: 1 - property var linkUnderscoreStrokeStyle: ShapePath.DashLine - property var linkUnderscoreDashPattern: [ 1, 4 ] -} diff --git a/src/pdf/quick/qmldir b/src/pdf/quick/qmldir deleted file mode 100644 index 65fa95cda..000000000 --- a/src/pdf/quick/qmldir +++ /dev/null @@ -1,4 +0,0 @@ -module QtQuick.Pdf -plugin pdfplugin -classname QtQuick2PdfPlugin -typeinfo plugins.qmltypes diff --git a/src/pdf/quick/qquickpdfdocument.cpp b/src/pdf/quick/qquickpdfdocument.cpp deleted file mode 100644 index ab5910523..000000000 --- a/src/pdf/quick/qquickpdfdocument.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qquickpdfdocument_p.h" -#include <QQuickItem> -#include <QQmlEngine> -#include <QStandardPaths> - -QT_BEGIN_NAMESPACE - -/*! - \qmltype PdfDocument - \instantiates QQuickPdfDocument - \inqmlmodule QtQuick.Pdf - \ingroup pdf - \brief A representation of a PDF document. - \since 5.15 - - PdfDocument provides access to PDF document meta-information. - It is not necessary for rendering, as it is enough to use an - \l Image with source set to the URL of the PDF. -*/ - -/*! - Constructs a PDF document. -*/ -QQuickPdfDocument::QQuickPdfDocument(QObject *parent) - : QObject(parent) -{ - connect(&m_doc, &QPdfDocument::passwordChanged, this, &QQuickPdfDocument::passwordChanged); - connect(&m_doc, &QPdfDocument::passwordRequired, this, &QQuickPdfDocument::passwordRequired); - connect(&m_doc, &QPdfDocument::statusChanged, [=] (QPdfDocument::Status status) { - emit statusChanged(); - if (status == QPdfDocument::Ready) - emit metaDataChanged(); - }); - connect(&m_doc, &QPdfDocument::pageCountChanged, this, &QQuickPdfDocument::pageCountChanged); -} - -void QQuickPdfDocument::componentComplete() -{ - if (m_doc.error() == QPdfDocument::IncorrectPasswordError) - emit passwordRequired(); -} - -/*! - \qmlproperty url PdfDocument::source - - This property holds a URL pointing to the PDF file to be loaded. - - \note At this time, only local filesystem URLs are supported. -*/ -void QQuickPdfDocument::setSource(QUrl source) -{ - if (m_source == source) - return; - - m_source = source; - m_maxPageWidthHeight = QSizeF(); - emit sourceChanged(); - if (source.scheme() == QLatin1String("qrc")) - m_doc.load(QLatin1Char(':') + source.path()); - else - m_doc.load(source.path()); -} - -/*! - \qmlproperty string PdfDocument::error - - This property holds a translated string representation of the current - error, if any. - - \sa status -*/ -QString QQuickPdfDocument::error() const -{ - switch (m_doc.error()) { - case QPdfDocument::NoError: - return tr("no error"); - break; - case QPdfDocument::UnknownError: - break; - case QPdfDocument::DataNotYetAvailableError: - return tr("data not yet available"); - break; - case QPdfDocument::FileNotFoundError: - return tr("file not found"); - break; - case QPdfDocument::InvalidFileFormatError: - return tr("invalid file format"); - break; - case QPdfDocument::IncorrectPasswordError: - return tr("incorrect password"); - break; - case QPdfDocument::UnsupportedSecuritySchemeError: - return tr("unsupported security scheme"); - break; - } - return tr("unknown error"); -} - -/*! - \qmlproperty bool PdfDocument::password - - This property holds the document password. If the passwordRequired() - signal is emitted, the UI should prompt the user and then set this - property so that document opening can continue. -*/ -void QQuickPdfDocument::setPassword(const QString &password) -{ - if (m_doc.password() == password) - return; - m_doc.setPassword(password); - if (source().isValid() && source().isLocalFile()) - m_doc.load(source().path()); -} - -/*! - \qmlproperty int PdfDocument::pageCount - - This property holds the number of pages the PDF contains. -*/ - -/*! - \qmlsignal PdfDocument::passwordRequired() - - This signal is emitted when the PDF requires a password in order to open. - The UI in a typical PDF viewer should prompt the user for the password - and then set the password property when the user has provided it. -*/ - -/*! - \qmlmethod size PdfDocument::pagePointSize(int page) - - Returns the size of the given \a page in points. -*/ -QSizeF QQuickPdfDocument::pagePointSize(int page) const -{ - return m_doc.pageSize(page); -} - -qreal QQuickPdfDocument::maxPageWidth() const -{ - const_cast<QQuickPdfDocument *>(this)->updateMaxPageSize(); - return m_maxPageWidthHeight.width(); -} - -qreal QQuickPdfDocument::maxPageHeight() const -{ - const_cast<QQuickPdfDocument *>(this)->updateMaxPageSize(); - return m_maxPageWidthHeight.height(); -} - -/*! - \internal - \qmlmethod size PdfDocument::heightSumBeforePage(int page) - - Returns the sum of the heights, in points, of all sets of \a facingPages - pages from 0 to the given \a page, exclusive. - - That is, if the pages were laid out end-to-end in adjacent sets of - \a facingPages, what would be the distance in points from the top of the - first page to the top of the given page. -*/ -// Workaround for lack of something analogous to ListView.positionViewAtIndex() in TableView -qreal QQuickPdfDocument::heightSumBeforePage(int page, qreal spacing, int facingPages) const -{ - qreal ret = 0; - for (int i = 0; i < page; i+= facingPages) { - if (i + facingPages > page) - break; - qreal facingPagesHeight = 0; - for (int j = i; j < i + facingPages; ++j) - facingPagesHeight = qMax(facingPagesHeight, pagePointSize(j).height()); - ret += facingPagesHeight + spacing; - } - return ret; -} - -void QQuickPdfDocument::updateMaxPageSize() -{ - if (m_maxPageWidthHeight.isValid()) - return; - qreal w = 0; - qreal h = 0; - const int count = pageCount(); - for (int i = 0; i < count; ++i) { - auto size = pagePointSize(i); - w = qMax(w, size.width()); - h = qMax(w, size.height()); - } - m_maxPageWidthHeight = QSizeF(w, h); -} - -/*! - \qmlproperty real PdfDocument::maxPageWidth - - This property holds the width of the widest page in the document, in points. -*/ - -/*! - \qmlproperty real PdfDocument::maxPageHeight - - This property holds the height of the tallest page in the document, in points. -*/ - -/*! - \qmlproperty string PdfDocument::title - - This property holds the document's title. A typical viewer UI can bind this - to the \c Window.title property. -*/ - -/*! - \qmlproperty string PdfDocument::author - - This property holds the name of the person who created the document. -*/ - -/*! - \qmlproperty string PdfDocument::subject - - This property holds the subject of the document. -*/ - -/*! - \qmlproperty string PdfDocument::keywords - - This property holds the keywords associated with the document. -*/ - -/*! - \qmlproperty string PdfDocument::creator - - If the document was converted to PDF from another format, this property - holds the name of the software that created the original document. -*/ - -/*! - \qmlproperty string PdfDocument::producer - - If the document was converted to PDF from another format, this property - holds the name of the software that converted it to PDF. -*/ - -/*! - \qmlproperty string PdfDocument::creationDate - - This property holds the date and time the document was created. -*/ - -/*! - \qmlproperty string PdfDocument::modificationDate - - This property holds the date and time the document was most recently - modified. -*/ - -/*! - \qmlproperty enum PdfDocument::status - - This property tells the current status of the document. The possible values are: - - \value PdfDocument.Null The initial status after the document has been created or after it has been closed. - \value PdfDocument.Loading The status after load() has been called and before the document is fully loaded. - \value PdfDocument.Ready The status when the document is fully loaded and its data can be accessed. - \value PdfDocument.Unloading The status after close() has been called on an open document. - At this point the document is still valid and all its data can be accessed. - \value PdfDocument.Error The status after Loading, if loading has failed. -*/ - -QT_END_NAMESPACE diff --git a/src/pdf/quick/qquickpdfdocument_p.h b/src/pdf/quick/qquickpdfdocument_p.h deleted file mode 100644 index cefa4f756..000000000 --- a/src/pdf/quick/qquickpdfdocument_p.h +++ /dev/null @@ -1,137 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQUICKPDFDOCUMENT_P_H -#define QQUICKPDFDOCUMENT_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 <QtPdf/QPdfDocument> -#include <QDateTime> -#include <QJSValue> -#include <QQmlParserStatus> -#include <QUrl> -#include <QVariant> - -QT_BEGIN_NAMESPACE - -class QQuickPdfDocument : public QObject, public QQmlParserStatus -{ - Q_OBJECT - Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged FINAL) - Q_PROPERTY(qreal maxPageWidth READ maxPageWidth NOTIFY metaDataChanged) - Q_PROPERTY(qreal maxPageHeight READ maxPageHeight NOTIFY metaDataChanged) - Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged FINAL) - Q_PROPERTY(QPdfDocument::Status status READ status NOTIFY statusChanged FINAL) - Q_PROPERTY(QString error READ error NOTIFY statusChanged FINAL) - - Q_PROPERTY(QString title READ title NOTIFY metaDataChanged) - Q_PROPERTY(QString subject READ subject NOTIFY metaDataChanged) - Q_PROPERTY(QString author READ author NOTIFY metaDataChanged) - Q_PROPERTY(QString keywords READ keywords NOTIFY metaDataChanged) - Q_PROPERTY(QString producer READ producer NOTIFY metaDataChanged) - Q_PROPERTY(QString creator READ creator NOTIFY metaDataChanged) - Q_PROPERTY(QDateTime creationDate READ creationDate NOTIFY metaDataChanged) - Q_PROPERTY(QDateTime modificationDate READ modificationDate NOTIFY metaDataChanged) - -public: - explicit QQuickPdfDocument(QObject *parent = nullptr); - - void classBegin() override {} - void componentComplete() override; - - QUrl source() const { return m_source; } - void setSource(QUrl source); - - int pageCount() const { return m_doc.pageCount(); } - QPdfDocument::Status status() const { return m_doc.status(); } - - QString error() const; - - QString password() const { return m_doc.password(); } - void setPassword(const QString &password); - - QString title() { return m_doc.metaData(QPdfDocument::Title).toString(); } - QString author() { return m_doc.metaData(QPdfDocument::Author).toString(); } - QString subject() { return m_doc.metaData(QPdfDocument::Subject).toString(); } - QString keywords() { return m_doc.metaData(QPdfDocument::Keywords).toString(); } - QString producer() { return m_doc.metaData(QPdfDocument::Producer).toString(); } - QString creator() { return m_doc.metaData(QPdfDocument::Creator).toString(); } - QDateTime creationDate() { return m_doc.metaData(QPdfDocument::CreationDate).toDateTime(); } - QDateTime modificationDate() { return m_doc.metaData(QPdfDocument::ModificationDate).toDateTime(); } - - Q_INVOKABLE QSizeF pagePointSize(int page) const; - qreal maxPageWidth() const; - qreal maxPageHeight() const; - Q_INVOKABLE qreal heightSumBeforePage(int page, qreal spacing = 0, int facingPages = 1) const; - -Q_SIGNALS: - void sourceChanged(); - void passwordChanged(); - void passwordRequired(); - void statusChanged(); - void pageCountChanged(); - void metaDataChanged(); - -private: - QPdfDocument &document() { return m_doc; } - void updateMaxPageSize(); - -private: - QUrl m_source; - QPdfDocument m_doc; - QSizeF m_maxPageWidthHeight; - - friend class QQuickPdfLinkModel; - friend class QQuickPdfSearchModel; - friend class QQuickPdfSelection; - - Q_DISABLE_COPY(QQuickPdfDocument) -}; - -QT_END_NAMESPACE - -#endif // QQUICKPDFDOCUMENT_P_H diff --git a/src/pdf/quick/qquickpdflinkmodel.cpp b/src/pdf/quick/qquickpdflinkmodel.cpp deleted file mode 100644 index 4f3958337..000000000 --- a/src/pdf/quick/qquickpdflinkmodel.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qquickpdflinkmodel_p.h" -#include <QQuickItem> -#include <QQmlEngine> -#include <QStandardPaths> - -QT_BEGIN_NAMESPACE - -/*! - \qmltype PdfLinkModel - \instantiates QQuickPdfLinkModel - \inqmlmodule QtQuick.Pdf - \ingroup pdf - \brief A representation of links within a PDF document. - \since 5.15 - - PdfLinkModel provides the geometry and the destination for each link - that the specified \l page contains. - - The available model roles are: - - \value rect - 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 intended zoom level on the destination page. - - Normally it will be used with \l {QtQuick::Repeater}{Repeater} to visualize - the links and provide the ability to click them: - - \qml - Repeater { - model: PdfLinkModel { - document: root.document - page: image.currentFrame - } - delegate: Rectangle { - color: "transparent" - border.color: "lightgrey" - x: rect.x - y: rect.y - width: rect.width - height: rect.height - HoverHandler { cursorShape: Qt.PointingHandCursor } - TapHandler { - onTapped: { - if (page >= 0) - image.currentFrame = page - else - Qt.openUrlExternally(url) - } - } - } - } - \endqml - - \note General-purpose PDF viewing capabilities are provided by - \l PdfScrollablePageView and \l PdfMultiPageView. PdfLinkModel is only needed - when building PDF view components from scratch. -*/ - -QQuickPdfLinkModel::QQuickPdfLinkModel(QObject *parent) - : QPdfLinkModel(parent) -{ -} - -/*! - \qmlproperty PdfDocument PdfLinkModel::document - - This property holds the PDF document in which links are to be found. -*/ -QQuickPdfDocument *QQuickPdfLinkModel::document() const -{ - return m_quickDocument; -} - -void QQuickPdfLinkModel::setDocument(QQuickPdfDocument *document) -{ - if (document == m_quickDocument) - return; - m_quickDocument = document; - QPdfLinkModel::setDocument(&document->m_doc); -} - -/*! - \qmlproperty int PdfLinkModel::page - - This property holds the page number on which links are to be found. -*/ - -QT_END_NAMESPACE diff --git a/src/pdf/quick/qquickpdflinkmodel_p.h b/src/pdf/quick/qquickpdflinkmodel_p.h deleted file mode 100644 index 23ad6c8c1..000000000 --- a/src/pdf/quick/qquickpdflinkmodel_p.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQUICKPDFLINKMODEL_P_H -#define QQUICKPDFLINKMODEL_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 "qquickpdfdocument_p.h" -#include "../api/qpdflinkmodel_p.h" - -#include <QVariant> -#include <QtQml/qqml.h> - -QT_BEGIN_NAMESPACE - -class QQuickPdfLinkModel : public QPdfLinkModel -{ - Q_OBJECT - Q_PROPERTY(QQuickPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged) - -public: - explicit QQuickPdfLinkModel(QObject *parent = nullptr); - - QQuickPdfDocument *document() const; - void setDocument(QQuickPdfDocument *document); - -signals: - void documentChanged(); - -private: - void updateResults(); - -private: - QQuickPdfDocument *m_quickDocument; - QVector<QPolygonF> m_linksGeometry; - - Q_DISABLE_COPY(QQuickPdfLinkModel) -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QQuickPdfLinkModel) - -#endif // QQUICKPDFLINKMODEL_P_H diff --git a/src/pdf/quick/qquickpdfnavigationstack.cpp b/src/pdf/quick/qquickpdfnavigationstack.cpp deleted file mode 100644 index 044023ef6..000000000 --- a/src/pdf/quick/qquickpdfnavigationstack.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qquickpdfnavigationstack_p.h" -#include <QLoggingCategory> - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(qLcNav, "qt.pdf.navigationstack") - -/*! - \qmltype PdfNavigationStack - \instantiates QQuickPdfNavigationStack - \inqmlmodule QtQuick.Pdf - \ingroup pdf - \brief History of the destinations visited within a PDF Document. - \since 5.15 - - PdfNavigationStack remembers which destinations the user has visited in a PDF - document, and provides the ability to traverse backward and forward. -*/ - -QQuickPdfNavigationStack::QQuickPdfNavigationStack(QObject *parent) - : QObject(parent) -{ - push(0, QPointF(), 1); -} - -/*! - \qmlmethod void PdfNavigationStack::forward() - - 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 QQuickPdfNavigationStack::forward() -{ - if (m_currentHistoryIndex >= m_pageHistory.count() - 1) - return; - bool backAvailableWas = backAvailable(); - bool forwardAvailableWas = forwardAvailable(); - QPointF currentLocationWas = currentLocation(); - qreal currentZoomWas = currentZoom(); - ++m_currentHistoryIndex; - m_changing = true; - emit jumped(currentPage(), currentLocation(), currentZoom()); - if (currentZoomWas != currentZoom()) - emit currentZoomChanged(); - emit currentPageChanged(); - if (currentLocationWas != currentLocation()) - emit currentLocationChanged(); - if (!backAvailableWas) - emit backAvailableChanged(); - if (forwardAvailableWas != forwardAvailable()) - emit forwardAvailableChanged(); - m_changing = false; - qCDebug(qLcNav) << "forward: index" << m_currentHistoryIndex << "page" << currentPage() - << "@" << currentLocation() << "zoom" << currentZoom(); -} - -/*! - \qmlmethod void PdfNavigationStack::back() - - 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 QQuickPdfNavigationStack::back() -{ - if (m_currentHistoryIndex <= 0) - return; - bool backAvailableWas = backAvailable(); - bool forwardAvailableWas = forwardAvailable(); - QPointF currentLocationWas = currentLocation(); - qreal currentZoomWas = currentZoom(); - --m_currentHistoryIndex; - m_changing = true; - emit jumped(currentPage(), currentLocation(), currentZoom()); - if (currentZoomWas != currentZoom()) - emit currentZoomChanged(); - emit currentPageChanged(); - if (currentLocationWas != currentLocation()) - emit currentLocationChanged(); - if (backAvailableWas != backAvailable()) - emit backAvailableChanged(); - if (!forwardAvailableWas) - emit forwardAvailableChanged(); - m_changing = false; - qCDebug(qLcNav) << "back: index" << m_currentHistoryIndex << "page" << currentPage() - << "@" << currentLocation() << "zoom" << currentZoom(); -} - -/*! - \qmlproperty int PdfNavigationStack::currentPage - - This property holds the current page that is being viewed. - If there is no current page, it holds \c -1. -*/ -int QQuickPdfNavigationStack::currentPage() const -{ - if (m_currentHistoryIndex < 0 || m_currentHistoryIndex >= m_pageHistory.count()) - return -1; - return m_pageHistory.at(m_currentHistoryIndex)->page; -} - -/*! - \qmlproperty point PdfNavigationStack::currentLocation - - This property holds the current location on the page that is being viewed. -*/ -QPointF QQuickPdfNavigationStack::currentLocation() const -{ - if (m_currentHistoryIndex < 0 || m_currentHistoryIndex >= m_pageHistory.count()) - return QPointF(); - return m_pageHistory.at(m_currentHistoryIndex)->location; -} - -/*! - \qmlproperty real PdfNavigationStack::currentZoom - - This property holds the magnification scale on the page that is being viewed. -*/ -qreal QQuickPdfNavigationStack::currentZoom() const -{ - if (m_currentHistoryIndex < 0 || m_currentHistoryIndex >= m_pageHistory.count()) - return 1; - return m_pageHistory.at(m_currentHistoryIndex)->zoom; -} - -/*! - \qmlmethod void PdfNavigationStack::push(int page, point location, qreal zoom) - - Adds the given destination, consisting of \a page, \a location and \a zoom, - to the history of visited locations. If \a emitJumped is \c false, the - \l jumped() signal will not be emitted. - - 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 QQuickPdfNavigationStack::push(int page, QPointF location, qreal zoom, bool emitJumped) -{ - if (page == currentPage() && location == currentLocation() && zoom == currentZoom()) - return; - if (qFuzzyIsNull(zoom)) - zoom = currentZoom(); - bool backAvailableWas = backAvailable(); - bool forwardAvailableWas = forwardAvailable(); - if (!m_changing) { - if (m_currentHistoryIndex >= 0 && forwardAvailableWas) - m_pageHistory.remove(m_currentHistoryIndex + 1, m_pageHistory.count() - m_currentHistoryIndex - 1); - m_pageHistory.append(QExplicitlySharedDataPointer<QPdfDestinationPrivate>(new QPdfDestinationPrivate(page, location, zoom))); - m_currentHistoryIndex = m_pageHistory.count() - 1; - } - emit currentZoomChanged(); - emit currentPageChanged(); - emit currentLocationChanged(); - if (m_changing) - return; - if (!backAvailableWas) - emit backAvailableChanged(); - if (forwardAvailableWas) - emit forwardAvailableChanged(); - if (emitJumped) - emit jumped(page, location, zoom); - qCDebug(qLcNav) << "push: index" << m_currentHistoryIndex << "page" << page - << "@" << location << "zoom" << zoom << "-> history" << - [this]() { - QStringList ret; - for (auto d : m_pageHistory) - ret << QString::number(d->page); - return ret.join(','); - }(); -} - -/*! - \qmlmethod void PdfNavigationStack::update(int page, point location, qreal zoom) - - 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 QQuickPdfNavigationStack::update(int page, QPointF location, qreal zoom) -{ - if (m_currentHistoryIndex < 0 || m_currentHistoryIndex >= m_pageHistory.count()) - return; - int currentPageWas = currentPage(); - QPointF currentLocationWas = currentLocation(); - qreal currentZoomWas = currentZoom(); - if (page == currentPageWas && location == currentLocationWas && zoom == currentZoomWas) - return; - m_pageHistory[m_currentHistoryIndex]->page = page; - m_pageHistory[m_currentHistoryIndex]->location = location; - m_pageHistory[m_currentHistoryIndex]->zoom = zoom; - if (currentZoomWas != zoom) - emit currentZoomChanged(); - if (currentPageWas != page) - emit currentPageChanged(); - if (currentLocationWas != location) - emit currentLocationChanged(); - qCDebug(qLcNav) << "update: index" << m_currentHistoryIndex << "page" << page - << "@" << location << "zoom" << zoom << "-> history" << - [this]() { - QStringList ret; - for (auto d : m_pageHistory) - ret << QString::number(d->page); - return ret.join(','); - }(); -} - -bool QQuickPdfNavigationStack::backAvailable() const -{ - return m_currentHistoryIndex > 0; -} - -bool QQuickPdfNavigationStack::forwardAvailable() const -{ - return m_currentHistoryIndex < m_pageHistory.count() - 1; -} - -/*! - \qmlsignal PdfNavigationStack::jumped(int page, point location, qreal zoom) - - This signal is emitted when forward(), back() or push() is called, but not - when update() is called. -*/ - -QT_END_NAMESPACE diff --git a/src/pdf/quick/qquickpdfnavigationstack_p.h b/src/pdf/quick/qquickpdfnavigationstack_p.h deleted file mode 100644 index 0d88d62fd..000000000 --- a/src/pdf/quick/qquickpdfnavigationstack_p.h +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQUICKPDFNAVIGATIONSTACK_P_H -#define QQUICKPDFNAVIGATIONSTACK_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 "qquickpdfdocument_p.h" -#include "../api/qpdfdestination_p.h" - -#include <QtQml/qqml.h> - -QT_BEGIN_NAMESPACE - -class QQuickPdfNavigationStack : 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: - explicit QQuickPdfNavigationStack(QObject *parent = nullptr); - - Q_INVOKABLE void push(int page, QPointF location, qreal zoom, bool emitJumped = true); - Q_INVOKABLE void update(int page, QPointF location, qreal zoom); - Q_INVOKABLE void forward(); - Q_INVOKABLE void back(); - - int currentPage() const; - QPointF currentLocation() const; - qreal currentZoom() const; - - bool backAvailable() const; - bool forwardAvailable() const; - -Q_SIGNALS: - void currentPageChanged(); - void currentLocationChanged(); - void currentZoomChanged(); - void backAvailableChanged(); - void forwardAvailableChanged(); - void jumped(int page, QPointF location, qreal zoom); - -private: - QVector<QExplicitlySharedDataPointer<QPdfDestinationPrivate>> m_pageHistory; - int m_currentHistoryIndex = 0; - bool m_changing = false; - - Q_DISABLE_COPY(QQuickPdfNavigationStack) -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QQuickPdfNavigationStack) - -#endif // QQUICKPDFNAVIGATIONSTACK_P_H diff --git a/src/pdf/quick/qquickpdfsearchmodel.cpp b/src/pdf/quick/qquickpdfsearchmodel.cpp deleted file mode 100644 index 1f62fbad0..000000000 --- a/src/pdf/quick/qquickpdfsearchmodel.cpp +++ /dev/null @@ -1,301 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qquickpdfsearchmodel_p.h" -#include <QtCore/qloggingcategory.h> - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(qLcS, "qt.pdf.search") - -/*! - \qmltype PdfSearchModel - \instantiates QQuickPdfSearchModel - \inqmlmodule QtQuick.Pdf - \ingroup pdf - \brief A representation of text search results within a PDF Document. - \since 5.15 - - PdfSearchModel provides the ability to search for text strings within a - document and get the geometric locations of matches on each page. -*/ - -QQuickPdfSearchModel::QQuickPdfSearchModel(QObject *parent) - : QPdfSearchModel(parent) -{ - connect(this, &QPdfSearchModel::searchStringChanged, - this, &QQuickPdfSearchModel::onResultsChanged); -} - -QQuickPdfDocument *QQuickPdfSearchModel::document() const -{ - return m_quickDocument; -} - -void QQuickPdfSearchModel::setDocument(QQuickPdfDocument *document) -{ - if (document == m_quickDocument || !document) - return; - - m_quickDocument = document; - QPdfSearchModel::setDocument(&document->m_doc); -} - -/*! - \qmlproperty list<list<point>> PdfSearchModel::currentResultBoundingPolygons - - A set of paths in a form that can be bound to the \c paths property of a - \l {QtQuick::PathMultiline}{PathMultiline} instance to render a batch of - rectangles around the regions comprising the search result \l currentResult - on \l currentPage. This is normally used to highlight one search result - at a time, in a UI that allows stepping through the results: - - \qml - PdfDocument { - id: doc - } - PdfSearchModel { - id: searchModel - document: doc - currentPage: view.currentPage - currentResult: ... - } - Shape { - ShapePath { - PathMultiline { - paths: searchModel.currentResultBoundingPolygons - } - } - } - \endqml - - \sa PathMultiline -*/ -QVector<QPolygonF> QQuickPdfSearchModel::currentResultBoundingPolygons() const -{ - QVector<QPolygonF> ret; - const auto &results = const_cast<QQuickPdfSearchModel *>(this)->resultsOnPage(m_currentPage); - if (m_currentResult < 0 || m_currentResult >= results.count()) - return ret; - const auto result = results[m_currentResult]; - for (auto rect : result.rectangles()) - ret << QPolygonF(rect); - return ret; -} - -/*! - \qmlproperty point PdfSearchModel::currentResultBoundingRect - - The bounding box containing all \l currentResultBoundingPolygons. - - When this property changes, a scrollable view should automatically scroll - itself in such a way as to ensure that this region is visible; for example, - it could try to position the upper-left corner near the upper-left of its - own viewport, subject to the constraints of the scrollable area. -*/ -QRectF QQuickPdfSearchModel::currentResultBoundingRect() const -{ - QRectF ret; - const auto &results = const_cast<QQuickPdfSearchModel *>(this)->resultsOnPage(m_currentPage); - if (m_currentResult < 0 || m_currentResult >= results.count()) - return ret; - auto rects = results[m_currentResult].rectangles(); - ret = rects.takeFirst(); - for (auto rect : rects) - ret = ret.united(rect); - return ret; -} - -void QQuickPdfSearchModel::onResultsChanged() -{ - emit currentPageBoundingPolygonsChanged(); - emit currentResultBoundingPolygonsChanged(); -} - -/*! - \qmlproperty list<list<point>> PdfSearchModel::currentPageBoundingPolygons - - A set of paths in a form that can be bound to the \c paths property of a - \l {QtQuick::PathMultiline}{PathMultiline} instance to render a batch of - rectangles around all the regions where search results are found on - \l currentPage: - - \qml - PdfDocument { - id: doc - } - PdfSearchModel { - id: searchModel - document: doc - } - Shape { - ShapePath { - PathMultiline { - paths: searchModel.matchGeometry(view.currentPage) - } - } - } - \endqml - - \sa PathMultiline -*/ -QVector<QPolygonF> QQuickPdfSearchModel::currentPageBoundingPolygons() const -{ - return const_cast<QQuickPdfSearchModel *>(this)->boundingPolygonsOnPage(m_currentPage); -} - -/*! - \qmlfunction list<list<point>> PdfSearchModel::boundingPolygonsOnPage(int page) - - Returns a set of paths in a form that can be bound to the \c paths property of a - \l {QtQuick::PathMultiline}{PathMultiline} instance to render a batch of - rectangles around all the locations where search results are found: - - \qml - PdfDocument { - id: doc - } - PdfSearchModel { - id: searchModel - document: doc - } - Shape { - ShapePath { - PathMultiline { - paths: searchModel.matchGeometry(view.currentPage) - } - } - } - \endqml - - \sa PathMultiline -*/ -QVector<QPolygonF> QQuickPdfSearchModel::boundingPolygonsOnPage(int page) -{ - if (!document() || searchString().isEmpty() || page < 0 || page > document()->pageCount()) - return {}; - - updatePage(page); - - QVector<QPolygonF> ret; - auto m = QPdfSearchModel::resultsOnPage(page); - for (auto result : m) { - for (auto rect : result.rectangles()) - ret << QPolygonF(rect); - } - - return ret; -} - -/*! - \qmlproperty int PdfSearchModel::currentPage - - The page on which \l currentMatchGeometry should provide filtered search results. -*/ -void QQuickPdfSearchModel::setCurrentPage(int currentPage) -{ - if (m_currentPage == currentPage) - return; - - if (currentPage < 0) - currentPage = document()->pageCount() - 1; - else if (currentPage >= document()->pageCount()) - currentPage = 0; - - m_currentPage = currentPage; - if (!m_suspendSignals) { - emit currentPageChanged(); - onResultsChanged(); - } -} - -/*! - \qmlproperty int PdfSearchModel::currentResult - - The result index on \l currentPage for which \l currentResultBoundingPolygons - should provide the regions to highlight. -*/ -void QQuickPdfSearchModel::setCurrentResult(int currentResult) -{ - if (m_currentResult == currentResult) - return; - - int currentResultWas = currentResult; - int currentPageWas = m_currentPage; - if (currentResult < 0) { - setCurrentPage(m_currentPage - 1); - while (resultsOnPage(m_currentPage).count() == 0 && m_currentPage != currentPageWas) { - m_suspendSignals = true; - setCurrentPage(m_currentPage - 1); - } - if (m_suspendSignals) { - emit currentPageChanged(); - m_suspendSignals = false; - } - const auto results = resultsOnPage(m_currentPage); - currentResult = results.count() - 1; - } else { - const auto results = resultsOnPage(m_currentPage); - if (currentResult >= results.count()) { - setCurrentPage(m_currentPage + 1); - while (resultsOnPage(m_currentPage).count() == 0 && m_currentPage != currentPageWas) { - m_suspendSignals = true; - setCurrentPage(m_currentPage + 1); - } - if (m_suspendSignals) { - emit currentPageChanged(); - m_suspendSignals = false; - } - currentResult = 0; - } - } - qCDebug(qLcS) << "currentResult was" << m_currentResult - << "requested" << currentResultWas << "on page" << currentPageWas - << "->" << currentResult << "on page" << m_currentPage; - - m_currentResult = currentResult; - emit currentResultChanged(); - emit currentResultBoundingPolygonsChanged(); - emit currentResultBoundingRectChanged(); -} - -/*! - \qmlproperty string PdfSearchModel::searchString - - The string to search for. -*/ - -QT_END_NAMESPACE diff --git a/src/pdf/quick/qquickpdfsearchmodel_p.h b/src/pdf/quick/qquickpdfsearchmodel_p.h deleted file mode 100644 index 66fc583d9..000000000 --- a/src/pdf/quick/qquickpdfsearchmodel_p.h +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQUICKPDFSEARCHMODEL_P_H -#define QQUICKPDFSEARCHMODEL_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 "qquickpdfdocument_p.h" -#include "../api/qpdfsearchmodel.h" - -#include <QtCore/qvariant.h> -#include <QtQml/qqml.h> - -QT_BEGIN_NAMESPACE - -class QQuickPdfSearchModel : public QPdfSearchModel -{ - Q_OBJECT - Q_PROPERTY(QQuickPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged) - Q_PROPERTY(int currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged) - Q_PROPERTY(int currentResult READ currentResult WRITE setCurrentResult NOTIFY currentResultChanged) - Q_PROPERTY(QVector<QPolygonF> currentPageBoundingPolygons READ currentPageBoundingPolygons NOTIFY currentPageBoundingPolygonsChanged) - Q_PROPERTY(QVector<QPolygonF> currentResultBoundingPolygons READ currentResultBoundingPolygons NOTIFY currentResultBoundingPolygonsChanged) - Q_PROPERTY(QRectF currentResultBoundingRect READ currentResultBoundingRect NOTIFY currentResultBoundingRectChanged) - -public: - explicit QQuickPdfSearchModel(QObject *parent = nullptr); - - QQuickPdfDocument *document() const; - void setDocument(QQuickPdfDocument * document); - - Q_INVOKABLE QVector<QPolygonF> boundingPolygonsOnPage(int page); - - int currentPage() const { return m_currentPage; } - void setCurrentPage(int currentPage); - - int currentResult() const { return m_currentResult; } - void setCurrentResult(int currentResult); - - QVector<QPolygonF> currentPageBoundingPolygons() const; - QVector<QPolygonF> currentResultBoundingPolygons() const; - QRectF currentResultBoundingRect() const; - -signals: - void documentChanged(); - void currentPageChanged(); - void currentResultChanged(); - void currentPageBoundingPolygonsChanged(); - void currentResultBoundingPolygonsChanged(); - void currentResultBoundingRectChanged(); - -private: - void updateResults(); - void onResultsChanged(); - -private: - QQuickPdfDocument *m_quickDocument = nullptr; - int m_currentPage = 0; - int m_currentResult = 0; - bool m_suspendSignals = false; - - Q_DISABLE_COPY(QQuickPdfSearchModel) -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QQuickPdfSearchModel) -QML_DECLARE_TYPE(QPdfSelection) - -#endif // QQUICKPDFSEARCHMODEL_P_H diff --git a/src/pdf/quick/qquickpdfselection.cpp b/src/pdf/quick/qquickpdfselection.cpp deleted file mode 100644 index 23fbb80b9..000000000 --- a/src/pdf/quick/qquickpdfselection.cpp +++ /dev/null @@ -1,541 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qquickpdfselection_p.h" -#include "qquickpdfdocument_p.h" -#include <QClipboard> -#include <QGuiApplication> -#include <QLoggingCategory> -#include <QQuickItem> -#include <QQmlEngine> -#include <QRegularExpression> -#include <QStandardPaths> -#include <QtPdf/private/qpdfdocument_p.h> - -Q_LOGGING_CATEGORY(qLcIm, "qt.pdf.im") - -QT_BEGIN_NAMESPACE - -static const QRegularExpression WordDelimiter("\\s"); - -/*! - \qmltype PdfSelection - \instantiates QQuickPdfSelection - \inqmlmodule QtQuick.Pdf - \ingroup pdf - \brief A representation of a text selection within a PDF Document. - \since 5.15 - - PdfSelection provides the text string and its geometry within a bounding box - from one point to another. - - To modify the selection using the mouse, bind \l fromPoint and \l toPoint - to the suitable properties of an input handler so that they will be set to - the positions where the drag gesture begins and ends, respectively; and - bind the \l hold property so that it will be set to \c true during the drag - gesture and \c false when the gesture ends. - - PdfSelection also directly handles Input Method queries so that text - selection handles can be used on platforms such as iOS. For this purpose, - it must have keyboard focus. -*/ - -/*! - Constructs a SearchModel. -*/ -QQuickPdfSelection::QQuickPdfSelection(QQuickItem *parent) - : QQuickItem(parent) -{ -#if QT_CONFIG(im) - setFlags(ItemIsFocusScope | ItemAcceptsInputMethod); - // workaround to get Copy instead of Paste on the popover menu (QTBUG-83811) - setProperty("qt_im_readonly", QVariant(true)); -#endif -} - -QQuickPdfDocument *QQuickPdfSelection::document() const -{ - return m_document; -} - -void QQuickPdfSelection::setDocument(QQuickPdfDocument *document) -{ - if (m_document == document) - return; - - if (m_document) { - disconnect(m_document, &QQuickPdfDocument::sourceChanged, - this, &QQuickPdfSelection::resetPoints); - } - m_document = document; - emit documentChanged(); - resetPoints(); - connect(m_document, &QQuickPdfDocument::sourceChanged, - this, &QQuickPdfSelection::resetPoints); -} - -/*! - \qmlproperty list<list<point>> PdfSelection::geometry - - A set of paths in a form that can be bound to the \c paths property of a - \l {QtQuick::PathMultiline}{PathMultiline} instance to render a batch of - rectangles around the text regions that are included in the selection: - - \qml - PdfDocument { - id: doc - } - PdfSelection { - id: selection - document: doc - fromPoint: textSelectionDrag.centroid.pressPosition - toPoint: textSelectionDrag.centroid.position - hold: !textSelectionDrag.active - } - Shape { - ShapePath { - PathMultiline { - paths: selection.geometry - } - } - } - DragHandler { - id: textSelectionDrag - acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus - target: null - } - \endqml - - \sa PathMultiline -*/ -QVector<QPolygonF> QQuickPdfSelection::geometry() const -{ - return m_geometry; -} - -void QQuickPdfSelection::clear() -{ - m_hitPoint = QPointF(); - m_fromPoint = QPointF(); - m_toPoint = QPointF(); - m_heightAtAnchor = 0; - m_heightAtCursor = 0; - m_fromCharIndex = -1; - m_toCharIndex = -1; - m_text.clear(); - m_geometry.clear(); - emit fromPointChanged(); - emit toPointChanged(); - emit textChanged(); - emit selectedAreaChanged(); - QGuiApplication::inputMethod()->update(Qt::ImQueryInput); -} - -void QQuickPdfSelection::selectAll() -{ - QPdfSelection sel = m_document->m_doc.getAllText(m_page); - if (sel.text() != m_text) { - m_text = sel.text(); - if (QGuiApplication::clipboard()->supportsSelection()) - sel.copyToClipboard(QClipboard::Selection); - emit textChanged(); - } - - if (sel.bounds() != m_geometry) { - m_geometry = sel.bounds(); - emit selectedAreaChanged(); - } -#if QT_CONFIG(im) - m_fromCharIndex = sel.startIndex(); - m_toCharIndex = sel.endIndex(); - if (sel.bounds().isEmpty()) { - m_fromPoint = QPointF(); - m_toPoint = QPointF(); - } else { - m_fromPoint = sel.bounds().first().boundingRect().topLeft() * m_renderScale; - m_toPoint = sel.bounds().last().boundingRect().bottomRight() * m_renderScale - QPointF(0, m_heightAtCursor); - } - - QGuiApplication::inputMethod()->update(Qt::ImCursorRectangle | Qt::ImAnchorRectangle); -#endif -} - -#if QT_CONFIG(im) -void QQuickPdfSelection::keyReleaseEvent(QKeyEvent *ev) -{ - qCDebug(qLcIm) << "release" << ev; - const auto &allText = pageText(); - if (ev == QKeySequence::MoveToPreviousWord) { - // iOS sends MoveToPreviousWord first to get to the beginning of the word, - // and then SelectNextWord to select the whole word. - int i = allText.lastIndexOf(WordDelimiter, m_fromCharIndex - allText.length()); - if (i < 0) - i = 0; - else - i += 1; // don't select the space before the word - auto sel = m_document->m_doc.getSelectionAtIndex(m_page, i, m_text.length() + m_fromCharIndex - i); - update(sel); - QGuiApplication::inputMethod()->update(Qt::ImAnchorRectangle); - } else if (ev == QKeySequence::SelectNextWord) { - int i = allText.indexOf(WordDelimiter, m_toCharIndex); - if (i < 0) - i = allText.length(); // go to the end of m_textAfter - auto sel = m_document->m_doc.getSelectionAtIndex(m_page, m_fromCharIndex, m_text.length() + i - m_toCharIndex); - update(sel); - QGuiApplication::inputMethod()->update(Qt::ImCursorRectangle); - } else if (ev == QKeySequence::Copy) { - copyToClipboard(); - } -} - -void QQuickPdfSelection::inputMethodEvent(QInputMethodEvent *event) -{ - for (auto attr : event->attributes()) { - switch (attr.type) { - case QInputMethodEvent::Cursor: - qCDebug(qLcIm) << "QInputMethodEvent::Cursor: moved to" << attr.start << "len" << attr.length; - break; - case QInputMethodEvent::Selection: { - auto sel = m_document->m_doc.getSelectionAtIndex(m_page, attr.start, attr.length); - update(sel); - qCDebug(qLcIm) << "QInputMethodEvent::Selection: from" << attr.start << "len" << attr.length - << "result:" << m_fromCharIndex << "->" << m_toCharIndex << sel.boundingRectangle(); - // the iOS plugin decided that it wanted to change the selection, but still has to be told to move the handles (!?) - QGuiApplication::inputMethod()->update(Qt::ImCursorRectangle | Qt::ImAnchorRectangle); - break; - } - case QInputMethodEvent::Language: - case QInputMethodEvent::Ruby: - case QInputMethodEvent::TextFormat: - break; - } - } -} - -QVariant QQuickPdfSelection::inputMethodQuery(Qt::InputMethodQuery query, const QVariant &argument) const -{ - if (!argument.isNull()) { - qCDebug(qLcIm) << "IM query" << query << "with arg" << argument; - if (query == Qt::ImCursorPosition) { - // If it didn't move since last time, return the same result. - if (m_hitPoint == argument.toPointF()) - return inputMethodQuery(query); - m_hitPoint = argument.toPointF(); - auto tp = m_document->m_doc.d->hitTest(m_page, m_hitPoint / m_renderScale); - qCDebug(qLcIm) << "ImCursorPosition hit testing in px" << m_hitPoint << "pt" << (m_hitPoint / m_renderScale) - << "got char index" << tp.charIndex << "@" << tp.position << "pt," << tp.position * m_renderScale << "px"; - if (tp.charIndex >= 0) { - m_toCharIndex = tp.charIndex; - m_toPoint = tp.position * m_renderScale - QPointF(0, m_heightAtCursor); - m_heightAtCursor = tp.height * m_renderScale; - if (qFuzzyIsNull(m_heightAtAnchor)) - m_heightAtAnchor = m_heightAtCursor; - } - } - } - return inputMethodQuery(query); -} - -QVariant QQuickPdfSelection::inputMethodQuery(Qt::InputMethodQuery query) const -{ - QVariant ret; - switch (query) { - case Qt::ImEnabled: - ret = true; - break; - case Qt::ImHints: - ret = QVariant(Qt::ImhMultiLine | Qt::ImhNoPredictiveText); - break; - case Qt::ImInputItemClipRectangle: - ret = boundingRect(); - break; - case Qt::ImAnchorPosition: - ret = m_fromCharIndex; - break; - case Qt::ImAbsolutePosition: - ret = m_toCharIndex; - break; - case Qt::ImCursorPosition: - ret = m_toCharIndex; - break; - case Qt::ImAnchorRectangle: - ret = QRectF(m_fromPoint, QSizeF(1, m_heightAtAnchor)); - break; - case Qt::ImCursorRectangle: - ret = QRectF(m_toPoint, QSizeF(1, m_heightAtCursor)); - break; - case Qt::ImSurroundingText: - ret = QVariant(pageText()); - break; - case Qt::ImTextBeforeCursor: - ret = QVariant(pageText().mid(0, m_toCharIndex)); - break; - case Qt::ImTextAfterCursor: - ret = QVariant(pageText().mid(m_toCharIndex)); - break; - case Qt::ImCurrentSelection: - ret = QVariant(m_text); - break; - case Qt::ImEnterKeyType: - break; - case Qt::ImFont: { - QFont font = QGuiApplication::font(); - font.setPointSizeF(m_heightAtCursor); - ret = font; - break; - } - case Qt::ImMaximumTextLength: - break; - case Qt::ImPreferredLanguage: - break; - case Qt::ImPlatformData: - break; - case Qt::ImQueryInput: - case Qt::ImQueryAll: - qWarning() << "unexpected composite query"; - break; - } - qCDebug(qLcIm) << "IM query" << query << "returns" << ret; - return ret; -} -#endif // QT_CONFIG(im) - -const QString &QQuickPdfSelection::pageText() const -{ - if (m_pageTextDirty) { - m_pageText = m_document->m_doc.getAllText(m_page).text(); - m_pageTextDirty = false; - } - return m_pageText; -} - -void QQuickPdfSelection::resetPoints() -{ - bool wasHolding = m_hold; - m_hold = false; - setFromPoint(QPointF()); - setToPoint(QPointF()); - m_hold = wasHolding; -} - -/*! - \qmlproperty int PdfSelection::page - - The page number on which to search. - - \sa QtQuick::Image::currentFrame -*/ -int QQuickPdfSelection::page() const -{ - return m_page; -} - -void QQuickPdfSelection::setPage(int page) -{ - if (m_page == page) - return; - - m_page = page; - m_pageTextDirty = true; - emit pageChanged(); - resetPoints(); -} - -/*! - \qmlproperty real PdfSelection::renderScale - \brief The ratio from points to pixels at which the page is rendered. - - This is used to scale \l fromPoint and \l toPoint to find ranges of - selected characters in the document, because positions within the document - are always given in points. -*/ -qreal QQuickPdfSelection::renderScale() const -{ - return m_renderScale; -} - -void QQuickPdfSelection::setRenderScale(qreal scale) -{ - if (qFuzzyCompare(scale, m_renderScale)) - return; - - m_renderScale = scale; - emit renderScaleChanged(); - updateResults(); -} - -/*! - \qmlproperty point PdfSelection::fromPoint - - The beginning location, in pixels from the upper-left corner of the page, - from which to find selected text. This can be bound to the - \c centroid.pressPosition of a \l DragHandler to begin selecting text from - the position where the user presses the mouse button and begins dragging, - for example. -*/ -QPointF QQuickPdfSelection::fromPoint() const -{ - return m_fromPoint; -} - -void QQuickPdfSelection::setFromPoint(QPointF fromPoint) -{ - if (m_hold || m_fromPoint == fromPoint) - return; - - m_fromPoint = fromPoint; - emit fromPointChanged(); - updateResults(); -} - -/*! - \qmlproperty point PdfSelection::toPoint - - The ending location, in pixels from the upper-left corner of the page, - from which to find selected text. This can be bound to the - \c centroid.position of a \l DragHandler to end selection of text at the - position where the user is currently dragging the mouse, for example. -*/ -QPointF QQuickPdfSelection::toPoint() const -{ - return m_toPoint; -} - -void QQuickPdfSelection::setToPoint(QPointF toPoint) -{ - if (m_hold || m_toPoint == toPoint) - return; - - m_toPoint = toPoint; - emit toPointChanged(); - updateResults(); -} - -/*! - \qmlproperty bool PdfSelection::hold - - Controls whether to hold the existing selection regardless of changes to - \l fromPoint and \l toPoint. This property can be set to \c true when the mouse - or touchpoint is released, so that the selection is not lost due to the - point bindings changing. -*/ -bool QQuickPdfSelection::hold() const -{ - return m_hold; -} - -void QQuickPdfSelection::setHold(bool hold) -{ - if (m_hold == hold) - return; - - m_hold = hold; - emit holdChanged(); -} - -/*! - \qmlproperty string PdfSelection::string - - The string found. -*/ -QString QQuickPdfSelection::text() const -{ - return m_text; -} - -#if QT_CONFIG(clipboard) -/*! - \qmlmethod void PdfSelection::copyToClipboard() - - Copies plain text from the \l string property to the system clipboard. -*/ -void QQuickPdfSelection::copyToClipboard() const -{ - QGuiApplication::clipboard()->setText(m_text); -} -#endif - -void QQuickPdfSelection::updateResults() -{ - if (!m_document) - return; - QPdfSelection sel = m_document->document().getSelection(m_page, - m_fromPoint / m_renderScale, m_toPoint / m_renderScale); - update(sel, true); -} - -void QQuickPdfSelection::update(const QPdfSelection &sel, bool textAndGeometryOnly) -{ - if (sel.text() != m_text) { - m_text = sel.text(); - if (QGuiApplication::clipboard()->supportsSelection()) - sel.copyToClipboard(QClipboard::Selection); - emit textChanged(); - } - - if (sel.bounds() != m_geometry) { - m_geometry = sel.bounds(); - emit selectedAreaChanged(); - } - - if (textAndGeometryOnly) - return; - - m_fromCharIndex = sel.startIndex(); - m_toCharIndex = sel.endIndex(); - if (sel.bounds().isEmpty()) { - m_fromPoint = sel.boundingRectangle().topLeft() * m_renderScale; - m_toPoint = m_fromPoint; - } else { - Qt::InputMethodQueries toUpdate = {}; - QRectF firstLineBounds = sel.bounds().first().boundingRect(); - m_fromPoint = firstLineBounds.topLeft() * m_renderScale; - if (!qFuzzyCompare(m_heightAtAnchor, firstLineBounds.height())) { - m_heightAtAnchor = firstLineBounds.height() * m_renderScale; - toUpdate.setFlag(Qt::ImAnchorRectangle); - } - QRectF lastLineBounds = sel.bounds().last().boundingRect(); - if (!qFuzzyCompare(m_heightAtCursor, lastLineBounds.height())) { - m_heightAtCursor = lastLineBounds.height() * m_renderScale; - toUpdate.setFlag(Qt::ImCursorRectangle); - } - m_toPoint = lastLineBounds.topRight() * m_renderScale; - if (toUpdate) - QGuiApplication::inputMethod()->update(toUpdate); - } -} - -QT_END_NAMESPACE diff --git a/src/pdf/quick/qquickpdfselection_p.h b/src/pdf/quick/qquickpdfselection_p.h deleted file mode 100644 index fb5b2901b..000000000 --- a/src/pdf/quick/qquickpdfselection_p.h +++ /dev/null @@ -1,148 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQUICKPDFSELECTION_P_H -#define QQUICKPDFSELECTION_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 <QPointF> -#include <QPolygonF> -#include <QVariant> -#include <QtQml/qqml.h> -#include <QtQuick/qquickitem.h> - -QT_BEGIN_NAMESPACE - -class QPdfSelection; -class QQuickPdfDocument; - -class QQuickPdfSelection : public QQuickItem -{ - Q_OBJECT - Q_PROPERTY(QQuickPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged) - Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged) - Q_PROPERTY(qreal renderScale READ renderScale WRITE setRenderScale NOTIFY renderScaleChanged) - Q_PROPERTY(QPointF fromPoint READ fromPoint WRITE setFromPoint NOTIFY fromPointChanged) - Q_PROPERTY(QPointF toPoint READ toPoint WRITE setToPoint NOTIFY toPointChanged) - Q_PROPERTY(bool hold READ hold WRITE setHold NOTIFY holdChanged) - - Q_PROPERTY(QString text READ text NOTIFY textChanged) - Q_PROPERTY(QVector<QPolygonF> geometry READ geometry NOTIFY selectedAreaChanged) - -public: - explicit QQuickPdfSelection(QQuickItem *parent = nullptr); - - QQuickPdfDocument *document() const; - void setDocument(QQuickPdfDocument * document); - int page() const; - void setPage(int page); - qreal renderScale() const; - void setRenderScale(qreal scale); - QPointF fromPoint() const; - void setFromPoint(QPointF fromPoint); - QPointF toPoint() const; - void setToPoint(QPointF toPoint); - bool hold() const; - void setHold(bool hold); - - QString text() const; - QVector<QPolygonF> geometry() const; - - Q_INVOKABLE void clear(); - Q_INVOKABLE void selectAll(); -#if QT_CONFIG(clipboard) - Q_INVOKABLE void copyToClipboard() const; -#endif - -signals: - void documentChanged(); - void pageChanged(); - void renderScaleChanged(); - void fromPointChanged(); - void toPointChanged(); - void holdChanged(); - void textChanged(); - void selectedAreaChanged(); - -protected: -#if QT_CONFIG(im) - void keyReleaseEvent(QKeyEvent *ev) override; - void inputMethodEvent(QInputMethodEvent *event) override; - Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, const QVariant &argument) const; - QVariant inputMethodQuery(Qt::InputMethodQuery query) const override; -#endif - -private: - void resetPoints(); - void updateResults(); - void update(const QPdfSelection &sel, bool textAndGeometryOnly = false); - const QString &pageText() const; - -private: - QQuickPdfDocument *m_document = nullptr; - mutable QPointF m_hitPoint; - QPointF m_fromPoint; - mutable QPointF m_toPoint; - qreal m_renderScale = 1; - mutable qreal m_heightAtAnchor = 0; - mutable qreal m_heightAtCursor = 0; - QString m_text; // selected text - mutable QString m_pageText; // all text on the page - QVector<QPolygonF> m_geometry; - int m_page = 0; - int m_fromCharIndex = -1; // same as anchor position - mutable int m_toCharIndex = -1; // same as cursor position - bool m_hold = false; - mutable bool m_pageTextDirty = true; - - Q_DISABLE_COPY(QQuickPdfSelection) -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QQuickPdfSelection) - -#endif // QQUICKPDFSELECTION_P_H diff --git a/src/pdf/quick/qquicktableviewextra.cpp b/src/pdf/quick/qquicktableviewextra.cpp deleted file mode 100644 index 601dfff7b..000000000 --- a/src/pdf/quick/qquicktableviewextra.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qquicktableviewextra_p.h" -#include <QtQml> -#include <QQmlContext> -#include <QtQuick/private/qquicktableview_p.h> - -Q_LOGGING_CATEGORY(qLcTVE, "qt.pdf.tableextra") - -QT_BEGIN_NAMESPACE - -/*! - \internal - \qmltype TableViewExtra - \instantiates QQuickTableViewExtra - \inqmlmodule QtQuick.Pdf - \ingroup pdf - \brief A helper class with missing TableView functions - \since 5.15 - - TableViewExtra provides equivalents for some functions that will be added - to TableView in Qt 6. -*/ - -QQuickTableViewExtra::QQuickTableViewExtra(QObject *parent) : QObject(parent) -{ -} - -QPoint QQuickTableViewExtra::cellAtPos(qreal x, qreal y) const -{ - QPointF position(x, y); -#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) - return m_tableView->cellAtPos(position); -#else - if (!m_tableView->boundingRect().contains(position)) - return QPoint(-1, -1); - - const QQuickItem *contentItem = m_tableView->contentItem(); - - for (const QQuickItem *child : contentItem->childItems()) { - const QPointF posInChild = m_tableView->mapToItem(child, position); - if (child->boundingRect().contains(posInChild)) { - const auto context = qmlContext(child); - const int column = context->contextProperty("column").toInt(); - const int row = context->contextProperty("row").toInt(); - return QPoint(column, row); - } - } - - return QPoint(-1, -1); -#endif -} - -QQuickItem *QQuickTableViewExtra::itemAtCell(const QPoint &cell) const -{ -#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) - return m_tableView->itemAtCell(cell); -#else - const QQuickItem *contentItem = m_tableView->contentItem(); - - for (QQuickItem *child : contentItem->childItems()) { - const auto context = qmlContext(child); - const int column = context->contextProperty("column").toInt(); - const int row = context->contextProperty("row").toInt(); - if (QPoint(column, row) == cell) - return child; - } - - return nullptr; -#endif -} - -void QQuickTableViewExtra::positionViewAtCell(const QPoint &cell, Qt::Alignment alignment, const QPointF &offset) -{ -#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) - m_tableView->positionViewAtCell(cell, alignment, offset); -#else - // Note: this fallback implementation assumes all cells to be of the same size! - - if (cell.x() < 0 || cell.x() > m_tableView->columns() - 1) - return; - if (cell.y() < 0 || cell.y() > m_tableView->rows() - 1) - return; - - Qt::Alignment verticalAlignment = alignment & (Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom); - Qt::Alignment horizontalAlignment = alignment & (Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight); - - const QQuickItem *contentItem = m_tableView->contentItem(); - const QQuickItem *randomChild = contentItem->childItems().first(); - const qreal cellWidth = randomChild->width(); - const qreal cellHeight = randomChild->height(); - - if (!verticalAlignment && !horizontalAlignment) { - qmlWarning(this) << "No valid alignment specified"; - return; - } - - if (horizontalAlignment) { - qreal newPosX = 0; - const qreal columnPosLeft = int(cell.x() * (cellWidth + m_tableView->columnSpacing())); - m_tableView->setContentX(0); - m_tableView->forceLayout(); - m_tableView->setContentX(columnPosLeft); - m_tableView->forceLayout(); - - switch (horizontalAlignment) { - case Qt::AlignLeft: - newPosX = m_tableView->contentX() + offset.x(); - break; - case Qt::AlignHCenter: - newPosX = m_tableView->contentX() - - m_tableView->width() / 2 - + (cellWidth / 2) - + offset.x(); - break; - case Qt::AlignRight: - newPosX = m_tableView->contentX() - - m_tableView->width() - + cellWidth - + offset.x(); - break; - } - - m_tableView->setContentX(newPosX); - m_tableView->forceLayout(); - } - - if (verticalAlignment) { - qreal newPosY = 0; - const qreal rowPosTop = int(cell.y() * (cellHeight + m_tableView->rowSpacing())); - m_tableView->setContentY(0); - m_tableView->forceLayout(); - m_tableView->setContentY(rowPosTop); - m_tableView->forceLayout(); - - switch (verticalAlignment) { - case Qt::AlignTop: - newPosY = m_tableView->contentY() + offset.y(); - break; - case Qt::AlignVCenter: - newPosY = m_tableView->contentY() - - m_tableView->height() / 2 - + (cellHeight / 2) - + offset.y(); - break; - case Qt::AlignBottom: - newPosY = m_tableView->contentY() - - m_tableView->height() - + cellHeight - + offset.y(); - break; - } - - m_tableView->setContentY(newPosY); - m_tableView->forceLayout(); - } -#endif -} - -QT_END_NAMESPACE diff --git a/src/pdf/quick/qquicktableviewextra_p.h b/src/pdf/quick/qquicktableviewextra_p.h deleted file mode 100644 index cd3035be5..000000000 --- a/src/pdf/quick/qquicktableviewextra_p.h +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQUICKTABLEVIEWEXTRA_P_H -#define QQUICKTABLEVIEWEXTRA_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 <QPointF> -#include <QPolygonF> -#include <QVariant> -#include <QtQml/qqml.h> -#include <QtQuick/qquickitem.h> - -QT_BEGIN_NAMESPACE - -class QQuickTableView; - -class QQuickTableViewExtra : public QObject -{ - Q_OBJECT - Q_PROPERTY(QQuickTableView *tableView READ tableView WRITE setTableView) - -public: - QQuickTableViewExtra(QObject *parent = nullptr); - - QQuickTableView * tableView() const { return m_tableView; } - void setTableView(QQuickTableView * tableView) { m_tableView = tableView; } - - Q_INVOKABLE QPoint cellAtPos(qreal x, qreal y) const; - Q_INVOKABLE QQuickItem *itemAtCell(int column, int row) const { - return itemAtCell(QPoint(column, row)); - } - Q_INVOKABLE QQuickItem *itemAtCell(const QPoint &cell) const; - Q_INVOKABLE void positionViewAtCell(int column, int row, Qt::Alignment alignment, const QPointF &offset = QPointF()) { - positionViewAtCell(QPoint(column, row), alignment, offset); - } - Q_INVOKABLE void positionViewAtCell(const QPoint &cell, Qt::Alignment alignment, const QPointF &offset); - Q_INVOKABLE void positionViewAtRow(int row, Qt::Alignment alignment, qreal offset = 0) { - positionViewAtCell(QPoint(0, row), alignment & Qt::AlignVertical_Mask, QPointF(0, offset)); - } - -private: - QQuickTableView *m_tableView = nullptr; -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QQuickTableViewExtra) - -#endif // QQUICKTABLEVIEWEXTRA_P_H diff --git a/src/pdf/quick/quick.pro b/src/pdf/quick/quick.pro deleted file mode 100644 index 47c559091..000000000 --- a/src/pdf/quick/quick.pro +++ /dev/null @@ -1,40 +0,0 @@ -CXX_MODULE = qml -TARGET = pdfplugin -TARGETPATH = QtQuick/Pdf -IMPORT_VERSION = 1.0 - -# qpdfdocument_p.h includes pdfium headers which we must find in order to use private API -CHROMIUM_SRC_DIR = $$QTWEBENGINE_ROOT/$$getChromiumSrcDir() -INCLUDEPATH += $$CHROMIUM_SRC_DIR - -#QMAKE_DOCS = $$PWD/doc/qtquickpdf.qdocconf - -PDF_QML_FILES = \ - qml/PdfMultiPageView.qml \ - qml/PdfPageView.qml \ - qml/PdfScrollablePageView.qml \ - -QML_FILES += $$PDF_QML_FILES qmldir - -RESOURCES += resources.qrc - -SOURCES += \ - plugin.cpp \ - qquickpdfdocument.cpp \ - qquickpdflinkmodel.cpp \ - qquickpdfnavigationstack.cpp \ - qquickpdfsearchmodel.cpp \ - qquickpdfselection.cpp \ - qquicktableviewextra.cpp \ - -HEADERS += \ - qquickpdfdocument_p.h \ - qquickpdflinkmodel_p.h \ - qquickpdfnavigationstack_p.h \ - qquickpdfsearchmodel_p.h \ - qquickpdfselection_p.h \ - qquicktableviewextra_p.h \ - -QT += pdf pdf-private gui core qml quick quick-private -include($${OUT_PWD}/../$$getConfigDir()/QtPdf_static_dep.pri) -load(qml_plugin) diff --git a/src/pdf/quick/resources.qrc b/src/pdf/quick/resources.qrc deleted file mode 100644 index 8270a2028..000000000 --- a/src/pdf/quick/resources.qrc +++ /dev/null @@ -1,10 +0,0 @@ -<RCC> - <qresource prefix="/qt-project.org/qtpdf"> - <file>qml/+material/PdfStyle.qml</file> - <file>qml/+universal/PdfStyle.qml</file> - <file>qml/PdfStyle.qml</file> - <file>qml/PdfMultiPageView.qml</file> - <file>qml/PdfPageView.qml</file> - <file>qml/PdfScrollablePageView.qml</file> - </qresource> -</RCC> |