07a311c4f6
The content of this branch was automatically imported from Fedora ELN with the following as its source: https://src.fedoraproject.org/rpms/poppler#f56209451f08744ff1ac5204dbd50e639598cd31
26571 lines
802 KiB
Diff
26571 lines
802 KiB
Diff
From 017d466e5d0895504fc8711f87806d3bd08d8416 Mon Sep 17 00:00:00 2001
|
|
From: David Tardon <dtardon@redhat.com>
|
|
Date: Thu, 8 Feb 2018 19:13:01 +0100
|
|
Subject: [PATCH] Revert "Remove the Qt4 frontend"
|
|
|
|
This reverts commit fb4c69d270a618bb23791e52f46ec73c86574294.
|
|
---
|
|
.gitignore | 2 +
|
|
CMakeLists.txt | 17 +
|
|
cmake/modules/FindQt4.cmake | 1311 +++++++
|
|
poppler-qt4.pc.cmake | 12 +
|
|
qt4/.gitignore | 4 +
|
|
qt4/CMakeLists.txt | 6 +
|
|
qt4/demos/.gitignore | 4 +
|
|
qt4/demos/CMakeLists.txt | 28 +
|
|
qt4/demos/abstractinfodock.cpp | 57 +
|
|
qt4/demos/abstractinfodock.h | 48 +
|
|
qt4/demos/documentobserver.cpp | 50 +
|
|
qt4/demos/documentobserver.h | 50 +
|
|
qt4/demos/embeddedfiles.cpp | 82 +
|
|
qt4/demos/embeddedfiles.h | 44 +
|
|
qt4/demos/fonts.cpp | 72 +
|
|
qt4/demos/fonts.h | 43 +
|
|
qt4/demos/info.cpp | 72 +
|
|
qt4/demos/info.h | 43 +
|
|
qt4/demos/main_viewer.cpp | 33 +
|
|
qt4/demos/metadata.cpp | 50 +
|
|
qt4/demos/metadata.h | 43 +
|
|
qt4/demos/navigationtoolbar.cpp | 144 +
|
|
qt4/demos/navigationtoolbar.h | 65 +
|
|
qt4/demos/optcontent.cpp | 69 +
|
|
qt4/demos/optcontent.h | 47 +
|
|
qt4/demos/pageview.cpp | 101 +
|
|
qt4/demos/pageview.h | 53 +
|
|
qt4/demos/permissions.cpp | 66 +
|
|
qt4/demos/permissions.h | 43 +
|
|
qt4/demos/thumbnails.cpp | 84 +
|
|
qt4/demos/thumbnails.h | 48 +
|
|
qt4/demos/toc.cpp | 88 +
|
|
qt4/demos/toc.h | 43 +
|
|
qt4/demos/viewer.cpp | 319 ++
|
|
qt4/demos/viewer.h | 73 +
|
|
qt4/src/.gitignore | 9 +
|
|
qt4/src/ArthurOutputDev.cc | 812 ++++
|
|
qt4/src/ArthurOutputDev.h | 170 +
|
|
qt4/src/CMakeLists.txt | 54 +
|
|
qt4/src/Doxyfile | 1637 +++++++++
|
|
qt4/src/Mainpage.dox | 85 +
|
|
qt4/src/poppler-annotation-helper.h | 181 +
|
|
qt4/src/poppler-annotation-private.h | 112 +
|
|
qt4/src/poppler-annotation.cc | 5089 ++++++++++++++++++++++++++
|
|
qt4/src/poppler-annotation.h | 1375 +++++++
|
|
qt4/src/poppler-base-converter.cc | 105 +
|
|
qt4/src/poppler-converter-private.h | 49 +
|
|
qt4/src/poppler-document.cc | 850 +++++
|
|
qt4/src/poppler-embeddedfile-private.h | 42 +
|
|
qt4/src/poppler-embeddedfile.cc | 135 +
|
|
qt4/src/poppler-export.h | 20 +
|
|
qt4/src/poppler-fontinfo.cc | 150 +
|
|
qt4/src/poppler-form.cc | 416 +++
|
|
qt4/src/poppler-form.h | 343 ++
|
|
qt4/src/poppler-link-extractor-private.h | 57 +
|
|
qt4/src/poppler-link-extractor.cc | 84 +
|
|
qt4/src/poppler-link-private.h | 57 +
|
|
qt4/src/poppler-link.cc | 710 ++++
|
|
qt4/src/poppler-link.h | 641 ++++
|
|
qt4/src/poppler-media.cc | 168 +
|
|
qt4/src/poppler-media.h | 100 +
|
|
qt4/src/poppler-movie.cc | 110 +
|
|
qt4/src/poppler-optcontent-private.h | 124 +
|
|
qt4/src/poppler-optcontent.cc | 456 +++
|
|
qt4/src/poppler-optcontent.h | 84 +
|
|
qt4/src/poppler-page-private.h | 57 +
|
|
qt4/src/poppler-page-transition-private.h | 28 +
|
|
qt4/src/poppler-page-transition.cc | 101 +
|
|
qt4/src/poppler-page-transition.h | 158 +
|
|
qt4/src/poppler-page.cc | 810 ++++
|
|
qt4/src/poppler-pdf-converter.cc | 115 +
|
|
qt4/src/poppler-private.cc | 296 ++
|
|
qt4/src/poppler-private.h | 241 ++
|
|
qt4/src/poppler-ps-converter.cc | 280 ++
|
|
qt4/src/poppler-qiodeviceoutstream-private.h | 47 +
|
|
qt4/src/poppler-qiodeviceoutstream.cc | 64 +
|
|
qt4/src/poppler-qt4.h | 1990 ++++++++++
|
|
qt4/src/poppler-sound.cc | 132 +
|
|
qt4/src/poppler-textbox.cc | 63 +
|
|
qt4/tests/.gitignore | 33 +
|
|
qt4/tests/CMakeLists.txt | 67 +
|
|
qt4/tests/README.unittest | 23 +
|
|
qt4/tests/check_actualtext.cpp | 33 +
|
|
qt4/tests/check_attachments.cpp | 157 +
|
|
qt4/tests/check_dateConversion.cpp | 142 +
|
|
qt4/tests/check_fonts.cpp | 248 ++
|
|
qt4/tests/check_goostring.cpp | 127 +
|
|
qt4/tests/check_lexer.cpp | 107 +
|
|
qt4/tests/check_links.cpp | 98 +
|
|
qt4/tests/check_metadata.cpp | 275 ++
|
|
qt4/tests/check_optcontent.cpp | 446 +++
|
|
qt4/tests/check_pagelabelinfo.cpp | 43 +
|
|
qt4/tests/check_pagelayout.cpp | 49 +
|
|
qt4/tests/check_pagemode.cpp | 73 +
|
|
qt4/tests/check_password.cpp | 88 +
|
|
qt4/tests/check_permissions.cpp | 44 +
|
|
qt4/tests/check_search.cpp | 175 +
|
|
qt4/tests/check_strings.cpp | 250 ++
|
|
qt4/tests/poppler-attachments.cpp | 39 +
|
|
qt4/tests/poppler-fonts.cpp | 89 +
|
|
qt4/tests/poppler-forms.cpp | 166 +
|
|
qt4/tests/poppler-texts.cpp | 40 +
|
|
qt4/tests/stress-poppler-dir.cpp | 67 +
|
|
qt4/tests/stress-poppler-qt4.cpp | 74 +
|
|
qt4/tests/stress-threads-qt4.cpp | 309 ++
|
|
qt4/tests/test-password-qt4.cpp | 136 +
|
|
qt4/tests/test-poppler-qt4.cpp | 235 ++
|
|
qt4/tests/test-render-to-file.cpp | 69 +
|
|
108 files changed, 25623 insertions(+)
|
|
create mode 100644 cmake/modules/FindQt4.cmake
|
|
create mode 100644 poppler-qt4.pc.cmake
|
|
create mode 100644 qt4/.gitignore
|
|
create mode 100644 qt4/CMakeLists.txt
|
|
create mode 100644 qt4/demos/.gitignore
|
|
create mode 100644 qt4/demos/CMakeLists.txt
|
|
create mode 100644 qt4/demos/abstractinfodock.cpp
|
|
create mode 100644 qt4/demos/abstractinfodock.h
|
|
create mode 100644 qt4/demos/documentobserver.cpp
|
|
create mode 100644 qt4/demos/documentobserver.h
|
|
create mode 100644 qt4/demos/embeddedfiles.cpp
|
|
create mode 100644 qt4/demos/embeddedfiles.h
|
|
create mode 100644 qt4/demos/fonts.cpp
|
|
create mode 100644 qt4/demos/fonts.h
|
|
create mode 100644 qt4/demos/info.cpp
|
|
create mode 100644 qt4/demos/info.h
|
|
create mode 100644 qt4/demos/main_viewer.cpp
|
|
create mode 100644 qt4/demos/metadata.cpp
|
|
create mode 100644 qt4/demos/metadata.h
|
|
create mode 100644 qt4/demos/navigationtoolbar.cpp
|
|
create mode 100644 qt4/demos/navigationtoolbar.h
|
|
create mode 100644 qt4/demos/optcontent.cpp
|
|
create mode 100644 qt4/demos/optcontent.h
|
|
create mode 100644 qt4/demos/pageview.cpp
|
|
create mode 100644 qt4/demos/pageview.h
|
|
create mode 100644 qt4/demos/permissions.cpp
|
|
create mode 100644 qt4/demos/permissions.h
|
|
create mode 100644 qt4/demos/thumbnails.cpp
|
|
create mode 100644 qt4/demos/thumbnails.h
|
|
create mode 100644 qt4/demos/toc.cpp
|
|
create mode 100644 qt4/demos/toc.h
|
|
create mode 100644 qt4/demos/viewer.cpp
|
|
create mode 100644 qt4/demos/viewer.h
|
|
create mode 100644 qt4/src/.gitignore
|
|
create mode 100644 qt4/src/ArthurOutputDev.cc
|
|
create mode 100644 qt4/src/ArthurOutputDev.h
|
|
create mode 100644 qt4/src/CMakeLists.txt
|
|
create mode 100644 qt4/src/Doxyfile
|
|
create mode 100644 qt4/src/Mainpage.dox
|
|
create mode 100644 qt4/src/poppler-annotation-helper.h
|
|
create mode 100644 qt4/src/poppler-annotation-private.h
|
|
create mode 100644 qt4/src/poppler-annotation.cc
|
|
create mode 100644 qt4/src/poppler-annotation.h
|
|
create mode 100644 qt4/src/poppler-base-converter.cc
|
|
create mode 100644 qt4/src/poppler-converter-private.h
|
|
create mode 100644 qt4/src/poppler-document.cc
|
|
create mode 100644 qt4/src/poppler-embeddedfile-private.h
|
|
create mode 100644 qt4/src/poppler-embeddedfile.cc
|
|
create mode 100644 qt4/src/poppler-export.h
|
|
create mode 100644 qt4/src/poppler-fontinfo.cc
|
|
create mode 100644 qt4/src/poppler-form.cc
|
|
create mode 100644 qt4/src/poppler-form.h
|
|
create mode 100644 qt4/src/poppler-link-extractor-private.h
|
|
create mode 100644 qt4/src/poppler-link-extractor.cc
|
|
create mode 100644 qt4/src/poppler-link-private.h
|
|
create mode 100644 qt4/src/poppler-link.cc
|
|
create mode 100644 qt4/src/poppler-link.h
|
|
create mode 100644 qt4/src/poppler-media.cc
|
|
create mode 100644 qt4/src/poppler-media.h
|
|
create mode 100644 qt4/src/poppler-movie.cc
|
|
create mode 100644 qt4/src/poppler-optcontent-private.h
|
|
create mode 100644 qt4/src/poppler-optcontent.cc
|
|
create mode 100644 qt4/src/poppler-optcontent.h
|
|
create mode 100644 qt4/src/poppler-page-private.h
|
|
create mode 100644 qt4/src/poppler-page-transition-private.h
|
|
create mode 100644 qt4/src/poppler-page-transition.cc
|
|
create mode 100644 qt4/src/poppler-page-transition.h
|
|
create mode 100644 qt4/src/poppler-page.cc
|
|
create mode 100644 qt4/src/poppler-pdf-converter.cc
|
|
create mode 100644 qt4/src/poppler-private.cc
|
|
create mode 100644 qt4/src/poppler-private.h
|
|
create mode 100644 qt4/src/poppler-ps-converter.cc
|
|
create mode 100644 qt4/src/poppler-qiodeviceoutstream-private.h
|
|
create mode 100644 qt4/src/poppler-qiodeviceoutstream.cc
|
|
create mode 100644 qt4/src/poppler-qt4.h
|
|
create mode 100644 qt4/src/poppler-sound.cc
|
|
create mode 100644 qt4/src/poppler-textbox.cc
|
|
create mode 100644 qt4/tests/.gitignore
|
|
create mode 100644 qt4/tests/CMakeLists.txt
|
|
create mode 100644 qt4/tests/README.unittest
|
|
create mode 100644 qt4/tests/check_actualtext.cpp
|
|
create mode 100644 qt4/tests/check_attachments.cpp
|
|
create mode 100644 qt4/tests/check_dateConversion.cpp
|
|
create mode 100644 qt4/tests/check_fonts.cpp
|
|
create mode 100644 qt4/tests/check_goostring.cpp
|
|
create mode 100644 qt4/tests/check_lexer.cpp
|
|
create mode 100644 qt4/tests/check_links.cpp
|
|
create mode 100644 qt4/tests/check_metadata.cpp
|
|
create mode 100644 qt4/tests/check_optcontent.cpp
|
|
create mode 100644 qt4/tests/check_pagelabelinfo.cpp
|
|
create mode 100644 qt4/tests/check_pagelayout.cpp
|
|
create mode 100644 qt4/tests/check_pagemode.cpp
|
|
create mode 100644 qt4/tests/check_password.cpp
|
|
create mode 100644 qt4/tests/check_permissions.cpp
|
|
create mode 100644 qt4/tests/check_search.cpp
|
|
create mode 100644 qt4/tests/check_strings.cpp
|
|
create mode 100644 qt4/tests/poppler-attachments.cpp
|
|
create mode 100644 qt4/tests/poppler-fonts.cpp
|
|
create mode 100644 qt4/tests/poppler-forms.cpp
|
|
create mode 100644 qt4/tests/poppler-texts.cpp
|
|
create mode 100644 qt4/tests/stress-poppler-dir.cpp
|
|
create mode 100644 qt4/tests/stress-poppler-qt4.cpp
|
|
create mode 100644 qt4/tests/stress-threads-qt4.cpp
|
|
create mode 100644 qt4/tests/test-password-qt4.cpp
|
|
create mode 100644 qt4/tests/test-poppler-qt4.cpp
|
|
create mode 100644 qt4/tests/test-render-to-file.cpp
|
|
|
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
|
index 5e3d6a17..431059fb 100644
|
|
--- a/CMakeLists.txt
|
|
+++ b/CMakeLists.txt
|
|
@@ -40,6 +40,7 @@ set (CMAKE_CXX_EXTENSIONS OFF)
|
|
# command line switches
|
|
option(ENABLE_UNSTABLE_API_ABI_HEADERS "Install API/ABI unstable xpdf headers." OFF)
|
|
option(BUILD_GTK_TESTS "Whether to compile the GTK+ test programs." ON)
|
|
+option(BUILD_QT4_TESTS "Whether to compile the Qt4 test programs." ON)
|
|
option(BUILD_QT5_TESTS "Whether to compile the Qt5 test programs." ON)
|
|
option(BUILD_CPP_TESTS "Whether to compile the CPP test programs." ON)
|
|
option(ENABLE_SPLASH "Build the Splash graphics backend." ON)
|
|
@@ -47,6 +48,7 @@ option(ENABLE_UTILS "Compile poppler command line utils." ON)
|
|
option(ENABLE_GLIB "Compile poppler glib wrapper." ON)
|
|
option(ENABLE_GOBJECT_INTROSPECTION "Whether to generate GObject introspection." ON)
|
|
option(ENABLE_GTK_DOC "Whether to generate glib API documentation." OFF)
|
|
+option(ENABLE_QT4 "Compile poppler qt4 wrapper." ON)
|
|
option(ENABLE_QT5 "Compile poppler qt5 wrapper." ON)
|
|
set(ENABLE_LIBOPENJPEG "openjpeg2" CACHE STRING "Use libopenjpeg for JPX streams. Possible values: openjpeg2, unmaintained, none. 'unmaintained' gives you the internal unmaintained decoder. Use at your own risk. 'none' compiles no JPX decoder at all. Default: openjpeg2")
|
|
set(ENABLE_CMS "lcms2" CACHE STRING "Use color management system. Possible values: lcms2, none. 'none' disables color management system.")
|
|
@@ -112,6 +114,7 @@ set(OPI_SUPPORT ON)
|
|
set(TEXTOUT_WORD_LIST ON)
|
|
|
|
# setting the minimum required versions for some components
|
|
+set(QT4_MIN_VERSION "4.7.0")
|
|
set(CAIRO_VERSION "1.10.0")
|
|
set(GLIB_REQUIRED "2.41")
|
|
|
|
@@ -141,6 +144,13 @@ else()
|
|
message(FATAL_ERROR "Invalid ENABLE_DCTDECODER value.")
|
|
endif()
|
|
|
|
+if (ENABLE_QT4)
|
|
+ macro_optional_find_package(Qt4)
|
|
+ if (NOT QT4_FOUND)
|
|
+ set(ENABLE_QT4 OFF)
|
|
+ endif()
|
|
+endif()
|
|
+
|
|
if (ENABLE_QT5)
|
|
find_package(Qt5Core 5.5) # Update QT_DISABLE_DEPRECATED_BEFORE in qt5/CMakeLists.txt when increasing this
|
|
find_package(Qt5Gui)
|
|
@@ -661,6 +671,9 @@ if(ENABLE_GLIB)
|
|
add_subdirectory(glib)
|
|
endif()
|
|
add_subdirectory(test)
|
|
+if(ENABLE_QT4)
|
|
+ add_subdirectory(qt4)
|
|
+endif()
|
|
if(ENABLE_QT5)
|
|
add_subdirectory(qt5)
|
|
endif()
|
|
@@ -685,6 +698,9 @@ poppler_create_install_pkgconfig(poppler.pc ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
|
if(ENABLE_SPLASH)
|
|
poppler_create_install_pkgconfig(poppler-splash.pc ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
|
endif()
|
|
+ if(ENABLE_QT4)
|
|
+ poppler_create_install_pkgconfig(poppler-qt4.pc ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
|
+ endif()
|
|
if(ENABLE_QT5)
|
|
poppler_create_install_pkgconfig(poppler-qt5.pc ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
|
endif()
|
|
@@ -706,6 +722,7 @@ if(SPLASH_CMYK)
|
|
show_end_message("font configuration" ${font_configuration})
|
|
show_end_message_yesno("splash output" ENABLE_SPLASH)
|
|
show_end_message_yesno("cairo output" CAIRO_FOUND)
|
|
+show_end_message_yesno("qt4 wrapper" ENABLE_QT4)
|
|
show_end_message_yesno("qt5 wrapper" ENABLE_QT5)
|
|
show_end_message_yesno("glib wrapper" ENABLE_GLIB)
|
|
show_end_message_yesno(" introspection" INTROSPECTION_FOUND)
|
|
diff --git a/cmake/modules/FindQt4.cmake b/cmake/modules/FindQt4.cmake
|
|
new file mode 100644
|
|
index 00000000..79378b0c
|
|
--- /dev/null
|
|
+++ b/cmake/modules/FindQt4.cmake
|
|
@@ -0,0 +1,1311 @@
|
|
+# - Find QT 4
|
|
+# This module can be used to find Qt4.
|
|
+# The most important issue is that the Qt4 qmake is available via the system path.
|
|
+# This qmake is then used to detect basically everything else.
|
|
+# This module defines a number of key variables and macros. First is
|
|
+# QT_USE_FILE which is the path to a CMake file that can be included to compile
|
|
+# Qt 4 applications and libraries. By default, the QtCore and QtGui
|
|
+# libraries are loaded. This behavior can be changed by setting one or more
|
|
+# of the following variables to true:
|
|
+# QT_DONT_USE_QTCORE
|
|
+# QT_DONT_USE_QTGUI
|
|
+# QT_USE_QT3SUPPORT
|
|
+# QT_USE_QTASSISTANT
|
|
+# QT_USE_QTDESIGNER
|
|
+# QT_USE_QTMOTIF
|
|
+# QT_USE_QTMAIN
|
|
+# QT_USE_QTNETWORK
|
|
+# QT_USE_QTNSPLUGIN
|
|
+# QT_USE_QTOPENGL
|
|
+# QT_USE_QTSQL
|
|
+# QT_USE_QTXML
|
|
+# QT_USE_QTSVG
|
|
+# QT_USE_QTTEST
|
|
+# QT_USE_QTUITOOLS
|
|
+# QT_USE_QTDBUS
|
|
+# QT_USE_QTSCRIPT
|
|
+#
|
|
+# All the libraries required are stored in a variable called QT_LIBRARIES.
|
|
+# Add this variable to your TARGET_LINK_LIBRARIES.
|
|
+#
|
|
+# macro QT4_WRAP_CPP(outfiles inputfile ... OPTIONS ...)
|
|
+# create moc code from a list of files containing Qt class with
|
|
+# the Q_OBJECT declaration. Options may be given to moc, such as those found
|
|
+# when executing "moc -help"
|
|
+#
|
|
+# macro QT4_WRAP_UI(outfiles inputfile ... OPTIONS ...)
|
|
+# create code from a list of Qt designer ui files.
|
|
+# Options may be given to uic, such as those found
|
|
+# when executing "uic -help"
|
|
+#
|
|
+# macro QT4_ADD_RESOURCES(outfiles inputfile ... OPTIONS ...)
|
|
+# create code from a list of Qt resource files.
|
|
+# Options may be given to rcc, such as those found
|
|
+# when executing "rcc -help"
|
|
+#
|
|
+# macro QT4_AUTOMOC(inputfile ... )
|
|
+# macro QT4_GENERATE_MOC(inputfile outputfile )
|
|
+#
|
|
+# macro QT4_ADD_DBUS_INTERFACE(outfiles interface basename)
|
|
+# create a the interface header and implementation files with the
|
|
+# given basename from the given interface xml file and add it to
|
|
+# the list of sources.
|
|
+# To disable generating a namespace header, set the source file property
|
|
+# NO_NAMESPACE to TRUE on the interface file.
|
|
+#
|
|
+# macro QT4_ADD_DBUS_INTERFACES(outfiles inputfile ... )
|
|
+# create the interface header and implementation files
|
|
+# for all listed interface xml files
|
|
+# the name will be automatically determined from the name of the xml file
|
|
+# To disable generating namespace headers, set the source file property
|
|
+# NO_NAMESPACE to TRUE for these inputfiles.
|
|
+#
|
|
+# macro QT4_ADD_DBUS_ADAPTOR(outfiles xmlfile parentheader parentclassname [basename] [classname])
|
|
+# create a dbus adaptor (header and implementation file) from the xml file
|
|
+# describing the interface, and add it to the list of sources. The adaptor
|
|
+# forwards the calls to a parent class, defined in parentheader and named
|
|
+# parentclassname. The name of the generated files will be
|
|
+# <basename>adaptor.{cpp,h} where basename defaults to the basename of the xml file.
|
|
+# If <classname> is provided, then it will be used as the classname of the
|
|
+# adaptor itself.
|
|
+#
|
|
+# macro QT4_GENERATE_DBUS_INTERFACE( header [interfacename] OPTIONS ...)
|
|
+# generate the xml interface file from the given header.
|
|
+# If the optional argument interfacename is omitted, the name of the
|
|
+# interface file is constructed from the basename of the header with
|
|
+# the suffix .xml appended.
|
|
+# Options may be given to uic, such as those found when executing "qdbuscpp2xml --help"
|
|
+#
|
|
+# QT_FOUND If false, don't try to use Qt.
|
|
+# QT4_FOUND If false, don't try to use Qt 4.
|
|
+#
|
|
+# QT4_QTCORE_FOUND True if QtCore was found.
|
|
+# QT4_QTGUI_FOUND True if QtGui was found.
|
|
+# QT4_QT3SUPPORT_FOUND True if Qt3Support was found.
|
|
+# QT4_QTASSISTANT_FOUND True if QtAssistant was found.
|
|
+# QT4_QTDBUS_FOUND True if QtDBus was found.
|
|
+# QT4_QTDESIGNER_FOUND True if QtDesigner was found.
|
|
+# QT4_QTDESIGNERCOMPONENTS True if QtDesignerComponents was found.
|
|
+# QT4_QTMOTIF_FOUND True if QtMotif was found.
|
|
+# QT4_QTNETWORK_FOUND True if QtNetwork was found.
|
|
+# QT4_QTNSPLUGIN_FOUND True if QtNsPlugin was found.
|
|
+# QT4_QTOPENGL_FOUND True if QtOpenGL was found.
|
|
+# QT4_QTSQL_FOUND True if QtSql was found.
|
|
+# QT4_QTXML_FOUND True if QtXml was found.
|
|
+# QT4_QTSVG_FOUND True if QtSvg was found.
|
|
+# QT4_QTSCRIPT_FOUND True if QtScript was found.
|
|
+# QT4_QTTEST_FOUND True if QtTest was found.
|
|
+# QT4_QTUITOOLS_FOUND True if QtUiTools was found.
|
|
+#
|
|
+# QT4_DEFINITIONS Definitions to use when compiling code that uses Qt.
|
|
+#
|
|
+# QT4_INCLUDES List of paths to all include directories of
|
|
+# Qt4 QT4_INCLUDE_DIR and QT4_QTCORE_INCLUDE_DIR are
|
|
+# always in this variable even if NOTFOUND,
|
|
+# all other INCLUDE_DIRS are
|
|
+# only added if they are found.
|
|
+#
|
|
+# QT4_INCLUDE_DIR Path to "include" of Qt4
|
|
+# QT4_QT4_INCLUDE_DIR Path to "include/Qt"
|
|
+# QT4_QT3SUPPORT_INCLUDE_DIR Path to "include/Qt3Support"
|
|
+# QT4_QTASSISTANT_INCLUDE_DIR Path to "include/QtAssistant"
|
|
+# QT4_QTCORE_INCLUDE_DIR Path to "include/QtCore"
|
|
+# QT4_QTDESIGNER_INCLUDE_DIR Path to "include/QtDesigner"
|
|
+# QT4_QTDESIGNERCOMPONENTS_INCLUDE_DIR Path to "include/QtDesigner"
|
|
+# QT4_QTDBUS_INCLUDE_DIR Path to "include/QtDBus"
|
|
+# QT4_QTGUI_INCLUDE_DIR Path to "include/QtGui"
|
|
+# QT4_QTMOTIF_INCLUDE_DIR Path to "include/QtMotif"
|
|
+# QT4_QTNETWORK_INCLUDE_DIR Path to "include/QtNetwork"
|
|
+# QT4_QTNSPLUGIN_INCLUDE_DIR Path to "include/QtNsPlugin"
|
|
+# QT4_QTOPENGL_INCLUDE_DIR Path to "include/QtOpenGL"
|
|
+# QT4_QTSQL_INCLUDE_DIR Path to "include/QtSql"
|
|
+# QT4_QTXML_INCLUDE_DIR Path to "include/QtXml"
|
|
+# QT4_QTSVG_INCLUDE_DIR Path to "include/QtSvg"
|
|
+# QT4_QTSCRIPT_INCLUDE_DIR Path to "include/QtScript"
|
|
+# QT4_QTTEST_INCLUDE_DIR Path to "include/QtTest"
|
|
+#
|
|
+# QT4_LIBRARY_DIR Path to "lib" of Qt4
|
|
+#
|
|
+# QT4_PLUGINS_DIR Path to "plugins" for Qt4
|
|
+#
|
|
+# For every library of Qt, a QT4_QTFOO_LIBRARY variable is defined, with the full path to the library.
|
|
+#
|
|
+# So there are the following variables:
|
|
+# The Qt3Support library: QT4_QT3SUPPORT_LIBRARY
|
|
+#
|
|
+# The QtAssistant library: QT4_QTASSISTANT_LIBRARY
|
|
+#
|
|
+# The QtCore library: QT4_QTCORE_LIBRARY
|
|
+#
|
|
+# The QtDBus library: QT4_QTDBUS_LIBRARY
|
|
+#
|
|
+# The QtDesigner library: QT4_QTDESIGNER_LIBRARY
|
|
+#
|
|
+# The QtDesignerComponents library: QT4_QTDESIGNERCOMPONENTS_LIBRARY
|
|
+#
|
|
+# The QtGui library: QT4_QTGUI_LIBRARY
|
|
+#
|
|
+# The QtMotif library: QT4_QTMOTIF_LIBRARY
|
|
+#
|
|
+# The QtNetwork library: QT4_QTNETWORK_LIBRARY
|
|
+#
|
|
+# The QtNsPLugin library: QT4_QTNSPLUGIN_LIBRARY
|
|
+#
|
|
+# The QtOpenGL library: QT4_QTOPENGL_LIBRARY
|
|
+#
|
|
+# The QtSql library: QT4_QTSQL_LIBRARY
|
|
+#
|
|
+# The QtXml library: QT4_QTXML_LIBRARY
|
|
+#
|
|
+# The QtSvg library: QT4_QTSVG_LIBRARY
|
|
+#
|
|
+# The QtScript library: QT4_QTSCRIPT_LIBRARY
|
|
+#
|
|
+# The QtTest library: QT4_QTTEST_LIBRARY
|
|
+#
|
|
+# The qtmain library for Windows QT4_QTMAIN_LIBRARY
|
|
+#
|
|
+# The QtUiTools library: QT4_QTUITOOLS_LIBRARY
|
|
+#
|
|
+# also defined, but NOT for general use are
|
|
+# QT4_MOC_EXECUTABLE Where to find the moc tool.
|
|
+# QT4_UIC_EXECUTABLE Where to find the uic tool.
|
|
+# QT_UIC3_EXECUTABLE Where to find the uic3 tool.
|
|
+# QT_RCC_EXECUTABLE Where to find the rcc tool
|
|
+# QT_DBUSCPP2XML_EXECUTABLE Where to find the qdbuscpp2xml tool.
|
|
+# QT_DBUSXML2CPP_EXECUTABLE Where to find the qdbusxml2cpp tool.
|
|
+#
|
|
+# QT_DOC_DIR Path to "doc" of Qt4
|
|
+# QT_MKSPECS_DIR Path to "mkspecs" of Qt4
|
|
+#
|
|
+#
|
|
+# These are around for backwards compatibility
|
|
+# they will be set
|
|
+# QT_WRAP_CPP Set true if QT4_MOC_EXECUTABLE is found
|
|
+# QT_WRAP_UI Set true if QT4_UIC_EXECUTABLE is found
|
|
+#
|
|
+# These variables do _NOT_ have any effect anymore (compared to FindQt.cmake)
|
|
+# QT_MT_REQUIRED Qt4 is now always multithreaded
|
|
+#
|
|
+# These variables are set to "" Because Qt structure changed
|
|
+# (They make no sense in Qt4)
|
|
+# QT4_QT_LIBRARY Qt-Library is now split
|
|
+
|
|
+# Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
|
|
+# See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
|
|
+
|
|
+if (QT4_QMAKE_FOUND)
|
|
+ # Check already done in this cmake run, nothing more to do
|
|
+
|
|
+else (QT4_QMAKE_FOUND)
|
|
+
|
|
+# check that QT_NO_DEBUG is defined for release configurations
|
|
+MACRO(QT_CHECK_FLAG_EXISTS FLAG VAR DOC)
|
|
+ IF(NOT ${VAR} MATCHES "${FLAG}")
|
|
+ SET(${VAR} "${${VAR}} ${FLAG}"
|
|
+ CACHE STRING "Flags used by the compiler during ${DOC} builds." FORCE)
|
|
+ ENDIF(NOT ${VAR} MATCHES "${FLAG}")
|
|
+ENDMACRO(QT_CHECK_FLAG_EXISTS FLAG VAR)
|
|
+QT_CHECK_FLAG_EXISTS(-DQT_NO_DEBUG CMAKE_CXX_FLAGS_RELWITHDEBINFO "Release with Debug Info")
|
|
+QT_CHECK_FLAG_EXISTS(-DQT_NO_DEBUG CMAKE_CXX_FLAGS_RELEASE "release")
|
|
+QT_CHECK_FLAG_EXISTS(-DQT_NO_DEBUG CMAKE_CXX_FLAGS_MINSIZEREL "release minsize")
|
|
+
|
|
+INCLUDE(CheckSymbolExists)
|
|
+INCLUDE(MacroAddFileDependencies)
|
|
+INCLUDE(MacroPushRequiredVars)
|
|
+
|
|
+SET(QT_USE_FILE ${CMAKE_ROOT}/Modules/UseQt4.cmake)
|
|
+
|
|
+SET( QT4_DEFINITIONS "")
|
|
+
|
|
+IF (WIN32)
|
|
+ SET(QT4_DEFINITIONS -DQT_DLL)
|
|
+ENDIF(WIN32)
|
|
+
|
|
+SET(QT4_INSTALLED_VERSION_TOO_OLD FALSE)
|
|
+
|
|
+# macro for asking qmake to process pro files
|
|
+MACRO(QT_QUERY_QMAKE outvar invar)
|
|
+ FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmpQmake/tmp.pro
|
|
+ "message(CMAKE_MESSAGE<$$${invar}>)")
|
|
+
|
|
+ # Invoke qmake with the tmp.pro program to get the desired
|
|
+ # information. Use the same variable for both stdout and stderr
|
|
+ # to make sure we get the output on all platforms.
|
|
+ EXECUTE_PROCESS(COMMAND ${QT_QMAKE_EXECUTABLE}
|
|
+ WORKING_DIRECTORY
|
|
+ ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmpQmake
|
|
+ OUTPUT_VARIABLE _qmake_query_output
|
|
+ RESULT_VARIABLE _qmake_result
|
|
+ ERROR_VARIABLE _qmake_query_output )
|
|
+
|
|
+ FILE(REMOVE_RECURSE
|
|
+ "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmpQmake")
|
|
+
|
|
+ IF(_qmake_result)
|
|
+ MESSAGE(WARNING " querying qmake for ${invar}. qmake reported:\n${_qmake_query_output}")
|
|
+ ELSE(_qmake_result)
|
|
+ STRING(REGEX REPLACE ".*CMAKE_MESSAGE<([^>]*).*" "\\1" ${outvar} "${_qmake_query_output}")
|
|
+ ENDIF(_qmake_result)
|
|
+
|
|
+ENDMACRO(QT_QUERY_QMAKE)
|
|
+
|
|
+MACRO(VERIFY_QMAKE_QT4)
|
|
+ EXEC_PROGRAM(${QT_QMAKE_EXECUTABLE} ARGS "-query QT_VERSION" OUTPUT_VARIABLE QTVERSION)
|
|
+
|
|
+ # check for qt3 qmake and then try and find qmake4 or qmake-qt4 in the path
|
|
+ IF("${QTVERSION}" MATCHES "Unknown")
|
|
+ SET(QT_QMAKE_EXECUTABLE NOTFOUND CACHE FILEPATH "" FORCE)
|
|
+ FIND_PROGRAM(QT_QMAKE_EXECUTABLE NAMES qmake4 qmake-qt4 PATHS
|
|
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\4.0.0;InstallDir]/bin"
|
|
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Versions\\4.0.0;InstallDir]/bin"
|
|
+ $ENV{QTDIR}/bin
|
|
+ )
|
|
+ IF(QT_QMAKE_EXECUTABLE)
|
|
+ EXEC_PROGRAM(${QT_QMAKE_EXECUTABLE}
|
|
+ ARGS "-query QT_VERSION" OUTPUT_VARIABLE QTVERSION)
|
|
+ ENDIF(QT_QMAKE_EXECUTABLE)
|
|
+ ENDIF("${QTVERSION}" MATCHES "Unknown")
|
|
+
|
|
+ # check that we found the Qt4 qmake, Qt3 qmake output won't match here
|
|
+ STRING(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+" qt_version_tmp "${QTVERSION}")
|
|
+ IF (qt_version_tmp)
|
|
+
|
|
+ # we need at least version 4.0.0
|
|
+ IF (NOT QT4_MIN_VERSION)
|
|
+ SET(QT4_MIN_VERSION "4.0.0")
|
|
+ ENDIF (NOT QT4_MIN_VERSION)
|
|
+
|
|
+ #now parse the parts of the user given version string into variables
|
|
+ STRING(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+" req_qt_major_vers "${QT4_MIN_VERSION}")
|
|
+ IF (NOT req_qt_major_vers)
|
|
+ MESSAGE( FATAL_ERROR "Invalid Qt version string given: \"${QT4_MIN_VERSION}\", expected e.g. \"4.0.1\"")
|
|
+ ENDIF (NOT req_qt_major_vers)
|
|
+
|
|
+ # now parse the parts of the user given version string into variables
|
|
+ STRING(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" req_qt_major_vers "${QT4_MIN_VERSION}")
|
|
+ STRING(REGEX REPLACE "^[0-9]+\\.([0-9])+\\.[0-9]+" "\\1" req_qt_minor_vers "${QT4_MIN_VERSION}")
|
|
+ STRING(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" req_qt_patch_vers "${QT4_MIN_VERSION}")
|
|
+
|
|
+ IF (NOT req_qt_major_vers EQUAL 4)
|
|
+ MESSAGE( FATAL_ERROR "Invalid Qt version string given: \"${QT4_MIN_VERSION}\", major version 4 is required, e.g. \"4.0.1\"")
|
|
+ ENDIF (NOT req_qt_major_vers EQUAL 4)
|
|
+
|
|
+ # and now the version string given by qmake
|
|
+ STRING(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" found_qt_major_vers "${QTVERSION}")
|
|
+ STRING(REGEX REPLACE "^[0-9]+\\.([0-9])+\\.[0-9]+.*" "\\1" found_qt_minor_vers "${QTVERSION}")
|
|
+ STRING(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" found_qt_patch_vers "${QTVERSION}")
|
|
+ IF (${found_qt_major_vers} EQUAL 4)
|
|
+ # compute an overall version number which can be compared at once
|
|
+ MATH(EXPR req_vers "${req_qt_major_vers}*10000 + ${req_qt_minor_vers}*100 + ${req_qt_patch_vers}")
|
|
+ MATH(EXPR found_vers "${found_qt_major_vers}*10000 + ${found_qt_minor_vers}*100 + ${found_qt_patch_vers}")
|
|
+
|
|
+
|
|
+ IF (found_vers LESS req_vers)
|
|
+ SET(QT4_QMAKE_FOUND FALSE)
|
|
+ SET(QT4_INSTALLED_VERSION_TOO_OLD TRUE)
|
|
+ ELSE (found_vers LESS req_vers)
|
|
+ SET(QT4_QMAKE_FOUND TRUE)
|
|
+ ENDIF (found_vers LESS req_vers)
|
|
+ ENDIF ()
|
|
+ ENDIF (qt_version_tmp)
|
|
+ENDMACRO()
|
|
+
|
|
+GET_FILENAME_COMPONENT(qt_install_version "[HKEY_CURRENT_USER\\Software\\trolltech\\Versions;DefaultQtVersion]" NAME)
|
|
+# check for qmake
|
|
+FIND_PROGRAM(QT_QMAKE_EXECUTABLE NAMES qmake qmake4 qmake-qt4 PATHS
|
|
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\4.0.0;InstallDir]/bin"
|
|
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Versions\\4.0.0;InstallDir]/bin"
|
|
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Versions\\${qt_install_version};InstallDir]/bin"
|
|
+ $ENV{QTDIR}/bin
|
|
+)
|
|
+
|
|
+IF (QT_QMAKE_EXECUTABLE)
|
|
+
|
|
+ SET(QT4_QMAKE_FOUND FALSE)
|
|
+ VERIFY_QMAKE_QT4()
|
|
+
|
|
+ IF (NOT QT4_QMAKE_FOUND)
|
|
+ FIND_PROGRAM(QT_QMAKE_EXECUTABLE2 NAMES qmake4 qmake-qt4 PATHS
|
|
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\4.0.0;InstallDir]/bin"
|
|
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Versions\\4.0.0;InstallDir]/bin"
|
|
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Versions\\${qt_install_version};InstallDir]/bin"
|
|
+ $ENV{QTDIR}/bin
|
|
+ )
|
|
+ SET(QT_QMAKE_EXECUTABLE ${QT_QMAKE_EXECUTABLE2})
|
|
+ VERIFY_QMAKE_QT4()
|
|
+ ENDIF()
|
|
+
|
|
+ENDIF (QT_QMAKE_EXECUTABLE)
|
|
+
|
|
+IF (QT4_QMAKE_FOUND)
|
|
+
|
|
+ if (WIN32)
|
|
+ # get qt install dir
|
|
+ get_filename_component(_DIR ${QT_QMAKE_EXECUTABLE} PATH )
|
|
+ get_filename_component(QT_INSTALL_DIR ${_DIR} PATH )
|
|
+ endif (WIN32)
|
|
+
|
|
+ # ask qmake for the library dir
|
|
+ # Set QT4_LIBRARY_DIR
|
|
+ IF (NOT QT4_LIBRARY_DIR)
|
|
+ EXEC_PROGRAM( ${QT_QMAKE_EXECUTABLE}
|
|
+ ARGS "-query QT_INSTALL_LIBS"
|
|
+ OUTPUT_VARIABLE QT4_LIBRARY_DIR_TMP )
|
|
+ IF(EXISTS "${QT4_LIBRARY_DIR_TMP}")
|
|
+ SET(QT4_LIBRARY_DIR ${QT4_LIBRARY_DIR_TMP} CACHE PATH "Qt library dir")
|
|
+ ELSE(EXISTS "${QT4_LIBRARY_DIR_TMP}")
|
|
+ MESSAGE("Warning: QT_QMAKE_EXECUTABLE reported QT_INSTALL_LIBS as ${QT4_LIBRARY_DIR_TMP}")
|
|
+ MESSAGE("Warning: ${QT4_LIBRARY_DIR_TMP} does NOT exist, Qt must NOT be installed correctly.")
|
|
+ ENDIF(EXISTS "${QT4_LIBRARY_DIR_TMP}")
|
|
+ ENDIF(NOT QT4_LIBRARY_DIR)
|
|
+
|
|
+ IF (APPLE)
|
|
+ IF (EXISTS ${QT4_LIBRARY_DIR}/QtCore.framework)
|
|
+ SET(QT_USE_FRAMEWORKS ON
|
|
+ CACHE BOOL "Set to ON if Qt build uses frameworks.")
|
|
+ ELSE (EXISTS ${QT4_LIBRARY_DIR}/QtCore.framework)
|
|
+ SET(QT_USE_FRAMEWORKS OFF
|
|
+ CACHE BOOL "Set to ON if Qt build uses frameworks.")
|
|
+ ENDIF (EXISTS ${QT4_LIBRARY_DIR}/QtCore.framework)
|
|
+
|
|
+ MARK_AS_ADVANCED(QT_USE_FRAMEWORKS)
|
|
+ ENDIF (APPLE)
|
|
+
|
|
+ # ask qmake for the binary dir
|
|
+ IF (NOT QT_BINARY_DIR)
|
|
+ EXEC_PROGRAM(${QT_QMAKE_EXECUTABLE}
|
|
+ ARGS "-query QT_INSTALL_BINS"
|
|
+ OUTPUT_VARIABLE qt_bins )
|
|
+ SET(QT_BINARY_DIR ${qt_bins} CACHE INTERNAL "")
|
|
+ ENDIF (NOT QT_BINARY_DIR)
|
|
+
|
|
+ # ask qmake for the include dir
|
|
+ IF (NOT QT_HEADERS_DIR)
|
|
+ EXEC_PROGRAM( ${QT_QMAKE_EXECUTABLE}
|
|
+ ARGS "-query QT_INSTALL_HEADERS"
|
|
+ OUTPUT_VARIABLE qt_headers )
|
|
+ SET(QT_HEADERS_DIR ${qt_headers} CACHE INTERNAL "")
|
|
+ ENDIF(NOT QT_HEADERS_DIR)
|
|
+
|
|
+
|
|
+ # ask qmake for the documentation directory
|
|
+ IF (NOT QT_DOC_DIR)
|
|
+ EXEC_PROGRAM( ${QT_QMAKE_EXECUTABLE}
|
|
+ ARGS "-query QT_INSTALL_DOCS"
|
|
+ OUTPUT_VARIABLE qt_doc_dir )
|
|
+ SET(QT_DOC_DIR ${qt_doc_dir} CACHE PATH "The location of the Qt docs")
|
|
+ ENDIF (NOT QT_DOC_DIR)
|
|
+
|
|
+ # ask qmake for the mkspecs directory
|
|
+ IF (NOT QT_MKSPECS_DIR)
|
|
+ EXEC_PROGRAM( ${QT_QMAKE_EXECUTABLE}
|
|
+ ARGS "-query QMAKE_MKSPECS"
|
|
+ OUTPUT_VARIABLE qt_mkspecs_dirs )
|
|
+ STRING(REPLACE ":" ";" qt_mkspecs_dirs "${qt_mkspecs_dirs}")
|
|
+ FIND_PATH(QT_MKSPECS_DIR qconfig.pri PATHS ${qt_mkspecs_dirs}
|
|
+ DOC "The location of the Qt mkspecs containing qconfig.pri"
|
|
+ NO_DEFAULT_PATH )
|
|
+ ENDIF (NOT QT_MKSPECS_DIR)
|
|
+
|
|
+ # ask qmake for the plugins directory
|
|
+ IF (NOT QT4_PLUGINS_DIR)
|
|
+ EXEC_PROGRAM( ${QT_QMAKE_EXECUTABLE}
|
|
+ ARGS "-query QT_INSTALL_PLUGINS"
|
|
+ OUTPUT_VARIABLE qt_plugins_dir )
|
|
+ SET(QT4_PLUGINS_DIR ${qt_plugins_dir} CACHE PATH "The location of the Qt plugins")
|
|
+ ENDIF (NOT QT4_PLUGINS_DIR)
|
|
+ ########################################
|
|
+ #
|
|
+ # Setting the INCLUDE-Variables
|
|
+ #
|
|
+ ########################################
|
|
+
|
|
+ FIND_PATH(QT4_QTCORE_INCLUDE_DIR QtGlobal
|
|
+ ${QT_HEADERS_DIR}/QtCore
|
|
+ ${QT4_LIBRARY_DIR}/QtCore.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Set QT4_INCLUDE_DIR by removine "/QtCore" in the string ${QT4_QTCORE_INCLUDE_DIR}
|
|
+ IF( QT4_QTCORE_INCLUDE_DIR AND NOT QT4_INCLUDE_DIR)
|
|
+ IF (QT_USE_FRAMEWORKS)
|
|
+ SET(QT4_INCLUDE_DIR ${QT_HEADERS_DIR})
|
|
+ ELSE (QT_USE_FRAMEWORKS)
|
|
+ STRING( REGEX REPLACE "/QtCore$" "" qt4_include_dir ${QT4_QTCORE_INCLUDE_DIR})
|
|
+ SET( QT4_INCLUDE_DIR ${qt4_include_dir} CACHE PATH "")
|
|
+ ENDIF (QT_USE_FRAMEWORKS)
|
|
+ ENDIF( QT4_QTCORE_INCLUDE_DIR AND NOT QT4_INCLUDE_DIR)
|
|
+
|
|
+ IF( NOT QT4_INCLUDE_DIR)
|
|
+ IF( NOT Qt4_FIND_QUIETLY AND Qt4_FIND_REQUIRED)
|
|
+ MESSAGE( FATAL_ERROR "Could NOT find QtGlobal header")
|
|
+ ENDIF( NOT Qt4_FIND_QUIETLY AND Qt4_FIND_REQUIRED)
|
|
+ ENDIF( NOT QT4_INCLUDE_DIR)
|
|
+
|
|
+ #############################################
|
|
+ #
|
|
+ # Find out what window system we're using
|
|
+ #
|
|
+ #############################################
|
|
+ # Save required includes and required_flags variables
|
|
+ macro_push_required_vars()
|
|
+ # Add QT4_INCLUDE_DIR to CMAKE_REQUIRED_INCLUDES
|
|
+ SET(CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES};${QT4_INCLUDE_DIR}")
|
|
+ # On Mac OS X when Qt has framework support, also add the framework path
|
|
+ IF( QT_USE_FRAMEWORKS )
|
|
+ SET(CMAKE_REQUIRED_FLAGS "-F${QT4_LIBRARY_DIR} ")
|
|
+ ENDIF( QT_USE_FRAMEWORKS )
|
|
+ # Check for Window system symbols (note: only one should end up being set)
|
|
+ CHECK_SYMBOL_EXISTS(Q_WS_X11 "QtCore/qglobal.h" Q_WS_X11)
|
|
+ CHECK_SYMBOL_EXISTS(Q_WS_WIN "QtCore/qglobal.h" Q_WS_WIN)
|
|
+ CHECK_SYMBOL_EXISTS(Q_WS_QWS "QtCore/qglobal.h" Q_WS_QWS)
|
|
+ CHECK_SYMBOL_EXISTS(Q_WS_MAC "QtCore/qglobal.h" Q_WS_MAC)
|
|
+
|
|
+ IF (QT4_QTCOPY_REQUIRED)
|
|
+ CHECK_SYMBOL_EXISTS(QT_IS_QTCOPY "QtCore/qglobal.h" QT_KDE_QT_COPY)
|
|
+ IF (NOT QT_IS_QTCOPY)
|
|
+ MESSAGE(FATAL_ERROR "qt-copy is required, but hasn't been found")
|
|
+ ENDIF (NOT QT_IS_QTCOPY)
|
|
+ ENDIF (QT4_QTCOPY_REQUIRED)
|
|
+
|
|
+ # Restore CMAKE_REQUIRED_INCLUDES+CMAKE_REQUIRED_FLAGS variables
|
|
+ macro_pop_required_vars()
|
|
+ #
|
|
+ #############################################
|
|
+
|
|
+ IF (QT_USE_FRAMEWORKS)
|
|
+ SET(QT4_DEFINITIONS ${QT4_DEFINITIONS} -F${QT4_LIBRARY_DIR} -L${QT4_LIBRARY_DIR} )
|
|
+ ENDIF (QT_USE_FRAMEWORKS)
|
|
+
|
|
+ # Set QT4_QT3SUPPORT_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QT3SUPPORT_INCLUDE_DIR Qt3Support
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/Qt3Support
|
|
+ ${QT4_LIBRARY_DIR}/Qt3Support.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Set QT4_QT4_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QT4_INCLUDE_DIR qglobal.h
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/Qt
|
|
+ ${QT4_LIBRARY_DIR}/QtCore.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Set QT4_QTGUI_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QTGUI_INCLUDE_DIR QtGui
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/QtGui
|
|
+ ${QT4_LIBRARY_DIR}/QtGui.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Set QT4_QTSVG_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QTSVG_INCLUDE_DIR QtSvg
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/QtSvg
|
|
+ ${QT4_LIBRARY_DIR}/QtSvg.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Set QT4_QTSCRIPT_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QTSCRIPT_INCLUDE_DIR QtScript
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/QtScript
|
|
+ ${QT4_LIBRARY_DIR}/QtScript.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Set QT4_QTTEST_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QTTEST_INCLUDE_DIR QtTest
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/QtTest
|
|
+ ${QT4_LIBRARY_DIR}/QtTest.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Set QT4_QTUITOOLS_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QTUITOOLS_INCLUDE_DIR QtUiTools
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/QtUiTools
|
|
+ ${QT4_LIBRARY_DIR}/QtUiTools.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+
|
|
+
|
|
+ # Set QT4_QTMOTIF_INCLUDE_DIR
|
|
+ IF(Q_WS_X11)
|
|
+ FIND_PATH(QT4_QTMOTIF_INCLUDE_DIR QtMotif PATHS ${QT4_INCLUDE_DIR}/QtMotif NO_DEFAULT_PATH )
|
|
+ ENDIF(Q_WS_X11)
|
|
+
|
|
+ # Set QT4_QTNETWORK_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QTNETWORK_INCLUDE_DIR QtNetwork
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/QtNetwork
|
|
+ ${QT4_LIBRARY_DIR}/QtNetwork.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Set QT4_QTNSPLUGIN_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QTNSPLUGIN_INCLUDE_DIR QtNsPlugin
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/QtNsPlugin
|
|
+ ${QT4_LIBRARY_DIR}/QtNsPlugin.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Set QT4_QTOPENGL_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QTOPENGL_INCLUDE_DIR QtOpenGL
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/QtOpenGL
|
|
+ ${QT4_LIBRARY_DIR}/QtOpenGL.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Set QT4_QTSQL_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QTSQL_INCLUDE_DIR QtSql
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/QtSql
|
|
+ ${QT4_LIBRARY_DIR}/QtSql.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Set QT4_QTXML_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QTXML_INCLUDE_DIR QtXml
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/QtXml
|
|
+ ${QT4_LIBRARY_DIR}/QtXml.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Set QT4_QTASSISTANT_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QTASSISTANT_INCLUDE_DIR QtAssistant
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/QtAssistant
|
|
+ ${QT_HEADERS_DIR}/QtAssistant
|
|
+ ${QT4_LIBRARY_DIR}/QtAssistant.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Set QT4_QTDESIGNER_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QTDESIGNER_INCLUDE_DIR QDesignerComponents
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/QtDesigner
|
|
+ ${QT_HEADERS_DIR}/QtDesigner
|
|
+ ${QT4_LIBRARY_DIR}/QtDesigner.framework/Headers
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Set QT4_QTDESIGNERCOMPONENTS_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QTDESIGNERCOMPONENTS_INCLUDE_DIR QDesignerComponents
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/QtDesigner
|
|
+ ${QT_HEADERS_DIR}/QtDesigner
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+
|
|
+ # Set QT4_QTDBUS_INCLUDE_DIR
|
|
+ FIND_PATH(QT4_QTDBUS_INCLUDE_DIR QtDBus
|
|
+ PATHS
|
|
+ ${QT4_INCLUDE_DIR}/QtDBus
|
|
+ ${QT_HEADERS_DIR}/QtDBus
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ # Make variables changeble to the advanced user
|
|
+ MARK_AS_ADVANCED( QT4_LIBRARY_DIR QT4_INCLUDE_DIR QT4_QT4_INCLUDE_DIR QT_DOC_DIR QT_MKSPECS_DIR QT4_PLUGINS_DIR)
|
|
+
|
|
+ # Set QT4_INCLUDES
|
|
+ SET( QT4_INCLUDES ${QT4_QT4_INCLUDE_DIR} ${QT_MKSPECS_DIR}/default ${QT4_INCLUDE_DIR})
|
|
+
|
|
+
|
|
+ ########################################
|
|
+ #
|
|
+ # Setting the LIBRARY-Variables
|
|
+ #
|
|
+ ########################################
|
|
+
|
|
+ IF (QT_USE_FRAMEWORKS)
|
|
+ # If FIND_LIBRARY found libraries in Apple frameworks, we would NOT have
|
|
+ # to jump through these hoops.
|
|
+ IF(EXISTS ${QT4_LIBRARY_DIR}/QtCore.framework)
|
|
+ SET(QT4_QTCORE_FOUND TRUE)
|
|
+ SET(QT4_QTCORE_LIBRARY "-F${QT4_LIBRARY_DIR} -framework QtCore" CACHE STRING "The QtCore library.")
|
|
+ ELSE(EXISTS ${QT4_LIBRARY_DIR}/QtCore.framework)
|
|
+ SET(QT4_QTCORE_FOUND FALSE)
|
|
+ ENDIF(EXISTS ${QT4_LIBRARY_DIR}/QtCore.framework)
|
|
+
|
|
+ IF(EXISTS ${QT4_LIBRARY_DIR}/QtGui.framework)
|
|
+ SET(QT4_QTGUI_FOUND TRUE)
|
|
+ SET(QT4_QTGUI_LIBRARY "-F${QT4_LIBRARY_DIR} -framework QtGui" CACHE STRING "The QtGui library.")
|
|
+ ELSE(EXISTS ${QT4_LIBRARY_DIR}/QtGui.framework)
|
|
+ SET(QT4_QTGUI_FOUND FALSE)
|
|
+ ENDIF(EXISTS ${QT4_LIBRARY_DIR}/QtGui.framework)
|
|
+
|
|
+ IF(EXISTS ${QT4_LIBRARY_DIR}/Qt3Support.framework)
|
|
+ SET(QT4_QT3SUPPORT_FOUND TRUE)
|
|
+ SET(QT4_QT3SUPPORT_LIBRARY "-F${QT4_LIBRARY_DIR} -framework Qt3Support" CACHE STRING "The Qt3Support library.")
|
|
+ ELSE(EXISTS ${QT4_LIBRARY_DIR}/Qt3Support.framework)
|
|
+ SET(QT4_QT3SUPPORT_FOUND FALSE)
|
|
+ ENDIF(EXISTS ${QT4_LIBRARY_DIR}/Qt3Support.framework)
|
|
+
|
|
+ IF(EXISTS ${QT4_LIBRARY_DIR}/QtNetwork.framework)
|
|
+ SET(QT4_QTNETWORK_FOUND TRUE)
|
|
+ SET(QT4_QTNETWORK_LIBRARY "-F${QT4_LIBRARY_DIR} -framework QtNetwork" CACHE STRING "The QtNetwork library.")
|
|
+ ELSE(EXISTS ${QT4_LIBRARY_DIR}/QtNetwork.framework)
|
|
+ SET(QT4_QTNETWORK_FOUND FALSE)
|
|
+ ENDIF(EXISTS ${QT4_LIBRARY_DIR}/QtNetwork.framework)
|
|
+
|
|
+ IF(EXISTS ${QT4_LIBRARY_DIR}/QtOpenGL.framework)
|
|
+ SET(QT4_QTOPENGL_FOUND TRUE)
|
|
+ SET(QT4_QTOPENGL_LIBRARY "-F${QT4_LIBRARY_DIR} -framework QtOpenGL" CACHE STRING "The QtOpenGL library.")
|
|
+ ELSE(EXISTS ${QT4_LIBRARY_DIR}/QtOpenGL.framework)
|
|
+ SET(QT4_QTOPENGL_FOUND FALSE)
|
|
+ ENDIF(EXISTS ${QT4_LIBRARY_DIR}/QtOpenGL.framework)
|
|
+
|
|
+ IF(EXISTS ${QT4_LIBRARY_DIR}/QtSql.framework)
|
|
+ SET(QT4_QTSQL_FOUND TRUE)
|
|
+ SET(QT4_QTSQL_LIBRARY "-F${QT4_LIBRARY_DIR} -framework QtSql" CACHE STRING "The QtSql library.")
|
|
+ ELSE(EXISTS ${QT4_LIBRARY_DIR}/QtSql.framework)
|
|
+ SET(QT4_QTSQL_FOUND FALSE)
|
|
+ ENDIF(EXISTS ${QT4_LIBRARY_DIR}/QtSql.framework)
|
|
+
|
|
+ IF(EXISTS ${QT4_LIBRARY_DIR}/QtXml.framework)
|
|
+ SET(QT4_QTXML_FOUND TRUE)
|
|
+ SET(QT4_QTXML_LIBRARY "-F${QT4_LIBRARY_DIR} -framework QtXml" CACHE STRING "The QtXml library.")
|
|
+ ELSE(EXISTS ${QT4_LIBRARY_DIR}/QtXml.framework)
|
|
+ SET(QT4_QTXML_FOUND FALSE)
|
|
+ ENDIF(EXISTS ${QT4_LIBRARY_DIR}/QtXml.framework)
|
|
+
|
|
+ IF(EXISTS ${QT4_LIBRARY_DIR}/QtSvg.framework)
|
|
+ SET(QT4_QTSVG_FOUND TRUE)
|
|
+ SET(QT4_QTSVG_LIBRARY "-F${QT4_LIBRARY_DIR} -framework QtSvg" CACHE STRING "The QtSvg library.")
|
|
+ ELSE(EXISTS ${QT4_LIBRARY_DIR}/QtSvg.framework)
|
|
+ SET(QT4_QTSVG_FOUND FALSE)
|
|
+ ENDIF(EXISTS ${QT4_LIBRARY_DIR}/QtSvg.framework)
|
|
+
|
|
+ IF(EXISTS ${QT4_LIBRARY_DIR}/QtDBus.framework)
|
|
+ SET(QT4_QTDBUS_FOUND TRUE)
|
|
+ SET(QT4_QTDBUS_LIBRARY "-F${QT4_LIBRARY_DIR} -framework QtDBus" CACHE STRING "The QtDBus library.")
|
|
+ ELSE(EXISTS ${QT4_LIBRARY_DIR}/QtDBus.framework)
|
|
+ SET(QT4_QTDBUS_FOUND FALSE)
|
|
+ ENDIF(EXISTS ${QT4_LIBRARY_DIR}/QtDBus.framework)
|
|
+
|
|
+ IF(EXISTS ${QT4_LIBRARY_DIR}/QtTest.framework)
|
|
+ SET(QT4_QTTEST_FOUND TRUE)
|
|
+ SET(QT4_QTTEST_LIBRARY "-F${QT4_LIBRARY_DIR} -framework QtTest" CACHE STRING "The QtTest library.")
|
|
+ ELSE(EXISTS ${QT4_LIBRARY_DIR}/QtTest.framework)
|
|
+ SET(QT4_QTTEST_FOUND FALSE)
|
|
+ ENDIF(EXISTS ${QT4_LIBRARY_DIR}/QtTest.framework)
|
|
+
|
|
+ # WTF? why don't we have frameworks? :P
|
|
+ # Set QT4_QTUITOOLS_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTUITOOLS_LIBRARY NAMES QtUiTools QtUiTools4 PATHS ${QT4_LIBRARY_DIR} )
|
|
+ # Set QT4_QTSCRIPT_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTSCRIPT_LIBRARY NAMES QtScript QtScript4 PATHS ${QT4_LIBRARY_DIR} )
|
|
+
|
|
+ ELSE (QT_USE_FRAMEWORKS)
|
|
+
|
|
+ # Set QT4_QTCORE_LIBRARY by searching for a lib with "QtCore." as part of the filename
|
|
+ FIND_LIBRARY(QT4_QTCORE_LIBRARY NAMES QtCore QtCore4 QtCored4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH )
|
|
+
|
|
+ # Set QT4_QT3SUPPORT_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QT3SUPPORT_LIBRARY NAMES Qt3Support Qt3Support4 Qt3Supportd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ # Set QT4_QTGUI_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTGUI_LIBRARY NAMES QtGui QtGui4 QtGuid4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ # Set QT4_QTMOTIF_LIBRARY
|
|
+ IF(Q_WS_X11)
|
|
+ FIND_LIBRARY(QT4_QTMOTIF_LIBRARY NAMES QtMotif PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ ENDIF(Q_WS_X11)
|
|
+
|
|
+ # Set QT4_QTNETWORK_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTNETWORK_LIBRARY NAMES QtNetwork QtNetwork4 QtNetworkd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ # Set QT4_QTNSPLUGIN_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTNSPLUGIN_LIBRARY NAMES QtNsPlugin PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ # Set QT4_QTOPENGL_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTOPENGL_LIBRARY NAMES QtOpenGL QtOpenGL4 QtOpenGLd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ # Set QT4_QTSQL_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTSQL_LIBRARY NAMES QtSql QtSql4 QtSqld4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ # Set QT4_QTXML_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTXML_LIBRARY NAMES QtXml QtXml4 QtXmld4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ # Set QT4_QTSVG_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTSVG_LIBRARY NAMES QtSvg QtSvg4 QtSvgd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ # Set QT4_QTSCRIPT_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTSCRIPT_LIBRARY NAMES QtScript QtScript4 QtScriptd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ # Set QT4_QTUITOOLS_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTUITOOLS_LIBRARY NAMES QtUiTools QtUiTools4 QtUiToolsd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ # Set QT4_QTTEST_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTTEST_LIBRARY NAMES QtTest QtTest4 QtTestd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ FIND_LIBRARY(QT4_QTDBUS_LIBRARY NAMES QtDBus QtDBus4 QtDBusd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ IF(MSVC)
|
|
+ FIND_LIBRARY(QT4_QTCORE_LIBRARY_RELEASE NAMES QtCore4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTCORE_LIBRARY_DEBUG NAMES QtCored4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QT3SUPPORT_LIBRARY_RELEASE NAMES Qt3Support4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QT3SUPPORT_LIBRARY_DEBUG NAMES Qt3Supportd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTGUI_LIBRARY_RELEASE NAMES QtGui4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTGUI_LIBRARY_DEBUG NAMES QtGuid4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTNETWORK_LIBRARY_RELEASE NAMES QtNetwork4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTNETWORK_LIBRARY_DEBUG NAMES QtNetworkd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTOPENGL_LIBRARY_RELEASE NAMES QtOpenGL4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTOPENGL_LIBRARY_DEBUG NAMES QtOpenGLd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTSQL_LIBRARY_RELEASE NAMES QtSql4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTSQL_LIBRARY_DEBUG NAMES QtSqld4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTXML_LIBRARY_RELEASE NAMES QtXml4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTXML_LIBRARY_DEBUG NAMES QtXmld4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTSVG_LIBRARY_RELEASE NAMES QtSvg4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTSVG_LIBRARY_DEBUG NAMES QtSvgd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTSCRIPT_LIBRARY_RELEASE NAMES QtScript4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTSCRIPT_LIBRARY_DEBUG NAMES QtScriptd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTUITOOLS_LIBRARY_RELEASE NAMES QtUiTools QtUiTools4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTUITOOLS_LIBRARY_DEBUG NAMES QtUiToolsd QtUiToolsd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTTEST_LIBRARY_RELEASE NAMES QtTest4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTTEST_LIBRARY_DEBUG NAMES QtTestd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTDBUS_LIBRARY_RELEASE NAMES QtDBus4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTDBUS_LIBRARY_DEBUG NAMES QtDBusd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTASSISTANT_LIBRARY_RELEASE NAMES QtAssistantClient4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTASSISTANT_LIBRARY_DEBUG NAMES QtAssistantClientd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTDESIGNER_LIBRARY_RELEASE NAMES QtDesigner4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTDESIGNER_LIBRARY_DEBUG NAMES QtDesignerd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTDESIGNERCOMPONENTS_LIBRARY_RELEASE NAMES QtDesignerComponents4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTDESIGNERCOMPONENTS_LIBRARY_DEBUG NAMES QtDesignerComponentsd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTMAIN_LIBRARY_RELEASE NAMES qtmain PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ FIND_LIBRARY(QT4_QTMAIN_LIBRARY_DEBUG NAMES qtmaind PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ ENDIF(MSVC)
|
|
+ ENDIF (QT_USE_FRAMEWORKS)
|
|
+
|
|
+ IF( NOT QT4_QTCORE_LIBRARY )
|
|
+ IF( NOT Qt4_FIND_QUIETLY AND Qt4_FIND_REQUIRED)
|
|
+ MESSAGE( FATAL_ERROR "Could NOT find QtCore. Check ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log for more details.")
|
|
+ ENDIF( NOT Qt4_FIND_QUIETLY AND Qt4_FIND_REQUIRED)
|
|
+ ENDIF( NOT QT4_QTCORE_LIBRARY )
|
|
+
|
|
+ # Set QT4_QTASSISTANT_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTASSISTANT_LIBRARY NAMES QtAssistantClient QtAssistantClient4 QtAssistant QtAssistant4 QtAssistantd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ # Set QT4_QTDESIGNER_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTDESIGNER_LIBRARY NAMES QtDesigner QtDesigner4 QtDesignerd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ # Set QT4_QTDESIGNERCOMPONENTS_LIBRARY
|
|
+ FIND_LIBRARY(QT4_QTDESIGNERCOMPONENTS_LIBRARY NAMES QtDesignerComponents QtDesignerComponents4 QtDesignerComponentsd4 PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+
|
|
+ # Set QT4_QTMAIN_LIBRARY
|
|
+ IF(WIN32)
|
|
+ FIND_LIBRARY(QT4_QTMAIN_LIBRARY NAMES qtmain qtmaind PATHS ${QT4_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
+ ENDIF(WIN32)
|
|
+
|
|
+ ############################################
|
|
+ #
|
|
+ # Check the existence of the libraries.
|
|
+ #
|
|
+ ############################################
|
|
+
|
|
+ MACRO (_QT4_ADJUST_LIB_VARS basename)
|
|
+ IF (QT4_${basename}_LIBRARY OR QT4_${basename}_LIBRARY_DEBUG)
|
|
+
|
|
+ IF(MSVC)
|
|
+ # Both set
|
|
+ IF (QT4_${basename}_LIBRARY_RELEASE AND QT4_${basename}_LIBRARY_DEBUG)
|
|
+ SET(QT4_${basename}_LIBRARY optimized ${QT4_${basename}_LIBRARY_RELEASE} debug ${QT4_${basename}_LIBRARY_DEBUG})
|
|
+ ENDIF (QT4_${basename}_LIBRARY_RELEASE AND QT4_${basename}_LIBRARY_DEBUG)
|
|
+
|
|
+ # Only debug was found
|
|
+ IF (NOT QT4_${basename}_LIBRARY_RELEASE AND QT4_${basename}_LIBRARY_DEBUG)
|
|
+ SET(QT4_${basename}_LIBRARY ${QT4_${basename}_LIBRARY_DEBUG})
|
|
+ ENDIF (NOT QT4_${basename}_LIBRARY_RELEASE AND QT4_${basename}_LIBRARY_DEBUG)
|
|
+
|
|
+ # Only release was found
|
|
+ IF (QT4_${basename}_LIBRARY_RELEASE AND NOT QT4_${basename}_LIBRARY_DEBUG)
|
|
+ SET(QT4_${basename}_LIBRARY ${QT4_${basename}_LIBRARY_RELEASE})
|
|
+ ENDIF (QT4_${basename}_LIBRARY_RELEASE AND NOT QT4_${basename}_LIBRARY_DEBUG)
|
|
+
|
|
+ # Hmm, is this used anywhere ? Yes, in UseQt4.cmake. We are currently incompatible :-(
|
|
+ SET(QT4_${basename}_LIBRARIES optimized ${QT4_${basename}_LIBRARY} debug ${QT4_${basename}_LIBRARY_DEBUG})
|
|
+
|
|
+ ENDIF(MSVC)
|
|
+
|
|
+ SET(QT4_${basename}_LIBRARY ${QT4_${basename}_LIBRARY} CACHE FILEPATH "The Qt4 ${basename} library")
|
|
+
|
|
+ IF (QT4_${basename}_LIBRARY)
|
|
+ SET(QT4_${basename}_FOUND 1)
|
|
+ ENDIF (QT4_${basename}_LIBRARY)
|
|
+
|
|
+ ENDIF (QT4_${basename}_LIBRARY OR QT4_${basename}_LIBRARY_DEBUG)
|
|
+
|
|
+ IF (QT4_${basename}_INCLUDE_DIR)
|
|
+ #add the include directory to QT4_INCLUDES
|
|
+ SET(QT4_INCLUDES "${QT4_${basename}_INCLUDE_DIR}" ${QT4_INCLUDES})
|
|
+ ENDIF (QT4_${basename}_INCLUDE_DIR)
|
|
+
|
|
+ # Make variables changeble to the advanced user
|
|
+ MARK_AS_ADVANCED(QT4_${basename}_LIBRARY QT4_${basename}_INCLUDE_DIR)
|
|
+ ENDMACRO (_QT4_ADJUST_LIB_VARS)
|
|
+
|
|
+
|
|
+ # Set QT_xyz_LIBRARY variable and add
|
|
+ # library include path to QT4_INCLUDES
|
|
+ _QT4_ADJUST_LIB_VARS(QTCORE)
|
|
+ _QT4_ADJUST_LIB_VARS(QTGUI)
|
|
+ _QT4_ADJUST_LIB_VARS(QT3SUPPORT)
|
|
+ _QT4_ADJUST_LIB_VARS(QTASSISTANT)
|
|
+ _QT4_ADJUST_LIB_VARS(QTDESIGNER)
|
|
+ _QT4_ADJUST_LIB_VARS(QTDESIGNERCOMPONENTS)
|
|
+ _QT4_ADJUST_LIB_VARS(QTNETWORK)
|
|
+ _QT4_ADJUST_LIB_VARS(QTNSPLUGIN)
|
|
+ _QT4_ADJUST_LIB_VARS(QTOPENGL)
|
|
+ _QT4_ADJUST_LIB_VARS(QTSQL)
|
|
+ _QT4_ADJUST_LIB_VARS(QTXML)
|
|
+ _QT4_ADJUST_LIB_VARS(QTSVG)
|
|
+ _QT4_ADJUST_LIB_VARS(QTSCRIPT)
|
|
+ _QT4_ADJUST_LIB_VARS(QTUITOOLS)
|
|
+ _QT4_ADJUST_LIB_VARS(QTTEST)
|
|
+ _QT4_ADJUST_LIB_VARS(QTDBUS)
|
|
+
|
|
+ # platform dependent libraries
|
|
+ IF(Q_WS_X11)
|
|
+ _QT4_ADJUST_LIB_VARS(QTMOTIF)
|
|
+ ENDIF(Q_WS_X11)
|
|
+ IF(WIN32)
|
|
+ _QT4_ADJUST_LIB_VARS(QTMAIN)
|
|
+ ENDIF(WIN32)
|
|
+
|
|
+
|
|
+ #######################################
|
|
+ #
|
|
+ # Check the executables of Qt
|
|
+ # ( moc, uic, rcc )
|
|
+ #
|
|
+ #######################################
|
|
+
|
|
+
|
|
+ # find moc and uic using qmake
|
|
+ QT_QUERY_QMAKE(QT4_MOC_EXECUTABLE_INTERNAL "QMAKE_MOC")
|
|
+ QT_QUERY_QMAKE(QT4_UIC_EXECUTABLE_INTERNAL "QMAKE_UIC")
|
|
+
|
|
+ FILE(TO_CMAKE_PATH
|
|
+ "${QT4_MOC_EXECUTABLE_INTERNAL}" QT4_MOC_EXECUTABLE_INTERNAL)
|
|
+ FILE(TO_CMAKE_PATH
|
|
+ "${QT4_UIC_EXECUTABLE_INTERNAL}" QT4_UIC_EXECUTABLE_INTERNAL)
|
|
+
|
|
+ SET(QT4_MOC_EXECUTABLE
|
|
+ ${QT4_MOC_EXECUTABLE_INTERNAL} CACHE FILEPATH "The moc executable")
|
|
+ SET(QT4_UIC_EXECUTABLE
|
|
+ ${QT4_UIC_EXECUTABLE_INTERNAL} CACHE FILEPATH "The uic executable")
|
|
+
|
|
+ FIND_PROGRAM(QT_UIC3_EXECUTABLE
|
|
+ NAMES uic3
|
|
+ PATHS ${QT_BINARY_DIR}
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ FIND_PROGRAM(QT_RCC_EXECUTABLE
|
|
+ NAMES rcc
|
|
+ PATHS ${QT_BINARY_DIR}
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ FIND_PROGRAM(QT_DBUSCPP2XML_EXECUTABLE
|
|
+ NAMES qdbuscpp2xml
|
|
+ PATHS ${QT_BINARY_DIR}
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ FIND_PROGRAM(QT_DBUSXML2CPP_EXECUTABLE
|
|
+ NAMES qdbusxml2cpp
|
|
+ PATHS ${QT_BINARY_DIR}
|
|
+ NO_DEFAULT_PATH
|
|
+ )
|
|
+
|
|
+ IF (QT4_MOC_EXECUTABLE)
|
|
+ SET(QT_WRAP_CPP "YES")
|
|
+ ENDIF (QT4_MOC_EXECUTABLE)
|
|
+
|
|
+ IF (QT4_UIC_EXECUTABLE)
|
|
+ SET(QT_WRAP_UI "YES")
|
|
+ ENDIF (QT4_UIC_EXECUTABLE)
|
|
+
|
|
+
|
|
+
|
|
+ MARK_AS_ADVANCED( QT4_UIC_EXECUTABLE QT_UIC3_EXECUTABLE QT4_MOC_EXECUTABLE QT_RCC_EXECUTABLE QT_DBUSXML2CPP_EXECUTABLE QT_DBUSCPP2XML_EXECUTABLE)
|
|
+
|
|
+ ######################################
|
|
+ #
|
|
+ # Macros for building Qt files
|
|
+ #
|
|
+ ######################################
|
|
+ MACRO (QT4_EXTRACT_OPTIONS _qt4_files _qt4_options)
|
|
+ SET(${_qt4_files})
|
|
+ SET(${_qt4_options})
|
|
+ SET(_QT4_DOING_OPTIONS FALSE)
|
|
+ FOREACH(_currentArg ${ARGN})
|
|
+ IF ("${_currentArg}" STREQUAL "OPTIONS")
|
|
+ SET(_QT4_DOING_OPTIONS TRUE)
|
|
+ ELSE ("${_currentArg}" STREQUAL "OPTIONS")
|
|
+ IF(_QT4_DOING_OPTIONS)
|
|
+ LIST(APPEND ${_qt4_options} "${_currentArg}")
|
|
+ ELSE(_QT4_DOING_OPTIONS)
|
|
+ LIST(APPEND ${_qt4_files} "${_currentArg}")
|
|
+ ENDIF(_QT4_DOING_OPTIONS)
|
|
+ ENDIF ("${_currentArg}" STREQUAL "OPTIONS")
|
|
+ ENDFOREACH(_currentArg)
|
|
+ ENDMACRO (QT4_EXTRACT_OPTIONS)
|
|
+
|
|
+ MACRO (QT4_GET_MOC_INC_DIRS _moc_INC_DIRS)
|
|
+ SET(${_moc_INC_DIRS})
|
|
+ GET_DIRECTORY_PROPERTY(_inc_DIRS INCLUDE_DIRECTORIES)
|
|
+
|
|
+ FOREACH(_current ${_inc_DIRS})
|
|
+ SET(${_moc_INC_DIRS} ${${_moc_INC_DIRS}} "-I" ${_current})
|
|
+ ENDFOREACH(_current ${_inc_DIRS})
|
|
+
|
|
+ ENDMACRO(QT4_GET_MOC_INC_DIRS)
|
|
+
|
|
+
|
|
+ MACRO (QT4_GENERATE_MOC infile outfile )
|
|
+ # get include dirs
|
|
+ QT4_GET_MOC_INC_DIRS(moc_includes)
|
|
+
|
|
+ GET_FILENAME_COMPONENT(abs_infile ${infile} ABSOLUTE)
|
|
+
|
|
+ IF (MSVC_IDE)
|
|
+ SET (_moc_parameter_file ${outfile}_parameters)
|
|
+ SET (_moc_param "${moc_includes} \n-o${outfile} \n${abs_infile}")
|
|
+ STRING(REGEX REPLACE ";-I;" "\\n-I" _moc_param "${_moc_param}")
|
|
+ FILE (WRITE ${_moc_parameter_file} "${_moc_param}")
|
|
+ ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
|
|
+ COMMAND ${QT4_MOC_EXECUTABLE}
|
|
+ ARGS @"${_moc_parameter_file}"
|
|
+ DEPENDS ${abs_infile})
|
|
+ ELSE (MSVC_IDE)
|
|
+ ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
|
|
+ COMMAND ${QT4_MOC_EXECUTABLE}
|
|
+ ARGS ${moc_includes} -o ${outfile} ${abs_infile}
|
|
+ DEPENDS ${abs_infile})
|
|
+ ENDIF (MSVC_IDE)
|
|
+
|
|
+ SET_SOURCE_FILES_PROPERTIES(${outfile} PROPERTIES SKIP_AUTOMOC TRUE) # dont run automoc on this file
|
|
+
|
|
+ MACRO_ADD_FILE_DEPENDENCIES(${abs_infile} ${outfile})
|
|
+ ENDMACRO (QT4_GENERATE_MOC)
|
|
+
|
|
+
|
|
+ # QT4_WRAP_CPP(outfiles inputfile ... )
|
|
+ # TODO perhaps add support for -D, -U and other minor options
|
|
+
|
|
+ MACRO (QT4_WRAP_CPP outfiles )
|
|
+ # get include dirs
|
|
+ QT4_GET_MOC_INC_DIRS(moc_includes)
|
|
+ QT4_EXTRACT_OPTIONS(moc_files moc_options ${ARGN})
|
|
+
|
|
+ FOREACH (it ${moc_files})
|
|
+ GET_FILENAME_COMPONENT(it ${it} ABSOLUTE)
|
|
+ GET_FILENAME_COMPONENT(outfile ${it} NAME_WE)
|
|
+
|
|
+ SET(outfile ${CMAKE_CURRENT_BINARY_DIR}/moc_${outfile}.cxx)
|
|
+ ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
|
|
+ COMMAND ${QT4_MOC_EXECUTABLE}
|
|
+ ARGS ${moc_includes} ${moc_options} -o ${outfile} ${it}
|
|
+ DEPENDS ${it})
|
|
+ SET(${outfiles} ${${outfiles}} ${outfile})
|
|
+ ENDFOREACH(it)
|
|
+
|
|
+ ENDMACRO (QT4_WRAP_CPP)
|
|
+
|
|
+
|
|
+ # QT4_WRAP_UI(outfiles inputfile ... )
|
|
+
|
|
+ MACRO (QT4_WRAP_UI outfiles )
|
|
+ QT4_EXTRACT_OPTIONS(ui_files ui_options ${ARGN})
|
|
+
|
|
+ FOREACH (it ${ui_files})
|
|
+ GET_FILENAME_COMPONENT(outfile ${it} NAME_WE)
|
|
+ GET_FILENAME_COMPONENT(infile ${it} ABSOLUTE)
|
|
+ SET(outfile ${CMAKE_CURRENT_BINARY_DIR}/ui_${outfile}.h)
|
|
+ ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
|
|
+ COMMAND ${QT4_UIC_EXECUTABLE}
|
|
+ ARGS ${ui_options} -o ${outfile} ${infile}
|
|
+ MAIN_DEPENDENCY ${infile})
|
|
+ SET(${outfiles} ${${outfiles}} ${outfile})
|
|
+ ENDFOREACH (it)
|
|
+
|
|
+ ENDMACRO (QT4_WRAP_UI)
|
|
+
|
|
+
|
|
+ # QT4_ADD_RESOURCES(outfiles inputfile ... )
|
|
+ # TODO perhaps consider adding support for compression and root options to rcc
|
|
+
|
|
+ MACRO (QT4_ADD_RESOURCES outfiles )
|
|
+ QT4_EXTRACT_OPTIONS(rcc_files rcc_options ${ARGN})
|
|
+
|
|
+ FOREACH (it ${rcc_files})
|
|
+ GET_FILENAME_COMPONENT(outfilename ${it} NAME_WE)
|
|
+ GET_FILENAME_COMPONENT(infile ${it} ABSOLUTE)
|
|
+ GET_FILENAME_COMPONENT(rc_path ${infile} PATH)
|
|
+ SET(outfile ${CMAKE_CURRENT_BINARY_DIR}/qrc_${outfilename}.cxx)
|
|
+ # parse file for dependencies
|
|
+ # all files are absolute paths or relative to the location of the qrc file
|
|
+ FILE(READ "${infile}" _RC_FILE_CONTENTS)
|
|
+ STRING(REGEX MATCHALL "<file[^<]+" _RC_FILES "${_RC_FILE_CONTENTS}")
|
|
+ SET(_RC_DEPENDS)
|
|
+ FOREACH(_RC_FILE ${_RC_FILES})
|
|
+ STRING(REGEX REPLACE "^<file[^>]*>" "" _RC_FILE "${_RC_FILE}")
|
|
+ STRING(REGEX MATCH "^/|([A-Za-z]:/)" _ABS_PATH_INDICATOR "${_RC_FILE}")
|
|
+ IF(NOT _ABS_PATH_INDICATOR)
|
|
+ SET(_RC_FILE "${rc_path}/${_RC_FILE}")
|
|
+ ENDIF(NOT _ABS_PATH_INDICATOR)
|
|
+ SET(_RC_DEPENDS ${_RC_DEPENDS} "${_RC_FILE}")
|
|
+ ENDFOREACH(_RC_FILE)
|
|
+ ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
|
|
+ COMMAND ${QT_RCC_EXECUTABLE}
|
|
+ ARGS ${rcc_options} -name ${outfilename} -o ${outfile} ${infile}
|
|
+ MAIN_DEPENDENCY ${infile}
|
|
+ DEPENDS ${_RC_DEPENDS})
|
|
+ SET(${outfiles} ${${outfiles}} ${outfile})
|
|
+ ENDFOREACH (it)
|
|
+
|
|
+ ENDMACRO (QT4_ADD_RESOURCES)
|
|
+
|
|
+ MACRO(QT4_ADD_DBUS_INTERFACE _sources _interface _basename)
|
|
+ GET_FILENAME_COMPONENT(_infile ${_interface} ABSOLUTE)
|
|
+ SET(_header ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.h)
|
|
+ SET(_impl ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.cpp)
|
|
+ SET(_moc ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.moc)
|
|
+
|
|
+ GET_SOURCE_FILE_PROPERTY(_nonamespace ${_interface} NO_NAMESPACE)
|
|
+ IF ( _nonamespace )
|
|
+ SET(_params -N -m)
|
|
+ ELSE ( _nonamespace )
|
|
+ SET(_params -m)
|
|
+ ENDIF ( _nonamespace )
|
|
+
|
|
+ GET_SOURCE_FILE_PROPERTY(_include ${_interface} INCLUDE)
|
|
+ IF ( _include )
|
|
+ SET(_params ${_params} -i ${_include})
|
|
+ ENDIF ( _include )
|
|
+
|
|
+ ADD_CUSTOM_COMMAND(OUTPUT ${_impl} ${_header}
|
|
+ COMMAND ${QT_DBUSXML2CPP_EXECUTABLE} ${_params} -p ${_basename} ${_infile}
|
|
+ DEPENDS ${_infile})
|
|
+
|
|
+ SET_SOURCE_FILES_PROPERTIES(${_impl} PROPERTIES SKIP_AUTOMOC TRUE)
|
|
+
|
|
+ QT4_GENERATE_MOC(${_header} ${_moc})
|
|
+
|
|
+ SET(${_sources} ${${_sources}} ${_impl} ${_header} ${_moc})
|
|
+ MACRO_ADD_FILE_DEPENDENCIES(${_impl} ${_moc})
|
|
+
|
|
+ ENDMACRO(QT4_ADD_DBUS_INTERFACE)
|
|
+
|
|
+
|
|
+ MACRO(QT4_ADD_DBUS_INTERFACES _sources)
|
|
+ FOREACH (_current_FILE ${ARGN})
|
|
+ GET_FILENAME_COMPONENT(_infile ${_current_FILE} ABSOLUTE)
|
|
+ # get the part before the ".xml" suffix
|
|
+ STRING(REGEX REPLACE "(.*[/\\.])?([^\\.]+)\\.xml" "\\2" _basename ${_current_FILE})
|
|
+ STRING(TOLOWER ${_basename} _basename)
|
|
+ QT4_ADD_DBUS_INTERFACE(${_sources} ${_infile} ${_basename}interface)
|
|
+ ENDFOREACH (_current_FILE)
|
|
+ ENDMACRO(QT4_ADD_DBUS_INTERFACES)
|
|
+
|
|
+
|
|
+ MACRO(QT4_GENERATE_DBUS_INTERFACE _header) # _customName OPTIONS -some -options )
|
|
+ QT4_EXTRACT_OPTIONS(_customName _qt4_dbus_options ${ARGN})
|
|
+
|
|
+ GET_FILENAME_COMPONENT(_in_file ${_header} ABSOLUTE)
|
|
+ GET_FILENAME_COMPONENT(_basename ${_header} NAME_WE)
|
|
+
|
|
+ IF (_customName)
|
|
+ SET(_target ${CMAKE_CURRENT_BINARY_DIR}/${_customName})
|
|
+ ELSE (_customName)
|
|
+ SET(_target ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.xml)
|
|
+ ENDIF (_customName)
|
|
+
|
|
+ ADD_CUSTOM_COMMAND(OUTPUT ${_target}
|
|
+ COMMAND ${QT_DBUSCPP2XML_EXECUTABLE} ${_qt4_dbus_options} ${_in_file} > ${_target}
|
|
+ DEPENDS ${_in_file}
|
|
+ )
|
|
+ ENDMACRO(QT4_GENERATE_DBUS_INTERFACE)
|
|
+
|
|
+
|
|
+ MACRO(QT4_ADD_DBUS_ADAPTOR _sources _xml_file _include _parentClass) # _optionalBasename _optionalClassName)
|
|
+ GET_FILENAME_COMPONENT(_infile ${_xml_file} ABSOLUTE)
|
|
+
|
|
+ SET(_optionalBasename "${ARGV4}")
|
|
+ IF (_optionalBasename)
|
|
+ SET(_basename ${_optionalBasename} )
|
|
+ ELSE (_optionalBasename)
|
|
+ STRING(REGEX REPLACE "(.*[/\\.])?([^\\.]+)\\.xml" "\\2adaptor" _basename ${_infile})
|
|
+ STRING(TOLOWER ${_basename} _basename)
|
|
+ ENDIF (_optionalBasename)
|
|
+
|
|
+ SET(_optionalClassName "${ARGV5}")
|
|
+ SET(_header ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.h)
|
|
+ SET(_impl ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.cpp)
|
|
+ SET(_moc ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.moc)
|
|
+
|
|
+ IF(_optionalClassName)
|
|
+ ADD_CUSTOM_COMMAND(OUTPUT ${_impl} ${_header}
|
|
+ COMMAND ${QT_DBUSXML2CPP_EXECUTABLE} -m -a ${_basename} -c ${_optionalClassName} -i ${_include} -l ${_parentClass} ${_infile}
|
|
+ DEPENDS ${_infile}
|
|
+ )
|
|
+ ELSE(_optionalClassName)
|
|
+ ADD_CUSTOM_COMMAND(OUTPUT ${_impl} ${_header}
|
|
+ COMMAND ${QT_DBUSXML2CPP_EXECUTABLE} -m -a ${_basename} -i ${_include} -l ${_parentClass} ${_infile}
|
|
+ DEPENDS ${_infile}
|
|
+ )
|
|
+ ENDIF(_optionalClassName)
|
|
+
|
|
+ QT4_GENERATE_MOC(${_header} ${_moc})
|
|
+ SET_SOURCE_FILES_PROPERTIES(${_impl} PROPERTIES SKIP_AUTOMOC TRUE)
|
|
+ MACRO_ADD_FILE_DEPENDENCIES(${_impl} ${_moc})
|
|
+
|
|
+ SET(${_sources} ${${_sources}} ${_impl} ${_header} ${_moc})
|
|
+ ENDMACRO(QT4_ADD_DBUS_ADAPTOR)
|
|
+
|
|
+ MACRO(QT4_AUTOMOC)
|
|
+ QT4_GET_MOC_INC_DIRS(_moc_INCS)
|
|
+
|
|
+ SET(_matching_FILES )
|
|
+ FOREACH (_current_FILE ${ARGN})
|
|
+
|
|
+ GET_FILENAME_COMPONENT(_abs_FILE ${_current_FILE} ABSOLUTE)
|
|
+ # if "SKIP_AUTOMOC" is set to true, we will not handle this file here.
|
|
+ # here. this is required to make bouic work correctly:
|
|
+ # we need to add generated .cpp files to the sources (to compile them),
|
|
+ # but we cannot let automoc handle them, as the .cpp files don't exist yet when
|
|
+ # cmake is run for the very first time on them -> however the .cpp files might
|
|
+ # exist at a later run. at that time we need to skip them, so that we don't add two
|
|
+ # different rules for the same moc file
|
|
+ GET_SOURCE_FILE_PROPERTY(_skip ${_abs_FILE} SKIP_AUTOMOC)
|
|
+
|
|
+ IF ( NOT _skip AND EXISTS ${_abs_FILE} )
|
|
+
|
|
+ FILE(READ ${_abs_FILE} _contents)
|
|
+
|
|
+ GET_FILENAME_COMPONENT(_abs_PATH ${_abs_FILE} PATH)
|
|
+
|
|
+ STRING(REGEX MATCHALL "#include +[^ ]+\\.moc[\">]" _match "${_contents}")
|
|
+ IF(_match)
|
|
+ FOREACH (_current_MOC_INC ${_match})
|
|
+ STRING(REGEX MATCH "[^ <\"]+\\.moc" _current_MOC "${_current_MOC_INC}")
|
|
+
|
|
+ GET_filename_component(_basename ${_current_MOC} NAME_WE)
|
|
+ # SET(_header ${CMAKE_CURRENT_SOURCE_DIR}/${_basename}.h)
|
|
+ IF (EXISTS ${_abs_PATH}/${_basename}.h)
|
|
+ SET(_header ${_abs_PATH}/${_basename}.h)
|
|
+ ELSE (EXISTS ${_abs_PATH}/${_basename}.h)
|
|
+ SET(_header ${_abs_FILE})
|
|
+ ENDIF (EXISTS ${_abs_PATH}/${_basename}.h)
|
|
+ SET(_moc ${CMAKE_CURRENT_BINARY_DIR}/${_current_MOC})
|
|
+ ADD_CUSTOM_COMMAND(OUTPUT ${_moc}
|
|
+ COMMAND ${QT4_MOC_EXECUTABLE}
|
|
+ ARGS ${_moc_INCS} ${_header} -o ${_moc}
|
|
+ DEPENDS ${_header}
|
|
+ )
|
|
+
|
|
+ MACRO_ADD_FILE_DEPENDENCIES(${_abs_FILE} ${_moc})
|
|
+ ENDFOREACH (_current_MOC_INC)
|
|
+ ENDIF(_match)
|
|
+ ENDIF ( NOT _skip AND EXISTS ${_abs_FILE} )
|
|
+ ENDFOREACH (_current_FILE)
|
|
+ ENDMACRO(QT4_AUTOMOC)
|
|
+
|
|
+
|
|
+
|
|
+ ######################################
|
|
+ #
|
|
+ # decide if Qt got found
|
|
+ #
|
|
+ ######################################
|
|
+
|
|
+ # if the includes,libraries,moc,uic and rcc are found then we have it
|
|
+ IF( QT4_LIBRARY_DIR AND QT4_INCLUDE_DIR AND QT4_MOC_EXECUTABLE AND QT4_UIC_EXECUTABLE AND QT_RCC_EXECUTABLE)
|
|
+ SET( QT4_FOUND "YES" )
|
|
+ IF( NOT Qt4_FIND_QUIETLY)
|
|
+ MESSAGE(STATUS "Found Qt-Version ${QTVERSION} (using ${QT_QMAKE_EXECUTABLE})")
|
|
+ ENDIF( NOT Qt4_FIND_QUIETLY)
|
|
+ ELSE( QT4_LIBRARY_DIR AND QT4_INCLUDE_DIR AND QT4_MOC_EXECUTABLE AND QT4_UIC_EXECUTABLE AND QT_RCC_EXECUTABLE)
|
|
+ SET( QT4_FOUND "NO")
|
|
+ SET(QT_QMAKE_EXECUTABLE "${QT_QMAKE_EXECUTABLE}-NOTFOUND" CACHE FILEPATH "Invalid qmake found" FORCE)
|
|
+ IF( Qt4_FIND_REQUIRED)
|
|
+ IF ( NOT QT4_LIBRARY_DIR )
|
|
+ MESSAGE(STATUS "Qt libraries NOT found!")
|
|
+ ENDIF(NOT QT4_LIBRARY_DIR )
|
|
+ IF ( NOT QT4_INCLUDE_DIR )
|
|
+ MESSAGE(STATUS "Qt includes NOT found!")
|
|
+ ENDIF( NOT QT4_INCLUDE_DIR )
|
|
+ IF ( NOT QT4_MOC_EXECUTABLE )
|
|
+ MESSAGE(STATUS "Qt's moc NOT found!")
|
|
+ ENDIF( NOT QT4_MOC_EXECUTABLE )
|
|
+ IF ( NOT QT4_UIC_EXECUTABLE )
|
|
+ MESSAGE(STATUS "Qt's uic NOT found!")
|
|
+ ENDIF( NOT QT4_UIC_EXECUTABLE )
|
|
+ IF ( NOT QT_RCC_EXECUTABLE )
|
|
+ MESSAGE(STATUS "Qt's rcc NOT found!")
|
|
+ ENDIF( NOT QT_RCC_EXECUTABLE )
|
|
+ MESSAGE( FATAL_ERROR "Qt libraries, includes, moc, uic or/and rcc NOT found!")
|
|
+ ENDIF( Qt4_FIND_REQUIRED)
|
|
+ ENDIF( QT4_LIBRARY_DIR AND QT4_INCLUDE_DIR AND QT4_MOC_EXECUTABLE AND QT4_UIC_EXECUTABLE AND QT_RCC_EXECUTABLE)
|
|
+ SET(QT_FOUND ${QT4_FOUND})
|
|
+
|
|
+
|
|
+ #######################################
|
|
+ #
|
|
+ # System dependent settings
|
|
+ #
|
|
+ #######################################
|
|
+ # for unix add X11 stuff
|
|
+ IF(UNIX)
|
|
+ # on OS X X11 may not be required
|
|
+ IF (Q_WS_X11)
|
|
+ FIND_PACKAGE(X11 REQUIRED)
|
|
+ ENDIF (Q_WS_X11)
|
|
+ FIND_PACKAGE(Threads)
|
|
+ SET(QT4_QTCORE_LIBRARY ${QT4_QTCORE_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
|
|
+ ENDIF(UNIX)
|
|
+
|
|
+
|
|
+ #######################################
|
|
+ #
|
|
+ # compatibility settings
|
|
+ #
|
|
+ #######################################
|
|
+ # Backwards compatibility for CMake1.4 and 1.2
|
|
+ SET (QT_MOC_EXE ${QT4_MOC_EXECUTABLE} )
|
|
+ SET (QT_UIC_EXE ${QT4_UIC_EXECUTABLE} )
|
|
+
|
|
+ SET( QT4_QT_LIBRARY "")
|
|
+
|
|
+ELSE(QT4_QMAKE_FOUND)
|
|
+
|
|
+ SET(QT_QMAKE_EXECUTABLE "${QT_QMAKE_EXECUTABLE}-NOTFOUND" CACHE FILEPATH "Invalid qmake found" FORCE)
|
|
+ IF(Qt4_FIND_REQUIRED)
|
|
+ IF(QT4_INSTALLED_VERSION_TOO_OLD)
|
|
+ MESSAGE(FATAL_ERROR "The installed Qt version ${QTVERSION} is too old, at least version ${QT4_MIN_VERSION} is required")
|
|
+ ELSE(QT4_INSTALLED_VERSION_TOO_OLD)
|
|
+ MESSAGE( FATAL_ERROR "Qt qmake not found!")
|
|
+ ENDIF(QT4_INSTALLED_VERSION_TOO_OLD)
|
|
+ ELSE(Qt4_FIND_REQUIRED)
|
|
+ IF(QT4_INSTALLED_VERSION_TOO_OLD AND NOT Qt4_FIND_QUIETLY)
|
|
+ MESSAGE(STATUS "The installed Qt version ${QTVERSION} is too old, at least version ${QT4_MIN_VERSION} is required")
|
|
+ ENDIF(QT4_INSTALLED_VERSION_TOO_OLD AND NOT Qt4_FIND_QUIETLY)
|
|
+ ENDIF(Qt4_FIND_REQUIRED)
|
|
+
|
|
+ENDIF (QT4_QMAKE_FOUND)
|
|
+ENDIF (QT4_QMAKE_FOUND)
|
|
+
|
|
diff --git a/poppler-qt4.pc.cmake b/poppler-qt4.pc.cmake
|
|
new file mode 100644
|
|
index 00000000..46a37f6d
|
|
--- /dev/null
|
|
+++ b/poppler-qt4.pc.cmake
|
|
@@ -0,0 +1,12 @@
|
|
+prefix=@CMAKE_INSTALL_PREFIX@
|
|
+libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
|
+includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
|
+
|
|
+Name: poppler-qt4
|
|
+Description: Qt4 bindings for poppler
|
|
+Version: @POPPLER_VERSION@
|
|
+Requires: @PC_REQUIRES@
|
|
+@PC_REQUIRES_PRIVATE@
|
|
+
|
|
+Libs: -L${libdir} -lpoppler-qt4
|
|
+Cflags: -I${includedir}/poppler/qt4
|
|
diff --git a/qt4/.gitignore b/qt4/.gitignore
|
|
new file mode 100644
|
|
index 00000000..5540f35d
|
|
--- /dev/null
|
|
+++ b/qt4/.gitignore
|
|
@@ -0,0 +1,4 @@
|
|
+Makefile
|
|
+Makefile.in
|
|
+*~
|
|
+
|
|
diff --git a/qt4/CMakeLists.txt b/qt4/CMakeLists.txt
|
|
new file mode 100644
|
|
index 00000000..4d345681
|
|
--- /dev/null
|
|
+++ b/qt4/CMakeLists.txt
|
|
@@ -0,0 +1,6 @@
|
|
+# Qt4 headers are not override clean so disable suggest-override if it's there
|
|
+string(REPLACE "-Wsuggest-override" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
|
+
|
|
+add_subdirectory(src)
|
|
+add_subdirectory(tests)
|
|
+add_subdirectory(demos)
|
|
diff --git a/qt4/demos/.gitignore b/qt4/demos/.gitignore
|
|
new file mode 100644
|
|
index 00000000..9639e685
|
|
--- /dev/null
|
|
+++ b/qt4/demos/.gitignore
|
|
@@ -0,0 +1,4 @@
|
|
+.deps
|
|
+.libs
|
|
+*moc
|
|
+poppler_qt4viewer
|
|
diff --git a/qt4/demos/CMakeLists.txt b/qt4/demos/CMakeLists.txt
|
|
new file mode 100644
|
|
index 00000000..76accf81
|
|
--- /dev/null
|
|
+++ b/qt4/demos/CMakeLists.txt
|
|
@@ -0,0 +1,28 @@
|
|
+add_definitions(${QT4_DEFINITIONS})
|
|
+
|
|
+include_directories(
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../src
|
|
+ ${CMAKE_CURRENT_BINARY_DIR}
|
|
+ ${QT4_INCLUDE_DIR}
|
|
+)
|
|
+
|
|
+set(poppler_qt4viewer_SRCS
|
|
+ abstractinfodock.cpp
|
|
+ documentobserver.cpp
|
|
+ embeddedfiles.cpp
|
|
+ fonts.cpp
|
|
+ info.cpp
|
|
+ main_viewer.cpp
|
|
+ metadata.cpp
|
|
+ navigationtoolbar.cpp
|
|
+ optcontent.cpp
|
|
+ pageview.cpp
|
|
+ permissions.cpp
|
|
+ thumbnails.cpp
|
|
+ toc.cpp
|
|
+ viewer.cpp
|
|
+)
|
|
+qt4_automoc(${poppler_qt4viewer_SRCS})
|
|
+poppler_add_test(poppler_qt4viewer BUILD_QT4_TESTS ${poppler_qt4viewer_SRCS})
|
|
+target_link_libraries(poppler_qt4viewer poppler-qt4)
|
|
diff --git a/qt4/demos/abstractinfodock.cpp b/qt4/demos/abstractinfodock.cpp
|
|
new file mode 100644
|
|
index 00000000..7b306d82
|
|
--- /dev/null
|
|
+++ b/qt4/demos/abstractinfodock.cpp
|
|
@@ -0,0 +1,57 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "fonts.h"
|
|
+
|
|
+AbstractInfoDock::AbstractInfoDock(QWidget *parent)
|
|
+ : QDockWidget(parent), m_filled(false)
|
|
+{
|
|
+ connect(this, SIGNAL(visibilityChanged(bool)), SLOT(slotVisibilityChanged(bool)));
|
|
+}
|
|
+
|
|
+AbstractInfoDock::~AbstractInfoDock()
|
|
+{
|
|
+}
|
|
+
|
|
+void AbstractInfoDock::documentLoaded()
|
|
+{
|
|
+ if (!isHidden()) {
|
|
+ fillInfo();
|
|
+ m_filled = true;
|
|
+ }
|
|
+}
|
|
+
|
|
+void AbstractInfoDock::documentClosed()
|
|
+{
|
|
+ m_filled = false;
|
|
+}
|
|
+
|
|
+void AbstractInfoDock::pageChanged(int page)
|
|
+{
|
|
+ Q_UNUSED(page)
|
|
+}
|
|
+
|
|
+void AbstractInfoDock::slotVisibilityChanged(bool visible)
|
|
+{
|
|
+ if (visible && document() && !m_filled) {
|
|
+ fillInfo();
|
|
+ m_filled = true;
|
|
+ }
|
|
+}
|
|
+
|
|
+#include "abstractinfodock.moc"
|
|
diff --git a/qt4/demos/abstractinfodock.h b/qt4/demos/abstractinfodock.h
|
|
new file mode 100644
|
|
index 00000000..2593325a
|
|
--- /dev/null
|
|
+++ b/qt4/demos/abstractinfodock.h
|
|
@@ -0,0 +1,48 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef ABSTRACTINFODOCK_H
|
|
+#define ABSTRACTINFODOCK_H
|
|
+
|
|
+#include <QtGui/QDockWidget>
|
|
+
|
|
+#include "documentobserver.h"
|
|
+
|
|
+class AbstractInfoDock : public QDockWidget, public DocumentObserver
|
|
+{
|
|
+ Q_OBJECT
|
|
+
|
|
+public:
|
|
+ AbstractInfoDock(QWidget *parent = 0);
|
|
+ ~AbstractInfoDock();
|
|
+
|
|
+ /*virtual*/ void documentLoaded();
|
|
+ /*virtual*/ void documentClosed();
|
|
+ /*virtual*/ void pageChanged(int page);
|
|
+
|
|
+protected:
|
|
+ virtual void fillInfo() = 0;
|
|
+
|
|
+private Q_SLOTS:
|
|
+ void slotVisibilityChanged(bool visible);
|
|
+
|
|
+private:
|
|
+ bool m_filled;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/demos/documentobserver.cpp b/qt4/demos/documentobserver.cpp
|
|
new file mode 100644
|
|
index 00000000..e5c283db
|
|
--- /dev/null
|
|
+++ b/qt4/demos/documentobserver.cpp
|
|
@@ -0,0 +1,50 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "documentobserver.h"
|
|
+
|
|
+#include "viewer.h"
|
|
+
|
|
+DocumentObserver::DocumentObserver()
|
|
+ : m_viewer(0)
|
|
+{
|
|
+}
|
|
+
|
|
+DocumentObserver::~DocumentObserver()
|
|
+{
|
|
+}
|
|
+
|
|
+Poppler::Document* DocumentObserver::document() const
|
|
+{
|
|
+ return m_viewer->m_doc;
|
|
+}
|
|
+
|
|
+void DocumentObserver::setPage(int page)
|
|
+{
|
|
+ m_viewer->setPage(page);
|
|
+}
|
|
+
|
|
+int DocumentObserver::page() const
|
|
+{
|
|
+ return m_viewer->page();
|
|
+}
|
|
+
|
|
+void DocumentObserver::reloadPage()
|
|
+{
|
|
+ m_viewer->setPage(m_viewer->page());
|
|
+}
|
|
diff --git a/qt4/demos/documentobserver.h b/qt4/demos/documentobserver.h
|
|
new file mode 100644
|
|
index 00000000..38fe2043
|
|
--- /dev/null
|
|
+++ b/qt4/demos/documentobserver.h
|
|
@@ -0,0 +1,50 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef DOCUMENTOBSERVER_H
|
|
+#define DOCUMENTOBSERVER_H
|
|
+
|
|
+class PdfViewer;
|
|
+namespace Poppler {
|
|
+class Document;
|
|
+}
|
|
+
|
|
+class DocumentObserver
|
|
+{
|
|
+friend class PdfViewer;
|
|
+
|
|
+public:
|
|
+ virtual ~DocumentObserver();
|
|
+
|
|
+ virtual void documentLoaded() = 0;
|
|
+ virtual void documentClosed() = 0;
|
|
+ virtual void pageChanged(int page) = 0;
|
|
+
|
|
+protected:
|
|
+ DocumentObserver();
|
|
+
|
|
+ Poppler::Document* document() const;
|
|
+ void setPage(int page);
|
|
+ int page() const;
|
|
+ void reloadPage();
|
|
+
|
|
+private:
|
|
+ PdfViewer *m_viewer;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/demos/embeddedfiles.cpp b/qt4/demos/embeddedfiles.cpp
|
|
new file mode 100644
|
|
index 00000000..22f9da7a
|
|
--- /dev/null
|
|
+++ b/qt4/demos/embeddedfiles.cpp
|
|
@@ -0,0 +1,82 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "embeddedfiles.h"
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <QtGui/QTableWidget>
|
|
+
|
|
+EmbeddedFilesDock::EmbeddedFilesDock(QWidget *parent)
|
|
+ : AbstractInfoDock(parent)
|
|
+{
|
|
+ m_table = new QTableWidget(this);
|
|
+ setWidget(m_table);
|
|
+ setWindowTitle(tr("Embedded files"));
|
|
+ m_table->setColumnCount(6);
|
|
+ m_table->setHorizontalHeaderLabels(
|
|
+ QStringList() << tr("Name") << tr("Description") << tr("Size") << tr("Creation date")
|
|
+ << tr("Modification date") << tr("Checksum"));
|
|
+ m_table->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
|
+}
|
|
+
|
|
+EmbeddedFilesDock::~EmbeddedFilesDock()
|
|
+{
|
|
+}
|
|
+
|
|
+void EmbeddedFilesDock::fillInfo()
|
|
+{
|
|
+ m_table->setHorizontalHeaderLabels(
|
|
+ QStringList() << tr("Name") << tr("Description") << tr("Size") << tr("Creation date")
|
|
+ << tr("Modification date") << tr("Checksum"));
|
|
+ if (!document()->hasEmbeddedFiles()) {
|
|
+ m_table->setItem(0, 0, new QTableWidgetItem(tr("No files")));
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ const QList<Poppler::EmbeddedFile*> files = document()->embeddedFiles();
|
|
+ m_table->setRowCount(files.count());
|
|
+ int i = 0;
|
|
+ Q_FOREACH(Poppler::EmbeddedFile *file, files) {
|
|
+ m_table->setItem(i, 0, new QTableWidgetItem(file->name()));
|
|
+ m_table->setItem(i, 1, new QTableWidgetItem(file->description()));
|
|
+ m_table->setItem(i, 2, new QTableWidgetItem(QString::number(file->size())));
|
|
+ m_table->setItem(i, 3, new QTableWidgetItem(file->createDate().toString(Qt::SystemLocaleDate)));
|
|
+ m_table->setItem(i, 4, new QTableWidgetItem(file->modDate().toString(Qt::SystemLocaleDate)));
|
|
+ const QByteArray checksum = file->checksum();
|
|
+ const QString checksumString = !checksum.isEmpty() ? QString::fromAscii(checksum.toHex()) : QString::fromLatin1("n/a");
|
|
+ m_table->setItem(i, 5, new QTableWidgetItem(checksumString));
|
|
+ ++i;
|
|
+ }
|
|
+}
|
|
+
|
|
+void EmbeddedFilesDock::documentLoaded()
|
|
+{
|
|
+ if ( document()->pageMode() == Poppler::Document::UseAttach ) {
|
|
+ show();
|
|
+ }
|
|
+}
|
|
+
|
|
+void EmbeddedFilesDock::documentClosed()
|
|
+{
|
|
+ m_table->clear();
|
|
+ m_table->setRowCount(0);
|
|
+ AbstractInfoDock::documentClosed();
|
|
+}
|
|
+
|
|
+#include "embeddedfiles.moc"
|
|
diff --git a/qt4/demos/embeddedfiles.h b/qt4/demos/embeddedfiles.h
|
|
new file mode 100644
|
|
index 00000000..7cd60397
|
|
--- /dev/null
|
|
+++ b/qt4/demos/embeddedfiles.h
|
|
@@ -0,0 +1,44 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef ATTACHMENTS_H
|
|
+#define ATTACHMENTS_H
|
|
+
|
|
+#include "abstractinfodock.h"
|
|
+
|
|
+class QTableWidget;
|
|
+
|
|
+class EmbeddedFilesDock : public AbstractInfoDock
|
|
+{
|
|
+ Q_OBJECT
|
|
+
|
|
+public:
|
|
+ EmbeddedFilesDock(QWidget *parent = 0);
|
|
+ ~EmbeddedFilesDock();
|
|
+
|
|
+ virtual void documentLoaded();
|
|
+ /*virtual*/ void documentClosed();
|
|
+
|
|
+protected:
|
|
+ /*virtual*/ void fillInfo();
|
|
+
|
|
+private:
|
|
+ QTableWidget *m_table;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/demos/fonts.cpp b/qt4/demos/fonts.cpp
|
|
new file mode 100644
|
|
index 00000000..bd342bd2
|
|
--- /dev/null
|
|
+++ b/qt4/demos/fonts.cpp
|
|
@@ -0,0 +1,72 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "fonts.h"
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <QtGui/QTableWidget>
|
|
+
|
|
+static QString yesNoStatement(bool value)
|
|
+{
|
|
+ return value ? QString::fromLatin1("yes") : QString::fromLatin1("no");
|
|
+}
|
|
+
|
|
+FontsDock::FontsDock(QWidget *parent)
|
|
+ : AbstractInfoDock(parent)
|
|
+{
|
|
+ m_table = new QTableWidget(this);
|
|
+ setWidget(m_table);
|
|
+ setWindowTitle(tr("Fonts"));
|
|
+ m_table->setColumnCount(5);
|
|
+ m_table->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Type") << tr("Embedded") << tr("Subset") << tr("File"));
|
|
+ m_table->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
|
+}
|
|
+
|
|
+FontsDock::~FontsDock()
|
|
+{
|
|
+}
|
|
+
|
|
+void FontsDock::fillInfo()
|
|
+{
|
|
+ const QList<Poppler::FontInfo> fonts = document()->fonts();
|
|
+ m_table->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Type") << tr("Embedded") << tr("Subset") << tr("File"));
|
|
+ m_table->setRowCount(fonts.count());
|
|
+ int i = 0;
|
|
+ Q_FOREACH(const Poppler::FontInfo &font, fonts) {
|
|
+ if (font.name().isNull()) {
|
|
+ m_table->setItem(i, 0, new QTableWidgetItem(QString::fromLatin1("[none]")));
|
|
+ } else {
|
|
+ m_table->setItem(i, 0, new QTableWidgetItem(font.name()));
|
|
+ }
|
|
+ m_table->setItem(i, 1, new QTableWidgetItem(font.typeName()));
|
|
+ m_table->setItem(i, 2, new QTableWidgetItem(yesNoStatement(font.isEmbedded())));
|
|
+ m_table->setItem(i, 3, new QTableWidgetItem(yesNoStatement(font.isSubset())));
|
|
+ m_table->setItem(i, 4, new QTableWidgetItem(font.file()));
|
|
+ ++i;
|
|
+ }
|
|
+}
|
|
+
|
|
+void FontsDock::documentClosed()
|
|
+{
|
|
+ m_table->clear();
|
|
+ m_table->setRowCount(0);
|
|
+ AbstractInfoDock::documentClosed();
|
|
+}
|
|
+
|
|
+#include "fonts.moc"
|
|
diff --git a/qt4/demos/fonts.h b/qt4/demos/fonts.h
|
|
new file mode 100644
|
|
index 00000000..81afa579
|
|
--- /dev/null
|
|
+++ b/qt4/demos/fonts.h
|
|
@@ -0,0 +1,43 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef FONTS_H
|
|
+#define FONTS_H
|
|
+
|
|
+#include "abstractinfodock.h"
|
|
+
|
|
+class QTableWidget;
|
|
+
|
|
+class FontsDock : public AbstractInfoDock
|
|
+{
|
|
+ Q_OBJECT
|
|
+
|
|
+public:
|
|
+ FontsDock(QWidget *parent = 0);
|
|
+ ~FontsDock();
|
|
+
|
|
+ /*virtual*/ void documentClosed();
|
|
+
|
|
+protected:
|
|
+ /*virtual*/ void fillInfo();
|
|
+
|
|
+private:
|
|
+ QTableWidget *m_table;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/demos/info.cpp b/qt4/demos/info.cpp
|
|
new file mode 100644
|
|
index 00000000..6491e0e4
|
|
--- /dev/null
|
|
+++ b/qt4/demos/info.cpp
|
|
@@ -0,0 +1,72 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "info.h"
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <QtGui/QTableWidget>
|
|
+
|
|
+InfoDock::InfoDock(QWidget *parent)
|
|
+ : AbstractInfoDock(parent)
|
|
+{
|
|
+ m_table = new QTableWidget(this);
|
|
+ setWidget(m_table);
|
|
+ setWindowTitle(tr("Information"));
|
|
+ m_table->setColumnCount(2);
|
|
+ m_table->setHorizontalHeaderLabels(QStringList() << tr("Key") << tr("Value"));
|
|
+ m_table->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
|
+}
|
|
+
|
|
+InfoDock::~InfoDock()
|
|
+{
|
|
+}
|
|
+
|
|
+void InfoDock::fillInfo()
|
|
+{
|
|
+ QStringList keys = document()->infoKeys();
|
|
+ m_table->setHorizontalHeaderLabels(QStringList() << tr("Key") << tr("Value"));
|
|
+ m_table->setRowCount(keys.count());
|
|
+ QStringList dateKeys;
|
|
+ dateKeys << QString::fromLatin1("CreationDate");
|
|
+ dateKeys << QString::fromLatin1("ModDate");
|
|
+ int i = 0;
|
|
+ Q_FOREACH(const QString &date, dateKeys) {
|
|
+ const int id = keys.indexOf(date);
|
|
+ if (id != -1) {
|
|
+ m_table->setItem(i, 0, new QTableWidgetItem(date));
|
|
+ m_table->setItem(i, 1, new QTableWidgetItem(document()->date(date).toString(Qt::SystemLocaleDate)));
|
|
+ ++i;
|
|
+ keys.removeAt(id);
|
|
+ }
|
|
+ }
|
|
+ Q_FOREACH(const QString &key, keys) {
|
|
+ m_table->setItem(i, 0, new QTableWidgetItem(key));
|
|
+ m_table->setItem(i, 1, new QTableWidgetItem(document()->info(key)));
|
|
+ ++i;
|
|
+ }
|
|
+}
|
|
+
|
|
+void InfoDock::documentClosed()
|
|
+{
|
|
+ m_table->clear();
|
|
+ m_table->setRowCount(0);
|
|
+ AbstractInfoDock::documentClosed();
|
|
+}
|
|
+
|
|
+#include "info.moc"
|
|
diff --git a/qt4/demos/info.h b/qt4/demos/info.h
|
|
new file mode 100644
|
|
index 00000000..d294b430
|
|
--- /dev/null
|
|
+++ b/qt4/demos/info.h
|
|
@@ -0,0 +1,43 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef INFO_H
|
|
+#define INFO_H
|
|
+
|
|
+#include "abstractinfodock.h"
|
|
+
|
|
+class QTableWidget;
|
|
+
|
|
+class InfoDock : public AbstractInfoDock
|
|
+{
|
|
+ Q_OBJECT
|
|
+
|
|
+public:
|
|
+ InfoDock(QWidget *parent = 0);
|
|
+ ~InfoDock();
|
|
+
|
|
+ /*virtual*/ void documentClosed();
|
|
+
|
|
+protected:
|
|
+ /*virtual*/ void fillInfo();
|
|
+
|
|
+private:
|
|
+ QTableWidget *m_table;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/demos/main_viewer.cpp b/qt4/demos/main_viewer.cpp
|
|
new file mode 100644
|
|
index 00000000..3f7080f2
|
|
--- /dev/null
|
|
+++ b/qt4/demos/main_viewer.cpp
|
|
@@ -0,0 +1,33 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "viewer.h"
|
|
+
|
|
+#include <QtGui/QApplication>
|
|
+
|
|
+int main(int argc, char *argv[])
|
|
+{
|
|
+ QApplication app(argc, argv);
|
|
+ const QStringList args = QCoreApplication::arguments();
|
|
+ PdfViewer *viewer = new PdfViewer();
|
|
+ viewer->show();
|
|
+ if (args.count() > 1) {
|
|
+ viewer->loadDocument(args.at(1));
|
|
+ }
|
|
+ return app.exec();
|
|
+}
|
|
diff --git a/qt4/demos/metadata.cpp b/qt4/demos/metadata.cpp
|
|
new file mode 100644
|
|
index 00000000..e5c7111d
|
|
--- /dev/null
|
|
+++ b/qt4/demos/metadata.cpp
|
|
@@ -0,0 +1,50 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "metadata.h"
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <QtGui/QTextEdit>
|
|
+
|
|
+MetadataDock::MetadataDock(QWidget *parent)
|
|
+ : AbstractInfoDock(parent)
|
|
+{
|
|
+ m_edit = new QTextEdit(this);
|
|
+ setWidget(m_edit);
|
|
+ setWindowTitle(tr("Metadata"));
|
|
+ m_edit->setAcceptRichText(false);
|
|
+ m_edit->setReadOnly(true);
|
|
+}
|
|
+
|
|
+MetadataDock::~MetadataDock()
|
|
+{
|
|
+}
|
|
+
|
|
+void MetadataDock::fillInfo()
|
|
+{
|
|
+ m_edit->setPlainText(document()->metadata());
|
|
+}
|
|
+
|
|
+void MetadataDock::documentClosed()
|
|
+{
|
|
+ m_edit->clear();
|
|
+ AbstractInfoDock::documentClosed();
|
|
+}
|
|
+
|
|
+#include "metadata.moc"
|
|
diff --git a/qt4/demos/metadata.h b/qt4/demos/metadata.h
|
|
new file mode 100644
|
|
index 00000000..6f1507a6
|
|
--- /dev/null
|
|
+++ b/qt4/demos/metadata.h
|
|
@@ -0,0 +1,43 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef METADATA_H
|
|
+#define METADATA_H
|
|
+
|
|
+#include "abstractinfodock.h"
|
|
+
|
|
+class QTextEdit;
|
|
+
|
|
+class MetadataDock : public AbstractInfoDock
|
|
+{
|
|
+ Q_OBJECT
|
|
+
|
|
+public:
|
|
+ MetadataDock(QWidget *parent = 0);
|
|
+ ~MetadataDock();
|
|
+
|
|
+ /*virtual*/ void documentClosed();
|
|
+
|
|
+protected:
|
|
+ /*virtual*/ void fillInfo();
|
|
+
|
|
+private:
|
|
+ QTextEdit *m_edit;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/demos/navigationtoolbar.cpp b/qt4/demos/navigationtoolbar.cpp
|
|
new file mode 100644
|
|
index 00000000..79dd418a
|
|
--- /dev/null
|
|
+++ b/qt4/demos/navigationtoolbar.cpp
|
|
@@ -0,0 +1,144 @@
|
|
+/*
|
|
+ * Copyright (C) 2008-2009, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2013, Fabio D'Urso <fabiodurso@hotmail.it>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "navigationtoolbar.h"
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <QtGui/QAction>
|
|
+#include <QtGui/QComboBox>
|
|
+
|
|
+NavigationToolBar::NavigationToolBar(QWidget *parent)
|
|
+ : QToolBar(parent)
|
|
+{
|
|
+ m_firstAct = addAction(tr("First"), this, SLOT(slotGoFirst()));
|
|
+ m_prevAct = addAction(tr("Previous"), this, SLOT(slotGoPrev()));
|
|
+ m_pageCombo = new QComboBox(this);
|
|
+ connect(m_pageCombo, SIGNAL(activated(int)), this, SLOT(slotComboActivated(int)));
|
|
+ addWidget(m_pageCombo);
|
|
+ m_nextAct = addAction(tr("Next"), this, SLOT(slotGoNext()));
|
|
+ m_lastAct = addAction(tr("Last"), this, SLOT(slotGoLast()));
|
|
+
|
|
+ addSeparator();
|
|
+
|
|
+ m_zoomCombo = new QComboBox(this);
|
|
+ m_zoomCombo->setEditable(true);
|
|
+ m_zoomCombo->addItem(tr("10%"));
|
|
+ m_zoomCombo->addItem(tr("25%"));
|
|
+ m_zoomCombo->addItem(tr("33%"));
|
|
+ m_zoomCombo->addItem(tr("50%"));
|
|
+ m_zoomCombo->addItem(tr("66%"));
|
|
+ m_zoomCombo->addItem(tr("75%"));
|
|
+ m_zoomCombo->addItem(tr("100%"));
|
|
+ m_zoomCombo->addItem(tr("125%"));
|
|
+ m_zoomCombo->addItem(tr("150%"));
|
|
+ m_zoomCombo->addItem(tr("200%"));
|
|
+ m_zoomCombo->addItem(tr("300%"));
|
|
+ m_zoomCombo->addItem(tr("400%"));
|
|
+ m_zoomCombo->setCurrentIndex(6); // "100%"
|
|
+ connect(m_zoomCombo, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotZoomComboChanged(QString)));
|
|
+ addWidget(m_zoomCombo);
|
|
+
|
|
+ m_rotationCombo = new QComboBox(this);
|
|
+ // NOTE: \302\260 = degree symbol
|
|
+ m_rotationCombo->addItem(trUtf8("0\302\260"));
|
|
+ m_rotationCombo->addItem(trUtf8("90\302\260"));
|
|
+ m_rotationCombo->addItem(trUtf8("180\302\260"));
|
|
+ m_rotationCombo->addItem(trUtf8("270\302\260"));
|
|
+ connect(m_rotationCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotRotationComboChanged(int)));
|
|
+ addWidget(m_rotationCombo);
|
|
+
|
|
+ documentClosed();
|
|
+}
|
|
+
|
|
+NavigationToolBar::~NavigationToolBar()
|
|
+{
|
|
+}
|
|
+
|
|
+void NavigationToolBar::documentLoaded()
|
|
+{
|
|
+ const int pageCount = document()->numPages();
|
|
+ for (int i = 0; i < pageCount; ++i) {
|
|
+ m_pageCombo->addItem(QString::number(i + 1));
|
|
+ }
|
|
+ m_pageCombo->setEnabled(true);
|
|
+}
|
|
+
|
|
+void NavigationToolBar::documentClosed()
|
|
+{
|
|
+ m_firstAct->setEnabled(false);
|
|
+ m_prevAct->setEnabled(false);
|
|
+ m_nextAct->setEnabled(false);
|
|
+ m_lastAct->setEnabled(false);
|
|
+ m_pageCombo->clear();
|
|
+ m_pageCombo->setEnabled(false);
|
|
+}
|
|
+
|
|
+void NavigationToolBar::pageChanged(int page)
|
|
+{
|
|
+ const int pageCount = document()->numPages();
|
|
+ m_firstAct->setEnabled(page > 0);
|
|
+ m_prevAct->setEnabled(page > 0);
|
|
+ m_nextAct->setEnabled(page < (pageCount - 1));
|
|
+ m_lastAct->setEnabled(page < (pageCount - 1));
|
|
+ m_pageCombo->setCurrentIndex(page);
|
|
+}
|
|
+
|
|
+void NavigationToolBar::slotGoFirst()
|
|
+{
|
|
+ setPage(0);
|
|
+}
|
|
+
|
|
+void NavigationToolBar::slotGoPrev()
|
|
+{
|
|
+ setPage(page() - 1);
|
|
+}
|
|
+
|
|
+void NavigationToolBar::slotGoNext()
|
|
+{
|
|
+ setPage(page() + 1);
|
|
+}
|
|
+
|
|
+void NavigationToolBar::slotGoLast()
|
|
+{
|
|
+ setPage(document()->numPages() - 1);
|
|
+}
|
|
+
|
|
+void NavigationToolBar::slotComboActivated(int index)
|
|
+{
|
|
+ setPage(index);
|
|
+}
|
|
+
|
|
+void NavigationToolBar::slotZoomComboChanged(const QString &_text)
|
|
+{
|
|
+ QString text = _text;
|
|
+ text.remove(QLatin1Char('%'));
|
|
+ bool ok = false;
|
|
+ int value = text.toInt(&ok);
|
|
+ if (ok && value >= 10) {
|
|
+ emit zoomChanged(qreal(value) / 100);
|
|
+ }
|
|
+}
|
|
+
|
|
+void NavigationToolBar::slotRotationComboChanged(int idx)
|
|
+{
|
|
+ emit rotationChanged(idx * 90);
|
|
+}
|
|
+
|
|
+#include "navigationtoolbar.moc"
|
|
diff --git a/qt4/demos/navigationtoolbar.h b/qt4/demos/navigationtoolbar.h
|
|
new file mode 100644
|
|
index 00000000..d7dbd5dd
|
|
--- /dev/null
|
|
+++ b/qt4/demos/navigationtoolbar.h
|
|
@@ -0,0 +1,65 @@
|
|
+/*
|
|
+ * Copyright (C) 2008-2009, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2013, Fabio D'Urso <fabiodurso@hotmail.it>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef NAVIGATIONTOOLBAR_H
|
|
+#define NAVIGATIONTOOLBAR_H
|
|
+
|
|
+#include <QtGui/QToolBar>
|
|
+
|
|
+#include "documentobserver.h"
|
|
+
|
|
+class QAction;
|
|
+class QComboBox;
|
|
+
|
|
+class NavigationToolBar : public QToolBar, public DocumentObserver
|
|
+{
|
|
+ Q_OBJECT
|
|
+
|
|
+public:
|
|
+ NavigationToolBar(QWidget *parent = 0);
|
|
+ ~NavigationToolBar();
|
|
+
|
|
+ /*virtual*/ void documentLoaded();
|
|
+ /*virtual*/ void documentClosed();
|
|
+ /*virtual*/ void pageChanged(int page);
|
|
+
|
|
+Q_SIGNALS:
|
|
+ void zoomChanged(qreal value);
|
|
+ void rotationChanged(int rotation);
|
|
+
|
|
+private Q_SLOTS:
|
|
+ void slotGoFirst();
|
|
+ void slotGoPrev();
|
|
+ void slotGoNext();
|
|
+ void slotGoLast();
|
|
+ void slotComboActivated(int index);
|
|
+ void slotZoomComboChanged(const QString &text);
|
|
+ void slotRotationComboChanged(int idx);
|
|
+
|
|
+private:
|
|
+ QAction *m_firstAct;
|
|
+ QAction *m_prevAct;
|
|
+ QComboBox *m_pageCombo;
|
|
+ QAction *m_nextAct;
|
|
+ QAction *m_lastAct;
|
|
+ QComboBox *m_zoomCombo;
|
|
+ QComboBox *m_rotationCombo;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/demos/optcontent.cpp b/qt4/demos/optcontent.cpp
|
|
new file mode 100644
|
|
index 00000000..0c1015b9
|
|
--- /dev/null
|
|
+++ b/qt4/demos/optcontent.cpp
|
|
@@ -0,0 +1,69 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "optcontent.h"
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <QtGui/QTreeView>
|
|
+
|
|
+OptContentDock::OptContentDock(QWidget *parent)
|
|
+ : AbstractInfoDock(parent)
|
|
+{
|
|
+ m_view = new QTreeView(this);
|
|
+ setWidget(m_view);
|
|
+ setWindowTitle(tr("Optional content"));
|
|
+ m_view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
|
+}
|
|
+
|
|
+OptContentDock::~OptContentDock()
|
|
+{
|
|
+}
|
|
+
|
|
+
|
|
+void OptContentDock::documentLoaded()
|
|
+{
|
|
+ AbstractInfoDock::documentLoaded();
|
|
+ if ( document()->pageMode() == Poppler::Document::UseOC ) {
|
|
+ show();
|
|
+ }
|
|
+}
|
|
+
|
|
+void OptContentDock::fillInfo()
|
|
+{
|
|
+ if (!document()->hasOptionalContent()) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ m_view->setModel(document()->optionalContentModel());
|
|
+ connect(m_view->model(), SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(reloadImage()));
|
|
+ m_view->expandToDepth(1);
|
|
+}
|
|
+
|
|
+void OptContentDock::documentClosed()
|
|
+{
|
|
+ m_view->setModel(0);
|
|
+ AbstractInfoDock::documentClosed();
|
|
+}
|
|
+
|
|
+void OptContentDock::reloadImage()
|
|
+{
|
|
+ reloadPage();
|
|
+}
|
|
+
|
|
+#include "optcontent.moc"
|
|
diff --git a/qt4/demos/optcontent.h b/qt4/demos/optcontent.h
|
|
new file mode 100644
|
|
index 00000000..b933f5cd
|
|
--- /dev/null
|
|
+++ b/qt4/demos/optcontent.h
|
|
@@ -0,0 +1,47 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef OPTCONTENT_H
|
|
+#define OPTCONTENT_H
|
|
+
|
|
+#include "abstractinfodock.h"
|
|
+
|
|
+class QTreeView;
|
|
+
|
|
+class OptContentDock : public AbstractInfoDock
|
|
+{
|
|
+ Q_OBJECT
|
|
+
|
|
+public:
|
|
+ OptContentDock(QWidget *parent = 0);
|
|
+ ~OptContentDock();
|
|
+
|
|
+ /*virtual*/ void documentLoaded();
|
|
+ /*virtual*/ void documentClosed();
|
|
+
|
|
+protected:
|
|
+ /*virtual*/ void fillInfo();
|
|
+
|
|
+private Q_SLOTS:
|
|
+ void reloadImage();
|
|
+
|
|
+private:
|
|
+ QTreeView *m_view;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/demos/pageview.cpp b/qt4/demos/pageview.cpp
|
|
new file mode 100644
|
|
index 00000000..0dfa5e9e
|
|
--- /dev/null
|
|
+++ b/qt4/demos/pageview.cpp
|
|
@@ -0,0 +1,101 @@
|
|
+/*
|
|
+ * Copyright (C) 2008-2009, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2013, Fabio D'Urso <fabiodurso@hotmail.it>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "pageview.h"
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <QtGui/QApplication>
|
|
+#include <QtGui/QDesktopWidget>
|
|
+#include <QtGui/QImage>
|
|
+#include <QtGui/QLabel>
|
|
+#include <QtGui/QPixmap>
|
|
+
|
|
+PageView::PageView(QWidget *parent)
|
|
+ : QScrollArea(parent)
|
|
+ , m_zoom(1.0)
|
|
+ , m_rotation(0)
|
|
+ , m_dpiX(QApplication::desktop()->physicalDpiX())
|
|
+ , m_dpiY(QApplication::desktop()->physicalDpiY())
|
|
+{
|
|
+ m_imageLabel = new QLabel(this);
|
|
+ m_imageLabel->resize(0, 0);
|
|
+ setWidget(m_imageLabel);
|
|
+}
|
|
+
|
|
+PageView::~PageView()
|
|
+{
|
|
+}
|
|
+
|
|
+void PageView::documentLoaded()
|
|
+{
|
|
+}
|
|
+
|
|
+void PageView::documentClosed()
|
|
+{
|
|
+ m_imageLabel->clear();
|
|
+ m_imageLabel->resize(0, 0);
|
|
+}
|
|
+
|
|
+void PageView::pageChanged(int page)
|
|
+{
|
|
+ Poppler::Page *popplerPage = document()->page(page);
|
|
+ const double resX = m_dpiX * m_zoom;
|
|
+ const double resY = m_dpiY * m_zoom;
|
|
+
|
|
+ Poppler::Page::Rotation rot;
|
|
+ if (m_rotation == 0)
|
|
+ rot = Poppler::Page::Rotate0;
|
|
+ else if (m_rotation == 90)
|
|
+ rot = Poppler::Page::Rotate90;
|
|
+ else if (m_rotation == 180)
|
|
+ rot = Poppler::Page::Rotate180;
|
|
+ else // m_rotation == 270
|
|
+ rot = Poppler::Page::Rotate270;
|
|
+
|
|
+ QImage image = popplerPage->renderToImage(resX, resY, -1, -1, -1, -1, rot);
|
|
+ if (!image.isNull()) {
|
|
+ m_imageLabel->resize(image.size());
|
|
+ m_imageLabel->setPixmap(QPixmap::fromImage(image));
|
|
+ } else {
|
|
+ m_imageLabel->resize(0, 0);
|
|
+ m_imageLabel->setPixmap(QPixmap());
|
|
+ }
|
|
+ delete popplerPage;
|
|
+}
|
|
+
|
|
+void PageView::slotZoomChanged(qreal value)
|
|
+{
|
|
+ m_zoom = value;
|
|
+ if (!document()) {
|
|
+ return;
|
|
+ }
|
|
+ reloadPage();
|
|
+}
|
|
+
|
|
+void PageView::slotRotationChanged(int value)
|
|
+{
|
|
+ m_rotation = value;
|
|
+ if (!document()) {
|
|
+ return;
|
|
+ }
|
|
+ reloadPage();
|
|
+}
|
|
+
|
|
+#include "pageview.moc"
|
|
diff --git a/qt4/demos/pageview.h b/qt4/demos/pageview.h
|
|
new file mode 100644
|
|
index 00000000..24065028
|
|
--- /dev/null
|
|
+++ b/qt4/demos/pageview.h
|
|
@@ -0,0 +1,53 @@
|
|
+/*
|
|
+ * Copyright (C) 2008-2009, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2013, Fabio D'Urso <fabiodurso@hotmail.it>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef PAGEVIEW_H
|
|
+#define PAGEVIEW_H
|
|
+
|
|
+#include <QtGui/QScrollArea>
|
|
+
|
|
+#include "documentobserver.h"
|
|
+
|
|
+class QLabel;
|
|
+
|
|
+class PageView : public QScrollArea, public DocumentObserver
|
|
+{
|
|
+ Q_OBJECT
|
|
+
|
|
+public:
|
|
+ PageView(QWidget *parent = 0);
|
|
+ ~PageView();
|
|
+
|
|
+ /*virtual*/ void documentLoaded();
|
|
+ /*virtual*/ void documentClosed();
|
|
+ /*virtual*/ void pageChanged(int page);
|
|
+
|
|
+private Q_SLOTS:
|
|
+ void slotZoomChanged(qreal value);
|
|
+ void slotRotationChanged(int value);
|
|
+
|
|
+private:
|
|
+ QLabel *m_imageLabel;
|
|
+ qreal m_zoom;
|
|
+ int m_rotation;
|
|
+ int m_dpiX;
|
|
+ int m_dpiY;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/demos/permissions.cpp b/qt4/demos/permissions.cpp
|
|
new file mode 100644
|
|
index 00000000..38205b2e
|
|
--- /dev/null
|
|
+++ b/qt4/demos/permissions.cpp
|
|
@@ -0,0 +1,66 @@
|
|
+/*
|
|
+ * Copyright (C) 2008-2009, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "permissions.h"
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <QtGui/QListWidget>
|
|
+
|
|
+PermissionsDock::PermissionsDock(QWidget *parent)
|
|
+ : AbstractInfoDock(parent)
|
|
+{
|
|
+ m_table = new QListWidget(this);
|
|
+ setWidget(m_table);
|
|
+ setWindowTitle(tr("Permissions"));
|
|
+ m_table->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
|
+}
|
|
+
|
|
+PermissionsDock::~PermissionsDock()
|
|
+{
|
|
+}
|
|
+
|
|
+void PermissionsDock::fillInfo()
|
|
+{
|
|
+#define ADD_ROW(title, function) \
|
|
+do { \
|
|
+ QListWidgetItem *item = new QListWidgetItem(); \
|
|
+ item->setFlags(item->flags() & ~Qt::ItemIsEnabled); \
|
|
+ item->setText(title); \
|
|
+ item->setCheckState(document()->function() ? Qt::Checked : Qt::Unchecked); \
|
|
+ m_table->addItem(item); \
|
|
+} while (0)
|
|
+ ADD_ROW("Print", okToPrint);
|
|
+ ADD_ROW("PrintHiRes", okToPrintHighRes);
|
|
+ ADD_ROW("Change", okToChange);
|
|
+ ADD_ROW("Copy", okToCopy);
|
|
+ ADD_ROW("Add Notes", okToAddNotes);
|
|
+ ADD_ROW("Fill Forms", okToFillForm);
|
|
+ ADD_ROW("Create Forms", okToCreateFormFields);
|
|
+ ADD_ROW("Extract for accessibility", okToExtractForAccessibility);
|
|
+ ADD_ROW("Assemble", okToAssemble);
|
|
+#undef ADD_ROW
|
|
+}
|
|
+
|
|
+void PermissionsDock::documentClosed()
|
|
+{
|
|
+ m_table->clear();
|
|
+ AbstractInfoDock::documentClosed();
|
|
+}
|
|
+
|
|
+#include "permissions.moc"
|
|
diff --git a/qt4/demos/permissions.h b/qt4/demos/permissions.h
|
|
new file mode 100644
|
|
index 00000000..13bcbbf0
|
|
--- /dev/null
|
|
+++ b/qt4/demos/permissions.h
|
|
@@ -0,0 +1,43 @@
|
|
+/*
|
|
+ * Copyright (C) 2008-2009, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef PERMISSIONS_H
|
|
+#define PERMISSIONS_H
|
|
+
|
|
+#include "abstractinfodock.h"
|
|
+
|
|
+class QListWidget;
|
|
+
|
|
+class PermissionsDock : public AbstractInfoDock
|
|
+{
|
|
+ Q_OBJECT
|
|
+
|
|
+public:
|
|
+ PermissionsDock(QWidget *parent = 0);
|
|
+ ~PermissionsDock();
|
|
+
|
|
+ /*virtual*/ void documentClosed();
|
|
+
|
|
+protected:
|
|
+ /*virtual*/ void fillInfo();
|
|
+
|
|
+private:
|
|
+ QListWidget *m_table;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/demos/thumbnails.cpp b/qt4/demos/thumbnails.cpp
|
|
new file mode 100644
|
|
index 00000000..07b19ca7
|
|
--- /dev/null
|
|
+++ b/qt4/demos/thumbnails.cpp
|
|
@@ -0,0 +1,84 @@
|
|
+/*
|
|
+ * Copyright (C) 2009, Shawn Rutledge <shawn.t.rutledge@gmail.com>
|
|
+ * Copyright (C) 2009, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "thumbnails.h"
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <QtGui/QListWidget>
|
|
+
|
|
+static const int PageRole = Qt::UserRole + 1;
|
|
+
|
|
+ThumbnailsDock::ThumbnailsDock(QWidget *parent)
|
|
+ : AbstractInfoDock(parent)
|
|
+{
|
|
+ m_list = new QListWidget(this);
|
|
+ setWidget(m_list);
|
|
+ setWindowTitle(tr("Thumbnails"));
|
|
+ m_list->setViewMode(QListView::ListMode);
|
|
+ m_list->setMovement(QListView::Static);
|
|
+ m_list->setVerticalScrollMode(QListView::ScrollPerPixel);
|
|
+ connect(m_list, SIGNAL(itemActivated(QListWidgetItem*)),
|
|
+ this, SLOT(slotItemActivated(QListWidgetItem*)));
|
|
+}
|
|
+
|
|
+ThumbnailsDock::~ThumbnailsDock()
|
|
+{
|
|
+}
|
|
+
|
|
+void ThumbnailsDock::fillInfo()
|
|
+{
|
|
+ const int num = document()->numPages();
|
|
+ QSize maxSize;
|
|
+ for (int i = 0; i < num; ++i) {
|
|
+ const Poppler::Page *page = document()->page(i);
|
|
+ const QImage image = page->thumbnail();
|
|
+ if (!image.isNull()) {
|
|
+ QListWidgetItem *item = new QListWidgetItem();
|
|
+ item->setText(QString::number(i + 1));
|
|
+ item->setData(Qt::DecorationRole, QPixmap::fromImage(image));
|
|
+ item->setData(PageRole, i);
|
|
+ m_list->addItem(item);
|
|
+ maxSize.setWidth(qMax(maxSize.width(), image.width()));
|
|
+ maxSize.setHeight(qMax(maxSize.height(), image.height()));
|
|
+ }
|
|
+ delete page;
|
|
+ }
|
|
+ if (num > 0) {
|
|
+ m_list->setGridSize(maxSize);
|
|
+ m_list->setIconSize(maxSize);
|
|
+ }
|
|
+}
|
|
+
|
|
+void ThumbnailsDock::documentClosed()
|
|
+{
|
|
+ m_list->clear();
|
|
+ AbstractInfoDock::documentClosed();
|
|
+}
|
|
+
|
|
+void ThumbnailsDock::slotItemActivated(QListWidgetItem *item)
|
|
+{
|
|
+ if (!item) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ setPage(item->data(PageRole).toInt());
|
|
+}
|
|
+
|
|
+#include "thumbnails.moc"
|
|
diff --git a/qt4/demos/thumbnails.h b/qt4/demos/thumbnails.h
|
|
new file mode 100644
|
|
index 00000000..076d5aee
|
|
--- /dev/null
|
|
+++ b/qt4/demos/thumbnails.h
|
|
@@ -0,0 +1,48 @@
|
|
+/*
|
|
+ * Copyright (C) 2009, Shawn Rutledge <shawn.t.rutledge@gmail.com>
|
|
+ * Copyright (C) 2009, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef THUMBNAILS_H
|
|
+#define THUMBNAILS_H
|
|
+
|
|
+#include "abstractinfodock.h"
|
|
+
|
|
+class QListWidget;
|
|
+class QListWidgetItem;
|
|
+
|
|
+class ThumbnailsDock : public AbstractInfoDock
|
|
+{
|
|
+ Q_OBJECT
|
|
+
|
|
+public:
|
|
+ ThumbnailsDock(QWidget *parent = 0);
|
|
+ ~ThumbnailsDock();
|
|
+
|
|
+ /*virtual*/ void documentClosed();
|
|
+
|
|
+protected:
|
|
+ /*virtual*/ void fillInfo();
|
|
+
|
|
+private Q_SLOTS:
|
|
+ void slotItemActivated(QListWidgetItem *item);
|
|
+
|
|
+private:
|
|
+ QListWidget *m_list;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/demos/toc.cpp b/qt4/demos/toc.cpp
|
|
new file mode 100644
|
|
index 00000000..bf3e5cbb
|
|
--- /dev/null
|
|
+++ b/qt4/demos/toc.cpp
|
|
@@ -0,0 +1,88 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "toc.h"
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <QtGui/QHeaderView>
|
|
+#include <QtGui/QTreeWidget>
|
|
+
|
|
+static void fillToc(const QDomNode &parent, QTreeWidget *tree, QTreeWidgetItem *parentItem)
|
|
+{
|
|
+ QTreeWidgetItem *newitem = 0;
|
|
+ for (QDomNode node = parent.firstChild(); !node.isNull(); node = node.nextSibling()) {
|
|
+ QDomElement e = node.toElement();
|
|
+
|
|
+ if (!parentItem) {
|
|
+ newitem = new QTreeWidgetItem(tree, newitem);
|
|
+ } else {
|
|
+ newitem = new QTreeWidgetItem(parentItem, newitem);
|
|
+ }
|
|
+ newitem->setText(0, e.tagName());
|
|
+
|
|
+ bool isOpen = false;
|
|
+ if (e.hasAttribute(QString::fromLatin1("Open"))) {
|
|
+ isOpen = QVariant(e.attribute(QString::fromLatin1("Open"))).toBool();
|
|
+ }
|
|
+ if (isOpen) {
|
|
+ tree->expandItem(newitem);
|
|
+ }
|
|
+
|
|
+ if (e.hasChildNodes()) {
|
|
+ fillToc(node, tree, newitem);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+TocDock::TocDock(QWidget *parent)
|
|
+ : AbstractInfoDock(parent)
|
|
+{
|
|
+ m_tree = new QTreeWidget(this);
|
|
+ setWidget(m_tree);
|
|
+ m_tree->setAlternatingRowColors(true);
|
|
+ m_tree->header()->hide();
|
|
+ setWindowTitle(tr("TOC"));
|
|
+ m_tree->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
|
+}
|
|
+
|
|
+TocDock::~TocDock()
|
|
+{
|
|
+}
|
|
+
|
|
+void TocDock::fillInfo()
|
|
+{
|
|
+ const QDomDocument *toc = document()->toc();
|
|
+ if (toc) {
|
|
+ fillToc(*toc, m_tree, 0);
|
|
+ } else {
|
|
+ QTreeWidgetItem *item = new QTreeWidgetItem();
|
|
+ item->setText(0, tr("No TOC"));
|
|
+ item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
|
|
+ m_tree->addTopLevelItem(item);
|
|
+ }
|
|
+}
|
|
+
|
|
+void TocDock::documentClosed()
|
|
+{
|
|
+ m_tree->clear();
|
|
+ AbstractInfoDock::documentClosed();
|
|
+}
|
|
+
|
|
+#include "toc.moc"
|
|
diff --git a/qt4/demos/toc.h b/qt4/demos/toc.h
|
|
new file mode 100644
|
|
index 00000000..bbc90827
|
|
--- /dev/null
|
|
+++ b/qt4/demos/toc.h
|
|
@@ -0,0 +1,43 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef TOC_H
|
|
+#define TOC_H
|
|
+
|
|
+#include "abstractinfodock.h"
|
|
+
|
|
+class QTreeWidget;
|
|
+
|
|
+class TocDock : public AbstractInfoDock
|
|
+{
|
|
+ Q_OBJECT
|
|
+
|
|
+public:
|
|
+ TocDock(QWidget *parent = 0);
|
|
+ ~TocDock();
|
|
+
|
|
+ /*virtual*/ void documentClosed();
|
|
+
|
|
+protected:
|
|
+ /*virtual*/ void fillInfo();
|
|
+
|
|
+private:
|
|
+ QTreeWidget *m_tree;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/demos/viewer.cpp b/qt4/demos/viewer.cpp
|
|
new file mode 100644
|
|
index 00000000..c34af23f
|
|
--- /dev/null
|
|
+++ b/qt4/demos/viewer.cpp
|
|
@@ -0,0 +1,319 @@
|
|
+/*
|
|
+ * Copyright (C) 2008-2009, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2008, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2009, Shawn Rutledge <shawn.t.rutledge@gmail.com>
|
|
+ * Copyright (C) 2013, Fabio D'Urso <fabiodurso@hotmail.it>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "viewer.h"
|
|
+
|
|
+#include "embeddedfiles.h"
|
|
+#include "fonts.h"
|
|
+#include "info.h"
|
|
+#include "metadata.h"
|
|
+#include "navigationtoolbar.h"
|
|
+#include "optcontent.h"
|
|
+#include "pageview.h"
|
|
+#include "permissions.h"
|
|
+#include "thumbnails.h"
|
|
+#include "toc.h"
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <QtCore/QDir>
|
|
+#include <QtGui/QAction>
|
|
+#include <QtGui/QApplication>
|
|
+#include <QtGui/QFileDialog>
|
|
+#include <QtGui/QInputDialog>
|
|
+#include <QtGui/QMenu>
|
|
+#include <QtGui/QMenuBar>
|
|
+#include <QtGui/QMessageBox>
|
|
+
|
|
+PdfViewer::PdfViewer()
|
|
+ : QMainWindow(), m_currentPage(0), m_doc(0)
|
|
+{
|
|
+ setWindowTitle(tr("Poppler-Qt4 Demo"));
|
|
+
|
|
+ // setup the menus
|
|
+ QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
|
|
+ m_fileOpenAct = fileMenu->addAction(tr("&Open"), this, SLOT(slotOpenFile()));
|
|
+ m_fileOpenAct->setShortcut(Qt::CTRL + Qt::Key_O);
|
|
+ fileMenu->addSeparator();
|
|
+ m_fileSaveCopyAct = fileMenu->addAction(tr("&Save a Copy..."), this, SLOT(slotSaveCopy()));
|
|
+ m_fileSaveCopyAct->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_S);
|
|
+ m_fileSaveCopyAct->setEnabled(false);
|
|
+ fileMenu->addSeparator();
|
|
+ QAction *act = fileMenu->addAction(tr("&Quit"), qApp, SLOT(closeAllWindows()));
|
|
+ act->setShortcut(Qt::CTRL + Qt::Key_Q);
|
|
+
|
|
+ QMenu *viewMenu = menuBar()->addMenu(tr("&View"));
|
|
+
|
|
+ QMenu *settingsMenu = menuBar()->addMenu(tr("&Settings"));
|
|
+ m_settingsTextAAAct = settingsMenu->addAction(tr("Text Antialias"));
|
|
+ m_settingsTextAAAct->setCheckable(true);
|
|
+ connect(m_settingsTextAAAct, SIGNAL(toggled(bool)), this, SLOT(slotToggleTextAA(bool)));
|
|
+ m_settingsGfxAAAct = settingsMenu->addAction(tr("Graphics Antialias"));
|
|
+ m_settingsGfxAAAct->setCheckable(true);
|
|
+ connect(m_settingsGfxAAAct, SIGNAL(toggled(bool)), this, SLOT(slotToggleGfxAA(bool)));
|
|
+ QMenu *settingsRenderMenu = settingsMenu->addMenu(tr("Render Backend"));
|
|
+ m_settingsRenderBackendGrp = new QActionGroup(settingsRenderMenu);
|
|
+ m_settingsRenderBackendGrp->setExclusive(true);
|
|
+ act = settingsRenderMenu->addAction(tr("Splash"));
|
|
+ act->setCheckable(true);
|
|
+ act->setChecked(true);
|
|
+ act->setData(qVariantFromValue(0));
|
|
+ m_settingsRenderBackendGrp->addAction(act);
|
|
+ act = settingsRenderMenu->addAction(tr("Arthur"));
|
|
+ act->setCheckable(true);
|
|
+ act->setData(qVariantFromValue(1));
|
|
+ m_settingsRenderBackendGrp->addAction(act);
|
|
+ connect(m_settingsRenderBackendGrp, SIGNAL(triggered(QAction*)),
|
|
+ this, SLOT(slotRenderBackend(QAction*)));
|
|
+
|
|
+ QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
|
|
+ act = helpMenu->addAction(tr("&About"), this, SLOT(slotAbout()));
|
|
+ act = helpMenu->addAction(tr("About &Qt"), this, SLOT(slotAboutQt()));
|
|
+
|
|
+ NavigationToolBar *navbar = new NavigationToolBar(this);
|
|
+ addToolBar(navbar);
|
|
+ m_observers.append(navbar);
|
|
+
|
|
+ PageView *view = new PageView(this);
|
|
+ setCentralWidget(view);
|
|
+ m_observers.append(view);
|
|
+
|
|
+ InfoDock *infoDock = new InfoDock(this);
|
|
+ addDockWidget(Qt::LeftDockWidgetArea, infoDock);
|
|
+ infoDock->hide();
|
|
+ viewMenu->addAction(infoDock->toggleViewAction());
|
|
+ m_observers.append(infoDock);
|
|
+
|
|
+ TocDock *tocDock = new TocDock(this);
|
|
+ addDockWidget(Qt::LeftDockWidgetArea, tocDock);
|
|
+ tocDock->hide();
|
|
+ viewMenu->addAction(tocDock->toggleViewAction());
|
|
+ m_observers.append(tocDock);
|
|
+
|
|
+ FontsDock *fontsDock = new FontsDock(this);
|
|
+ addDockWidget(Qt::LeftDockWidgetArea, fontsDock);
|
|
+ fontsDock->hide();
|
|
+ viewMenu->addAction(fontsDock->toggleViewAction());
|
|
+ m_observers.append(fontsDock);
|
|
+
|
|
+ PermissionsDock *permissionsDock = new PermissionsDock(this);
|
|
+ addDockWidget(Qt::LeftDockWidgetArea, permissionsDock);
|
|
+ permissionsDock->hide();
|
|
+ viewMenu->addAction(permissionsDock->toggleViewAction());
|
|
+ m_observers.append(permissionsDock);
|
|
+
|
|
+ ThumbnailsDock *thumbnailsDock = new ThumbnailsDock(this);
|
|
+ addDockWidget(Qt::LeftDockWidgetArea, thumbnailsDock);
|
|
+ thumbnailsDock->hide();
|
|
+ viewMenu->addAction(thumbnailsDock->toggleViewAction());
|
|
+ m_observers.append(thumbnailsDock);
|
|
+
|
|
+ EmbeddedFilesDock *embfilesDock = new EmbeddedFilesDock(this);
|
|
+ addDockWidget(Qt::BottomDockWidgetArea, embfilesDock);
|
|
+ embfilesDock->hide();
|
|
+ viewMenu->addAction(embfilesDock->toggleViewAction());
|
|
+ m_observers.append(embfilesDock);
|
|
+
|
|
+ MetadataDock *metadataDock = new MetadataDock(this);
|
|
+ addDockWidget(Qt::BottomDockWidgetArea, metadataDock);
|
|
+ metadataDock->hide();
|
|
+ viewMenu->addAction(metadataDock->toggleViewAction());
|
|
+ m_observers.append(metadataDock);
|
|
+
|
|
+ OptContentDock *optContentDock = new OptContentDock(this);
|
|
+ addDockWidget(Qt::LeftDockWidgetArea, optContentDock);
|
|
+ optContentDock->hide();
|
|
+ viewMenu->addAction(optContentDock->toggleViewAction());
|
|
+ m_observers.append(optContentDock);
|
|
+
|
|
+ Q_FOREACH(DocumentObserver *obs, m_observers) {
|
|
+ obs->m_viewer = this;
|
|
+ }
|
|
+
|
|
+ connect(navbar, SIGNAL(zoomChanged(qreal)), view, SLOT(slotZoomChanged(qreal)));
|
|
+ connect(navbar, SIGNAL(rotationChanged(int)), view, SLOT(slotRotationChanged(int)));
|
|
+
|
|
+ // activate AA by default
|
|
+ m_settingsTextAAAct->setChecked(true);
|
|
+ m_settingsGfxAAAct->setChecked(true);
|
|
+}
|
|
+
|
|
+PdfViewer::~PdfViewer()
|
|
+{
|
|
+ closeDocument();
|
|
+}
|
|
+
|
|
+QSize PdfViewer::sizeHint() const
|
|
+{
|
|
+ return QSize(500, 600);
|
|
+}
|
|
+
|
|
+void PdfViewer::loadDocument(const QString &file)
|
|
+{
|
|
+ Poppler::Document *newdoc = Poppler::Document::load(file);
|
|
+ if (!newdoc) {
|
|
+ QMessageBox msgbox(QMessageBox::Critical, tr("Open Error"), tr("Cannot open:\n") + file,
|
|
+ QMessageBox::Ok, this);
|
|
+ msgbox.exec();
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ while (newdoc->isLocked()) {
|
|
+ bool ok = true;
|
|
+ QString password = QInputDialog::getText(this, tr("Document Password"),
|
|
+ tr("Please insert the password of the document:"),
|
|
+ QLineEdit::Password, QString(), &ok);
|
|
+ if (!ok) {
|
|
+ delete newdoc;
|
|
+ return;
|
|
+ }
|
|
+ newdoc->unlock(password.toLatin1(), password.toLatin1());
|
|
+ }
|
|
+
|
|
+ closeDocument();
|
|
+
|
|
+ m_doc = newdoc;
|
|
+
|
|
+ m_doc->setRenderHint(Poppler::Document::TextAntialiasing, m_settingsTextAAAct->isChecked());
|
|
+ m_doc->setRenderHint(Poppler::Document::Antialiasing, m_settingsGfxAAAct->isChecked());
|
|
+ m_doc->setRenderBackend((Poppler::Document::RenderBackend)m_settingsRenderBackendGrp->checkedAction()->data().toInt());
|
|
+
|
|
+ Q_FOREACH(DocumentObserver *obs, m_observers) {
|
|
+ obs->documentLoaded();
|
|
+ obs->pageChanged(0);
|
|
+ }
|
|
+
|
|
+ m_fileSaveCopyAct->setEnabled(true);
|
|
+}
|
|
+
|
|
+void PdfViewer::closeDocument()
|
|
+{
|
|
+ if (!m_doc) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ Q_FOREACH(DocumentObserver *obs, m_observers) {
|
|
+ obs->documentClosed();
|
|
+ }
|
|
+
|
|
+ m_currentPage = 0;
|
|
+ delete m_doc;
|
|
+ m_doc = 0;
|
|
+
|
|
+ m_fileSaveCopyAct->setEnabled(false);
|
|
+}
|
|
+
|
|
+void PdfViewer::slotOpenFile()
|
|
+{
|
|
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Open PDF Document"), QDir::homePath(), tr("PDF Documents (*.pdf)"));
|
|
+ if (fileName.isEmpty()) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ loadDocument(fileName);
|
|
+}
|
|
+
|
|
+void PdfViewer::slotSaveCopy()
|
|
+{
|
|
+ if (!m_doc) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ QString fileName = QFileDialog::getSaveFileName(this, tr("Save Copy"), QDir::homePath(), tr("PDF Documents (*.pdf)"));
|
|
+ if (fileName.isEmpty()) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ Poppler::PDFConverter *converter = m_doc->pdfConverter();
|
|
+ converter->setOutputFileName(fileName);
|
|
+ converter->setPDFOptions(converter->pdfOptions() & ~Poppler::PDFConverter::WithChanges);
|
|
+ if (!converter->convert()) {
|
|
+ QMessageBox msgbox(QMessageBox::Critical, tr("Save Error"), tr("Cannot export to:\n%1").arg(fileName),
|
|
+ QMessageBox::Ok, this);
|
|
+ }
|
|
+ delete converter;
|
|
+}
|
|
+
|
|
+void PdfViewer::slotAbout()
|
|
+{
|
|
+ const QString text("This is a demo of the Poppler-Qt4 library.");
|
|
+ QMessageBox::about(this, QString::fromLatin1("About Poppler-Qt4 Demo"), text);
|
|
+}
|
|
+
|
|
+void PdfViewer::slotAboutQt()
|
|
+{
|
|
+ QMessageBox::aboutQt(this);
|
|
+}
|
|
+
|
|
+void PdfViewer::slotToggleTextAA(bool value)
|
|
+{
|
|
+ if (!m_doc) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ m_doc->setRenderHint(Poppler::Document::TextAntialiasing, value);
|
|
+
|
|
+ Q_FOREACH(DocumentObserver *obs, m_observers) {
|
|
+ obs->pageChanged(m_currentPage);
|
|
+ }
|
|
+}
|
|
+
|
|
+void PdfViewer::slotToggleGfxAA(bool value)
|
|
+{
|
|
+ if (!m_doc) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ m_doc->setRenderHint(Poppler::Document::Antialiasing, value);
|
|
+
|
|
+ Q_FOREACH(DocumentObserver *obs, m_observers) {
|
|
+ obs->pageChanged(m_currentPage);
|
|
+ }
|
|
+}
|
|
+
|
|
+void PdfViewer::slotRenderBackend(QAction *act)
|
|
+{
|
|
+ if (!m_doc || !act) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ m_doc->setRenderBackend((Poppler::Document::RenderBackend)act->data().toInt());
|
|
+
|
|
+ Q_FOREACH(DocumentObserver *obs, m_observers) {
|
|
+ obs->pageChanged(m_currentPage);
|
|
+ }
|
|
+}
|
|
+
|
|
+void PdfViewer::setPage(int page)
|
|
+{
|
|
+ Q_FOREACH(DocumentObserver *obs, m_observers) {
|
|
+ obs->pageChanged(page);
|
|
+ }
|
|
+
|
|
+ m_currentPage = page;
|
|
+}
|
|
+
|
|
+int PdfViewer::page() const
|
|
+{
|
|
+ return m_currentPage;
|
|
+}
|
|
+
|
|
+#include "viewer.moc"
|
|
diff --git a/qt4/demos/viewer.h b/qt4/demos/viewer.h
|
|
new file mode 100644
|
|
index 00000000..5e0eaaff
|
|
--- /dev/null
|
|
+++ b/qt4/demos/viewer.h
|
|
@@ -0,0 +1,73 @@
|
|
+/*
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef PDFVIEWER_H
|
|
+#define PDFVIEWER_H
|
|
+
|
|
+#include <QtGui/QMainWindow>
|
|
+
|
|
+class QAction;
|
|
+class QActionGroup;
|
|
+class QLabel;
|
|
+class DocumentObserver;
|
|
+namespace Poppler {
|
|
+class Document;
|
|
+}
|
|
+
|
|
+class PdfViewer : public QMainWindow
|
|
+{
|
|
+ Q_OBJECT
|
|
+
|
|
+ friend class DocumentObserver;
|
|
+
|
|
+public:
|
|
+ PdfViewer();
|
|
+ ~PdfViewer();
|
|
+
|
|
+ /*virtual*/ QSize sizeHint() const;
|
|
+
|
|
+ void loadDocument(const QString &file);
|
|
+ void closeDocument();
|
|
+
|
|
+private Q_SLOTS:
|
|
+ void slotOpenFile();
|
|
+ void slotSaveCopy();
|
|
+ void slotAbout();
|
|
+ void slotAboutQt();
|
|
+ void slotToggleTextAA(bool value);
|
|
+ void slotToggleGfxAA(bool value);
|
|
+ void slotRenderBackend(QAction *act);
|
|
+
|
|
+private:
|
|
+ void setPage(int page);
|
|
+ int page() const;
|
|
+
|
|
+ int m_currentPage;
|
|
+
|
|
+ QAction *m_fileOpenAct;
|
|
+ QAction *m_fileSaveCopyAct;
|
|
+ QAction *m_settingsTextAAAct;
|
|
+ QAction *m_settingsGfxAAAct;
|
|
+ QActionGroup *m_settingsRenderBackendGrp;
|
|
+
|
|
+ QList<DocumentObserver *> m_observers;
|
|
+
|
|
+ Poppler::Document *m_doc;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/.gitignore b/qt4/src/.gitignore
|
|
new file mode 100644
|
|
index 00000000..3d124ddd
|
|
--- /dev/null
|
|
+++ b/qt4/src/.gitignore
|
|
@@ -0,0 +1,9 @@
|
|
+.deps
|
|
+.libs
|
|
+*.la
|
|
+*.lo
|
|
+Makefile
|
|
+Makefile.in
|
|
+APIDOCS-html
|
|
+APIDOCS-latex
|
|
+*.moc
|
|
diff --git a/qt4/src/ArthurOutputDev.cc b/qt4/src/ArthurOutputDev.cc
|
|
new file mode 100644
|
|
index 00000000..f2fa6f17
|
|
--- /dev/null
|
|
+++ b/qt4/src/ArthurOutputDev.cc
|
|
@@ -0,0 +1,817 @@
|
|
+//========================================================================
|
|
+//
|
|
+// ArthurOutputDev.cc
|
|
+//
|
|
+// Copyright 2003 Glyph & Cog, LLC
|
|
+//
|
|
+//========================================================================
|
|
+
|
|
+//========================================================================
|
|
+//
|
|
+// Modified under the Poppler project - http://poppler.freedesktop.org
|
|
+//
|
|
+// All changes made under the Poppler project to this file are licensed
|
|
+// under GPL version 2 or later
|
|
+//
|
|
+// Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
|
|
+// Copyright (C) 2005-2009, 2011, 2012, 2014, 2015 Albert Astals Cid <aacid@kde.org>
|
|
+// Copyright (C) 2008, 2010 Pino Toscano <pino@kde.org>
|
|
+// Copyright (C) 2009, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
|
|
+// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
|
|
+// Copyright (C) 2010 Matthias Fauconneau <matthias.fauconneau@gmail.com>
|
|
+// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
|
|
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
|
|
+// Copyright (C) 2013 Dominik Haumann <dhaumann@kde.org>
|
|
+// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
|
|
+//
|
|
+// To see a description of the changes please see the Changelog file that
|
|
+// came with your tarball or type make ChangeLog if you are building from git
|
|
+//
|
|
+//========================================================================
|
|
+
|
|
+#include <config.h>
|
|
+
|
|
+#ifdef USE_GCC_PRAGMAS
|
|
+#pragma implementation
|
|
+#endif
|
|
+
|
|
+#include <string.h>
|
|
+#include <math.h>
|
|
+
|
|
+#include "goo/gfile.h"
|
|
+#include "GlobalParams.h"
|
|
+#include "Error.h"
|
|
+#include "Object.h"
|
|
+#include "GfxState.h"
|
|
+#include "GfxFont.h"
|
|
+#include "Link.h"
|
|
+#include "FontEncodingTables.h"
|
|
+#include <fofi/FoFiTrueType.h>
|
|
+#include "ArthurOutputDev.h"
|
|
+
|
|
+#include <QtCore/QtDebug>
|
|
+#include <QtGui/QPainterPath>
|
|
+//------------------------------------------------------------------------
|
|
+
|
|
+#ifdef HAVE_SPLASH
|
|
+#include "splash/SplashFontFileID.h"
|
|
+#include "splash/SplashFontFile.h"
|
|
+#include "splash/SplashFontEngine.h"
|
|
+#include "splash/SplashFont.h"
|
|
+#include "splash/SplashMath.h"
|
|
+#include "splash/SplashPath.h"
|
|
+#include "splash/SplashGlyphBitmap.h"
|
|
+//------------------------------------------------------------------------
|
|
+// SplashOutFontFileID
|
|
+//------------------------------------------------------------------------
|
|
+
|
|
+class SplashOutFontFileID: public SplashFontFileID {
|
|
+public:
|
|
+
|
|
+ SplashOutFontFileID(const Ref *rA) { r = *rA; }
|
|
+
|
|
+ ~SplashOutFontFileID() {}
|
|
+
|
|
+ bool matches(SplashFontFileID *id) {
|
|
+ return ((SplashOutFontFileID *)id)->r.num == r.num &&
|
|
+ ((SplashOutFontFileID *)id)->r.gen == r.gen;
|
|
+ }
|
|
+
|
|
+private:
|
|
+
|
|
+ Ref r;
|
|
+};
|
|
+
|
|
+#endif
|
|
+
|
|
+//------------------------------------------------------------------------
|
|
+// ArthurOutputDev
|
|
+//------------------------------------------------------------------------
|
|
+
|
|
+ArthurOutputDev::ArthurOutputDev(QPainter *painter):
|
|
+ m_painter(painter),
|
|
+ m_fontHinting(NoHinting)
|
|
+{
|
|
+ m_currentBrush = QBrush(Qt::SolidPattern);
|
|
+ m_fontEngine = 0;
|
|
+ m_font = 0;
|
|
+}
|
|
+
|
|
+ArthurOutputDev::~ArthurOutputDev()
|
|
+{
|
|
+#ifdef HAVE_SPLASH
|
|
+ delete m_fontEngine;
|
|
+#endif
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::startDoc(XRef *xrefA) {
|
|
+ xref = xrefA;
|
|
+#ifdef HAVE_SPLASH
|
|
+ delete m_fontEngine;
|
|
+
|
|
+ const bool isHintingEnabled = m_fontHinting != NoHinting;
|
|
+ const bool isSlightHinting = m_fontHinting == SlightHinting;
|
|
+
|
|
+ m_fontEngine = new SplashFontEngine(
|
|
+ true, // I just set this to true. We should finally remove the QT4.
|
|
+ isHintingEnabled,
|
|
+ isSlightHinting,
|
|
+ m_painter->testRenderHint(QPainter::TextAntialiasing));
|
|
+#endif
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::startPage(int pageNum, GfxState *state, XRef *xref)
|
|
+{
|
|
+ // fill page with white background.
|
|
+ int w = static_cast<int>(state->getPageWidth());
|
|
+ int h = static_cast<int>(state->getPageHeight());
|
|
+ QColor fillColour(Qt::white);
|
|
+ QBrush fill(fillColour);
|
|
+ m_painter->save();
|
|
+ m_painter->setPen(fillColour);
|
|
+ m_painter->setBrush(fill);
|
|
+ m_painter->drawRect(0, 0, w, h);
|
|
+ m_painter->restore();
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::endPage() {
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::saveState(GfxState *state)
|
|
+{
|
|
+ m_painter->save();
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::restoreState(GfxState *state)
|
|
+{
|
|
+ m_painter->restore();
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::updateAll(GfxState *state)
|
|
+{
|
|
+ OutputDev::updateAll(state);
|
|
+ m_needFontUpdate = true;
|
|
+}
|
|
+
|
|
+// This looks wrong - why aren't adjusting the matrix?
|
|
+void ArthurOutputDev::updateCTM(GfxState *state, double m11, double m12,
|
|
+ double m21, double m22,
|
|
+ double m31, double m32)
|
|
+{
|
|
+ updateLineDash(state);
|
|
+ updateLineJoin(state);
|
|
+ updateLineCap(state);
|
|
+ updateLineWidth(state);
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::updateLineDash(GfxState *state)
|
|
+{
|
|
+ double *dashPattern;
|
|
+ int dashLength;
|
|
+ double dashStart;
|
|
+ state->getLineDash(&dashPattern, &dashLength, &dashStart);
|
|
+ QVector<qreal> pattern(dashLength);
|
|
+ for (int i = 0; i < dashLength; ++i) {
|
|
+ pattern[i] = dashPattern[i];
|
|
+ }
|
|
+ m_currentPen.setDashPattern(pattern);
|
|
+ m_currentPen.setDashOffset(dashStart);
|
|
+ m_painter->setPen(m_currentPen);
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::updateFlatness(GfxState *state)
|
|
+{
|
|
+ // qDebug() << "updateFlatness";
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::updateLineJoin(GfxState *state)
|
|
+{
|
|
+ switch (state->getLineJoin()) {
|
|
+ case 0:
|
|
+ m_currentPen.setJoinStyle(Qt::MiterJoin);
|
|
+ break;
|
|
+ case 1:
|
|
+ m_currentPen.setJoinStyle(Qt::RoundJoin);
|
|
+ break;
|
|
+ case 2:
|
|
+ m_currentPen.setJoinStyle(Qt::BevelJoin);
|
|
+ break;
|
|
+ }
|
|
+ m_painter->setPen(m_currentPen);
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::updateLineCap(GfxState *state)
|
|
+{
|
|
+ switch (state->getLineCap()) {
|
|
+ case 0:
|
|
+ m_currentPen.setCapStyle(Qt::FlatCap);
|
|
+ break;
|
|
+ case 1:
|
|
+ m_currentPen.setCapStyle(Qt::RoundCap);
|
|
+ break;
|
|
+ case 2:
|
|
+ m_currentPen.setCapStyle(Qt::SquareCap);
|
|
+ break;
|
|
+ }
|
|
+ m_painter->setPen(m_currentPen);
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::updateMiterLimit(GfxState *state)
|
|
+{
|
|
+ m_currentPen.setMiterLimit(state->getMiterLimit());
|
|
+ m_painter->setPen(m_currentPen);
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::updateLineWidth(GfxState *state)
|
|
+{
|
|
+ m_currentPen.setWidthF(state->getLineWidth());
|
|
+ m_painter->setPen(m_currentPen);
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::updateFillColor(GfxState *state)
|
|
+{
|
|
+ GfxRGB rgb;
|
|
+ QColor brushColour = m_currentBrush.color();
|
|
+ state->getFillRGB(&rgb);
|
|
+ brushColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), brushColour.alphaF());
|
|
+ m_currentBrush.setColor(brushColour);
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::updateStrokeColor(GfxState *state)
|
|
+{
|
|
+ GfxRGB rgb;
|
|
+ QColor penColour = m_currentPen.color();
|
|
+ state->getStrokeRGB(&rgb);
|
|
+ penColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), penColour.alphaF());
|
|
+ m_currentPen.setColor(penColour);
|
|
+ m_painter->setPen(m_currentPen);
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::updateFillOpacity(GfxState *state)
|
|
+{
|
|
+ QColor brushColour= m_currentBrush.color();
|
|
+ brushColour.setAlphaF(state->getFillOpacity());
|
|
+ m_currentBrush.setColor(brushColour);
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::updateStrokeOpacity(GfxState *state)
|
|
+{
|
|
+ QColor penColour= m_currentPen.color();
|
|
+ penColour.setAlphaF(state->getStrokeOpacity());
|
|
+ m_currentPen.setColor(penColour);
|
|
+ m_painter->setPen(m_currentPen);
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::updateFont(GfxState *state)
|
|
+{
|
|
+#ifdef HAVE_SPLASH
|
|
+ GfxFont *gfxFont;
|
|
+ GfxFontLoc *fontLoc;
|
|
+ GfxFontType fontType;
|
|
+ SplashOutFontFileID *id;
|
|
+ SplashFontFile *fontFile;
|
|
+ SplashFontSrc *fontsrc = NULL;
|
|
+ FoFiTrueType *ff;
|
|
+ Object refObj, strObj;
|
|
+ GooString *fileName;
|
|
+ char *tmpBuf;
|
|
+ int tmpBufLen = 0;
|
|
+ int *codeToGID;
|
|
+ const double *textMat;
|
|
+ double m11, m12, m21, m22, fontSize;
|
|
+ SplashCoord mat[4];
|
|
+ int n;
|
|
+ int faceIndex = 0;
|
|
+ SplashCoord matrix[6];
|
|
+
|
|
+ m_needFontUpdate = false;
|
|
+ m_font = NULL;
|
|
+ fileName = NULL;
|
|
+ tmpBuf = NULL;
|
|
+ fontLoc = NULL;
|
|
+
|
|
+ if (!(gfxFont = state->getFont())) {
|
|
+ goto err1;
|
|
+ }
|
|
+ fontType = gfxFont->getType();
|
|
+ if (fontType == fontType3) {
|
|
+ goto err1;
|
|
+ }
|
|
+
|
|
+ // check the font file cache
|
|
+ id = new SplashOutFontFileID(gfxFont->getID());
|
|
+ if ((fontFile = m_fontEngine->getFontFile(id))) {
|
|
+ delete id;
|
|
+
|
|
+ } else {
|
|
+
|
|
+ if (!(fontLoc = gfxFont->locateFont(xref, NULL))) {
|
|
+ error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
|
|
+ gfxFont->getName() ? gfxFont->getName()->c_str()
|
|
+ : "(unnamed)");
|
|
+ goto err2;
|
|
+ }
|
|
+
|
|
+ // embedded font
|
|
+ if (fontLoc->locType == gfxFontLocEmbedded) {
|
|
+ // if there is an embedded font, read it to memory
|
|
+ tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen);
|
|
+ if (! tmpBuf)
|
|
+ goto err2;
|
|
+
|
|
+ // external font
|
|
+ } else { // gfxFontLocExternal
|
|
+ fileName = fontLoc->path;
|
|
+ fontType = fontLoc->fontType;
|
|
+ }
|
|
+
|
|
+ fontsrc = new SplashFontSrc;
|
|
+ if (fileName)
|
|
+ fontsrc->setFile(fileName, false);
|
|
+ else
|
|
+ fontsrc->setBuf(tmpBuf, tmpBufLen, true);
|
|
+
|
|
+ // load the font file
|
|
+ switch (fontType) {
|
|
+ case fontType1:
|
|
+ if (!(fontFile = m_fontEngine->loadType1Font(
|
|
+ id,
|
|
+ fontsrc,
|
|
+ (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
|
|
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
|
|
+ gfxFont->getName() ? gfxFont->getName()->c_str()
|
|
+ : "(unnamed)");
|
|
+ goto err2;
|
|
+ }
|
|
+ break;
|
|
+ case fontType1C:
|
|
+ if (!(fontFile = m_fontEngine->loadType1CFont(
|
|
+ id,
|
|
+ fontsrc,
|
|
+ (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
|
|
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
|
|
+ gfxFont->getName() ? gfxFont->getName()->c_str()
|
|
+ : "(unnamed)");
|
|
+ goto err2;
|
|
+ }
|
|
+ break;
|
|
+ case fontType1COT:
|
|
+ if (!(fontFile = m_fontEngine->loadOpenTypeT1CFont(
|
|
+ id,
|
|
+ fontsrc,
|
|
+ (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
|
|
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
|
|
+ gfxFont->getName() ? gfxFont->getName()->c_str()
|
|
+ : "(unnamed)");
|
|
+ goto err2;
|
|
+ }
|
|
+ break;
|
|
+ case fontTrueType:
|
|
+ case fontTrueTypeOT:
|
|
+ if (fileName)
|
|
+ ff = FoFiTrueType::load(fileName->c_str());
|
|
+ else
|
|
+ ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
|
|
+ if (ff) {
|
|
+ codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
|
|
+ n = 256;
|
|
+ delete ff;
|
|
+ } else {
|
|
+ codeToGID = NULL;
|
|
+ n = 0;
|
|
+ }
|
|
+ if (!(fontFile = m_fontEngine->loadTrueTypeFont(
|
|
+ id,
|
|
+ fontsrc,
|
|
+ codeToGID, n))) {
|
|
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
|
|
+ gfxFont->getName() ? gfxFont->getName()->c_str()
|
|
+ : "(unnamed)");
|
|
+ goto err2;
|
|
+ }
|
|
+ break;
|
|
+ case fontCIDType0:
|
|
+ case fontCIDType0C:
|
|
+ if (!(fontFile = m_fontEngine->loadCIDFont(
|
|
+ id,
|
|
+ fontsrc))) {
|
|
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
|
|
+ gfxFont->getName() ? gfxFont->getName()->c_str()
|
|
+ : "(unnamed)");
|
|
+ goto err2;
|
|
+ }
|
|
+ break;
|
|
+ case fontCIDType0COT:
|
|
+ if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
|
|
+ n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
|
|
+ codeToGID = (int *)gmallocn(n, sizeof(int));
|
|
+ memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
|
|
+ n * sizeof(int));
|
|
+ } else {
|
|
+ codeToGID = NULL;
|
|
+ n = 0;
|
|
+ }
|
|
+ if (!(fontFile = m_fontEngine->loadOpenTypeCFFFont(
|
|
+ id,
|
|
+ fontsrc,
|
|
+ codeToGID, n))) {
|
|
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
|
|
+ gfxFont->getName() ? gfxFont->getName()->c_str()
|
|
+ : "(unnamed)");
|
|
+ goto err2;
|
|
+ }
|
|
+ break;
|
|
+ case fontCIDType2:
|
|
+ case fontCIDType2OT:
|
|
+ codeToGID = NULL;
|
|
+ n = 0;
|
|
+ if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
|
|
+ n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
|
|
+ if (n) {
|
|
+ codeToGID = (int *)gmallocn(n, sizeof(int));
|
|
+ memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
|
|
+ n * sizeof(int));
|
|
+ }
|
|
+ } else {
|
|
+ if (fileName)
|
|
+ ff = FoFiTrueType::load(fileName->c_str());
|
|
+ else
|
|
+ ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
|
|
+ if (! ff)
|
|
+ goto err2;
|
|
+ codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n);
|
|
+ delete ff;
|
|
+ }
|
|
+ if (!(fontFile = m_fontEngine->loadTrueTypeFont(
|
|
+ id,
|
|
+ fontsrc,
|
|
+ codeToGID, n, faceIndex))) {
|
|
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
|
|
+ gfxFont->getName() ? gfxFont->getName()->c_str()
|
|
+ : "(unnamed)");
|
|
+ goto err2;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ // this shouldn't happen
|
|
+ goto err2;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // get the font matrix
|
|
+ textMat = state->getTextMat();
|
|
+ fontSize = state->getFontSize();
|
|
+ m11 = textMat[0] * fontSize * state->getHorizScaling();
|
|
+ m12 = textMat[1] * fontSize * state->getHorizScaling();
|
|
+ m21 = textMat[2] * fontSize;
|
|
+ m22 = textMat[3] * fontSize;
|
|
+
|
|
+ {
|
|
+ QMatrix painterMatrix = m_painter->worldMatrix();
|
|
+ matrix[0] = painterMatrix.m11();
|
|
+ matrix[1] = painterMatrix.m12();
|
|
+ matrix[2] = painterMatrix.m21();
|
|
+ matrix[3] = painterMatrix.m22();
|
|
+ matrix[4] = painterMatrix.dx();
|
|
+ matrix[5] = painterMatrix.dy();
|
|
+ }
|
|
+
|
|
+ // create the scaled font
|
|
+ mat[0] = m11; mat[1] = -m12;
|
|
+ mat[2] = m21; mat[3] = -m22;
|
|
+ m_font = m_fontEngine->getFont(fontFile, mat, matrix);
|
|
+
|
|
+ delete fontLoc;
|
|
+ if (fontsrc && !fontsrc->isFile)
|
|
+ fontsrc->unref();
|
|
+ return;
|
|
+
|
|
+ err2:
|
|
+ delete id;
|
|
+ delete fontLoc;
|
|
+ err1:
|
|
+ if (fontsrc && !fontsrc->isFile)
|
|
+ fontsrc->unref();
|
|
+ return;
|
|
+#endif
|
|
+}
|
|
+
|
|
+static QPainterPath convertPath(GfxState *state, const GfxPath *path, Qt::FillRule fillRule)
|
|
+{
|
|
+ const GfxSubpath *subpath;
|
|
+ double x1, y1, x2, y2, x3, y3;
|
|
+ int i, j;
|
|
+
|
|
+ QPainterPath qPath;
|
|
+ qPath.setFillRule(fillRule);
|
|
+ for (i = 0; i < path->getNumSubpaths(); ++i) {
|
|
+ subpath = path->getSubpath(i);
|
|
+ if (subpath->getNumPoints() > 0) {
|
|
+ state->transform(subpath->getX(0), subpath->getY(0), &x1, &y1);
|
|
+ qPath.moveTo(x1, y1);
|
|
+ j = 1;
|
|
+ while (j < subpath->getNumPoints()) {
|
|
+ if (subpath->getCurve(j)) {
|
|
+ state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
|
|
+ state->transform(subpath->getX(j+1), subpath->getY(j+1), &x2, &y2);
|
|
+ state->transform(subpath->getX(j+2), subpath->getY(j+2), &x3, &y3);
|
|
+ qPath.cubicTo( x1, y1, x2, y2, x3, y3);
|
|
+ j += 3;
|
|
+ } else {
|
|
+ state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
|
|
+ qPath.lineTo(x1, y1);
|
|
+ ++j;
|
|
+ }
|
|
+ }
|
|
+ if (subpath->isClosed()) {
|
|
+ qPath.closeSubpath();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return qPath;
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::stroke(GfxState *state)
|
|
+{
|
|
+ m_painter->strokePath( convertPath( state, state->getPath(), Qt::OddEvenFill ), m_currentPen );
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::fill(GfxState *state)
|
|
+{
|
|
+ m_painter->fillPath( convertPath( state, state->getPath(), Qt::WindingFill ), m_currentBrush );
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::eoFill(GfxState *state)
|
|
+{
|
|
+ m_painter->fillPath( convertPath( state, state->getPath(), Qt::OddEvenFill ), m_currentBrush );
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::clip(GfxState *state)
|
|
+{
|
|
+ m_painter->setClipPath(convertPath( state, state->getPath(), Qt::WindingFill ) );
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::eoClip(GfxState *state)
|
|
+{
|
|
+ m_painter->setClipPath(convertPath( state, state->getPath(), Qt::OddEvenFill ) );
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::drawChar(GfxState *state, double x, double y,
|
|
+ double dx, double dy,
|
|
+ double originX, double originY,
|
|
+ CharCode code, int nBytes, Unicode *u, int uLen) {
|
|
+#ifdef HAVE_SPLASH
|
|
+ double x1, y1;
|
|
+ double x2, y2;
|
|
+ double px, py;
|
|
+// SplashPath *path;
|
|
+ int render;
|
|
+ unsigned char f;
|
|
+
|
|
+ if (m_needFontUpdate) {
|
|
+ updateFont(state);
|
|
+ }
|
|
+ if (!m_font) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // check for invisible text -- this is used by Acrobat Capture
|
|
+ render = state->getRender();
|
|
+ if (render == 3) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ x -= originX;
|
|
+ y -= originY;
|
|
+
|
|
+ // fill
|
|
+ if (!(render & 1)) {
|
|
+ SplashPath * fontPath;
|
|
+ fontPath = m_font->getGlyphPath(code);
|
|
+ if (fontPath) {
|
|
+ QPainterPath qPath;
|
|
+ qPath.setFillRule(Qt::WindingFill);
|
|
+ for (int i = 0; i < fontPath->getLength(); ++i) {
|
|
+ // SplashPath.flags: bitwise or allowed
|
|
+ fontPath->getPoint(i, &px, &py, &f);
|
|
+ if (f & splashPathLast || f & splashPathClosed) {
|
|
+ qPath.closeSubpath();
|
|
+ }
|
|
+ if (f & splashPathFirst) {
|
|
+ state->transform(px+x, -py+y, &x1, &y1);
|
|
+ qPath.moveTo(x1,y1);
|
|
+ }
|
|
+ if (f & splashPathCurve) {
|
|
+ state->transform(px+x, -py+y, &x1, &y1);
|
|
+ fontPath->getPoint(i+1, &px, &py, &f);
|
|
+ state->transform(px+x, -py+y, &x2, &y2);
|
|
+ qPath.quadTo(x1,y1,x2,y2);
|
|
+ ++i;
|
|
+ }
|
|
+ // FIXME fix this
|
|
+ // else if (fontPath->flags[i] & splashPathArcCW) {
|
|
+ // qDebug() << "Need to implement arc";
|
|
+ // }
|
|
+ else {
|
|
+ fontPath->getPoint(i, &px, &py, &f);
|
|
+ state->transform(px+x, -py+y, &x1, &y1);
|
|
+ qPath.lineTo(x1,y1);
|
|
+ }
|
|
+ }
|
|
+ GfxRGB rgb;
|
|
+ QColor brushColour = m_currentBrush.color();
|
|
+ state->getFillRGB(&rgb);
|
|
+ brushColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), state->getFillOpacity());
|
|
+ m_painter->setBrush(brushColour);
|
|
+ m_painter->setPen(Qt::NoPen);
|
|
+ m_painter->drawPath(qPath);
|
|
+ delete fontPath;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // stroke
|
|
+ if ((render & 3) == 1 || (render & 3) == 2) {
|
|
+ qDebug() << "no stroke";
|
|
+ /*
|
|
+ if ((path = m_font->getGlyphPath(code))) {
|
|
+ path->offset((SplashCoord)x1, (SplashCoord)y1);
|
|
+ splash->stroke(path);
|
|
+ delete path;
|
|
+ }
|
|
+ */
|
|
+ }
|
|
+
|
|
+ // clip
|
|
+ if (render & 4) {
|
|
+ qDebug() << "no clip";
|
|
+ /*
|
|
+ path = m_font->getGlyphPath(code);
|
|
+ path->offset((SplashCoord)x1, (SplashCoord)y1);
|
|
+ if (textClipPath) {
|
|
+ textClipPath->append(path);
|
|
+ delete path;
|
|
+ } else {
|
|
+ textClipPath = path;
|
|
+ }
|
|
+ */
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+
|
|
+bool ArthurOutputDev::beginType3Char(GfxState *state, double x, double y,
|
|
+ double dx, double dy,
|
|
+ CharCode code, Unicode *u, int uLen)
|
|
+{
|
|
+ return false;
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::endType3Char(GfxState *state)
|
|
+{
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::type3D0(GfxState *state, double wx, double wy)
|
|
+{
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::type3D1(GfxState *state, double wx, double wy,
|
|
+ double llx, double lly, double urx, double ury)
|
|
+{
|
|
+}
|
|
+
|
|
+void ArthurOutputDev::endTextObject(GfxState *state)
|
|
+{
|
|
+}
|
|
+
|
|
+
|
|
+void ArthurOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
|
|
+ int width, int height, bool invert,
|
|
+ bool interpolate, bool inlineImg)
|
|
+{
|
|
+ qDebug() << "drawImageMask";
|
|
+#if 0
|
|
+ unsigned char *buffer;
|
|
+ unsigned char *dest;
|
|
+ cairo_surface_t *image;
|
|
+ cairo_pattern_t *pattern;
|
|
+ int x, y;
|
|
+ ImageStream *imgStr;
|
|
+ Guchar *pix;
|
|
+ double *ctm;
|
|
+ cairo_matrix_t matrix;
|
|
+ int invert_bit;
|
|
+ int row_stride;
|
|
+
|
|
+ row_stride = (width + 3) & ~3;
|
|
+ buffer = (unsigned char *) malloc (height * row_stride);
|
|
+ if (buffer == NULL) {
|
|
+ error(-1, "Unable to allocate memory for image.");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* TODO: Do we want to cache these? */
|
|
+ imgStr = new ImageStream(str, width, 1, 1);
|
|
+ imgStr->reset();
|
|
+
|
|
+ invert_bit = invert ? 1 : 0;
|
|
+
|
|
+ for (y = 0; y < height; y++) {
|
|
+ pix = imgStr->getLine();
|
|
+ dest = buffer + y * row_stride;
|
|
+ for (x = 0; x < width; x++) {
|
|
+
|
|
+ if (pix[x] ^ invert_bit)
|
|
+ *dest++ = 0;
|
|
+ else
|
|
+ *dest++ = 255;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_A8,
|
|
+ width, height, row_stride);
|
|
+ if (image == NULL)
|
|
+ return;
|
|
+ pattern = cairo_pattern_create_for_surface (image);
|
|
+ if (pattern == NULL)
|
|
+ return;
|
|
+
|
|
+ ctm = state->getCTM();
|
|
+ LOG (printf ("drawImageMask %dx%d, matrix: %f, %f, %f, %f, %f, %f\n",
|
|
+ width, height, ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]));
|
|
+ matrix.xx = ctm[0] / width;
|
|
+ matrix.xy = -ctm[2] / height;
|
|
+ matrix.yx = ctm[1] / width;
|
|
+ matrix.yy = -ctm[3] / height;
|
|
+ matrix.x0 = ctm[2] + ctm[4];
|
|
+ matrix.y0 = ctm[3] + ctm[5];
|
|
+ cairo_matrix_invert (&matrix);
|
|
+ cairo_pattern_set_matrix (pattern, &matrix);
|
|
+
|
|
+ cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST);
|
|
+ /* FIXME: Doesn't the image mask support any colorspace? */
|
|
+ cairo_set_source_rgb (cairo, fill_color.r, fill_color.g, fill_color.b);
|
|
+ cairo_mask (cairo, pattern);
|
|
+
|
|
+ cairo_pattern_destroy (pattern);
|
|
+ cairo_surface_destroy (image);
|
|
+ free (buffer);
|
|
+ imgStr->close ();
|
|
+ delete imgStr;
|
|
+#endif
|
|
+}
|
|
+
|
|
+//TODO: lots more work here.
|
|
+void ArthurOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
|
|
+ int width, int height,
|
|
+ GfxImageColorMap *colorMap,
|
|
+ bool interpolate, int *maskColors, bool inlineImg)
|
|
+{
|
|
+ unsigned int *data;
|
|
+ unsigned int *line;
|
|
+ int x, y;
|
|
+ ImageStream *imgStr;
|
|
+ unsigned char *pix;
|
|
+ int i;
|
|
+ const double *ctm;
|
|
+ QMatrix matrix;
|
|
+ QImage image;
|
|
+ int stride;
|
|
+
|
|
+ /* TODO: Do we want to cache these? */
|
|
+ imgStr = new ImageStream(str, width,
|
|
+ colorMap->getNumPixelComps(),
|
|
+ colorMap->getBits());
|
|
+ imgStr->reset();
|
|
+
|
|
+ image = QImage(width, height, QImage::Format_ARGB32);
|
|
+ data = (unsigned int *)image.bits();
|
|
+ stride = image.bytesPerLine()/4;
|
|
+ for (y = 0; y < height; y++) {
|
|
+ pix = imgStr->getLine();
|
|
+ line = data+y*stride;
|
|
+ colorMap->getRGBLine(pix, line, width);
|
|
+
|
|
+ if (maskColors) {
|
|
+ for (x = 0; x < width; x++) {
|
|
+ for (i = 0; i < colorMap->getNumPixelComps(); ++i) {
|
|
+ if (pix[i] < maskColors[2*i] * 255||
|
|
+ pix[i] > maskColors[2*i+1] * 255) {
|
|
+ *line = *line | 0xff000000;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ pix += colorMap->getNumPixelComps();
|
|
+ line++;
|
|
+ }
|
|
+ } else {
|
|
+ for (x = 0; x < width; x++) { *line = *line | 0xff000000; line++; }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ctm = state->getCTM();
|
|
+ matrix.setMatrix(ctm[0] / width, ctm[1] / width, -ctm[2] / height, -ctm[3] / height, ctm[2] + ctm[4], ctm[3] + ctm[5]);
|
|
+
|
|
+ m_painter->setMatrix(matrix, true);
|
|
+ m_painter->drawImage( QPoint(0,0), image );
|
|
+ delete imgStr;
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/ArthurOutputDev.h b/qt4/src/ArthurOutputDev.h
|
|
new file mode 100644
|
|
index 00000000..9d5e8679
|
|
--- /dev/null
|
|
+++ b/qt4/src/ArthurOutputDev.h
|
|
@@ -0,0 +1,169 @@
|
|
+//========================================================================
|
|
+//
|
|
+// ArthurOutputDev.h
|
|
+//
|
|
+// Copyright 2003 Glyph & Cog, LLC
|
|
+//
|
|
+//========================================================================
|
|
+
|
|
+//========================================================================
|
|
+//
|
|
+// Modified under the Poppler project - http://poppler.freedesktop.org
|
|
+//
|
|
+// All changes made under the Poppler project to this file are licensed
|
|
+// under GPL version 2 or later
|
|
+//
|
|
+// Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
|
|
+// Copyright (C) 2005 Albert Astals Cid <aacid@kde.org>
|
|
+// Copyright (C) 2009, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
|
|
+// Copyright (C) 2010 Pino Toscano <pino@kde.org>
|
|
+// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
|
|
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
|
|
+//
|
|
+// To see a description of the changes please see the Changelog file that
|
|
+// came with your tarball or type make ChangeLog if you are building from git
|
|
+//
|
|
+//========================================================================
|
|
+
|
|
+#ifndef ARTHUROUTPUTDEV_H
|
|
+#define ARTHUROUTPUTDEV_H
|
|
+
|
|
+#ifdef USE_GCC_PRAGMAS
|
|
+#pragma interface
|
|
+#endif
|
|
+
|
|
+#include "OutputDev.h"
|
|
+#include "GfxState.h"
|
|
+
|
|
+#include <QtGui/QPainter>
|
|
+
|
|
+class GfxState;
|
|
+class GfxPath;
|
|
+class Gfx8BitFont;
|
|
+struct GfxRGB;
|
|
+
|
|
+class SplashFont;
|
|
+class SplashFontEngine;
|
|
+struct SplashGlyphBitmap;
|
|
+
|
|
+//------------------------------------------------------------------------
|
|
+// ArthurOutputDev - Qt 4 QPainter renderer
|
|
+//------------------------------------------------------------------------
|
|
+
|
|
+class ArthurOutputDev: public OutputDev {
|
|
+public:
|
|
+ /**
|
|
+ * Describes how fonts are distorted (aka hinted) to fit the pixel grid.
|
|
+ * More hinting means sharper edges and less adherence to the true letter shapes.
|
|
+ */
|
|
+ enum FontHinting {
|
|
+ NoHinting = 0, ///< Font shapes are left unchanged
|
|
+ SlightHinting, ///< Font shapes are distorted vertically only
|
|
+ FullHinting ///< Font shapes are distorted horizontally and vertically
|
|
+ };
|
|
+
|
|
+ // Constructor.
|
|
+ ArthurOutputDev(QPainter *painter );
|
|
+
|
|
+ // Destructor.
|
|
+ virtual ~ArthurOutputDev();
|
|
+
|
|
+ void setFontHinting(FontHinting hinting) { m_fontHinting = hinting; }
|
|
+
|
|
+ //----- get info about output device
|
|
+
|
|
+ // Does this device use upside-down coordinates?
|
|
+ // (Upside-down means (0,0) is the top left corner of the page.)
|
|
+ virtual bool upsideDown() { return true; }
|
|
+
|
|
+ // Does this device use drawChar() or drawString()?
|
|
+ virtual bool useDrawChar() { return true; }
|
|
+
|
|
+ // Does this device use beginType3Char/endType3Char? Otherwise,
|
|
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
|
|
+ virtual bool interpretType3Chars() { return true; }
|
|
+
|
|
+ //----- initialization and control
|
|
+
|
|
+ // Start a page.
|
|
+ virtual void startPage(int pageNum, GfxState *state, XRef *xref);
|
|
+
|
|
+ // End a page.
|
|
+ virtual void endPage();
|
|
+
|
|
+ //----- save/restore graphics state
|
|
+ virtual void saveState(GfxState *state);
|
|
+ virtual void restoreState(GfxState *state);
|
|
+
|
|
+ //----- update graphics state
|
|
+ virtual void updateAll(GfxState *state);
|
|
+ virtual void updateCTM(GfxState *state, double m11, double m12,
|
|
+ double m21, double m22, double m31, double m32);
|
|
+ virtual void updateLineDash(GfxState *state);
|
|
+ virtual void updateFlatness(GfxState *state);
|
|
+ virtual void updateLineJoin(GfxState *state);
|
|
+ virtual void updateLineCap(GfxState *state);
|
|
+ virtual void updateMiterLimit(GfxState *state);
|
|
+ virtual void updateLineWidth(GfxState *state);
|
|
+ virtual void updateFillColor(GfxState *state);
|
|
+ virtual void updateStrokeColor(GfxState *state);
|
|
+ virtual void updateFillOpacity(GfxState *state);
|
|
+ virtual void updateStrokeOpacity(GfxState *state);
|
|
+
|
|
+ //----- update text state
|
|
+ virtual void updateFont(GfxState *state);
|
|
+
|
|
+ //----- path painting
|
|
+ virtual void stroke(GfxState *state);
|
|
+ virtual void fill(GfxState *state);
|
|
+ virtual void eoFill(GfxState *state);
|
|
+
|
|
+ //----- path clipping
|
|
+ virtual void clip(GfxState *state);
|
|
+ virtual void eoClip(GfxState *state);
|
|
+
|
|
+ //----- text drawing
|
|
+ // virtual void drawString(GfxState *state, GooString *s);
|
|
+ virtual void drawChar(GfxState *state, double x, double y,
|
|
+ double dx, double dy,
|
|
+ double originX, double originY,
|
|
+ CharCode code, int nBytes, Unicode *u, int uLen);
|
|
+ virtual bool beginType3Char(GfxState *state, double x, double y,
|
|
+ double dx, double dy,
|
|
+ CharCode code, Unicode *u, int uLen);
|
|
+ virtual void endType3Char(GfxState *state);
|
|
+ virtual void endTextObject(GfxState *state);
|
|
+
|
|
+ //----- image drawing
|
|
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
|
|
+ int width, int height, bool invert,
|
|
+ bool interpolate, bool inlineImg);
|
|
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
|
|
+ int width, int height, GfxImageColorMap *colorMap,
|
|
+ bool interpolate, int *maskColors, bool inlineImg);
|
|
+
|
|
+ //----- Type 3 font operators
|
|
+ virtual void type3D0(GfxState *state, double wx, double wy);
|
|
+ virtual void type3D1(GfxState *state, double wx, double wy,
|
|
+ double llx, double lly, double urx, double ury);
|
|
+
|
|
+ //----- special access
|
|
+
|
|
+ // Called to indicate that a new PDF document has been loaded.
|
|
+ void startDoc(XRef *xrefA);
|
|
+
|
|
+ bool isReverseVideo() { return false; }
|
|
+
|
|
+private:
|
|
+ QPainter *m_painter;
|
|
+ FontHinting m_fontHinting;
|
|
+ QFont m_currentFont;
|
|
+ QPen m_currentPen;
|
|
+ QBrush m_currentBrush;
|
|
+ bool m_needFontUpdate; // set when the font needs to be updated
|
|
+ SplashFontEngine *m_fontEngine;
|
|
+ SplashFont *m_font; // current font
|
|
+ XRef *xref; // xref table for current document
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/CMakeLists.txt b/qt4/src/CMakeLists.txt
|
|
new file mode 100644
|
|
index 00000000..f6547726
|
|
--- /dev/null
|
|
+++ b/qt4/src/CMakeLists.txt
|
|
@@ -0,0 +1,54 @@
|
|
+add_definitions(${QT4_DEFINITIONS})
|
|
+
|
|
+include_directories(
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}
|
|
+ ${QT4_INCLUDE_DIR}
|
|
+ ${CMAKE_CURRENT_BINARY_DIR}
|
|
+)
|
|
+
|
|
+set(poppler_qt4_SRCS
|
|
+ poppler-annotation.cc
|
|
+ poppler-document.cc
|
|
+ poppler-embeddedfile.cc
|
|
+ poppler-fontinfo.cc
|
|
+ poppler-form.cc
|
|
+ poppler-link.cc
|
|
+ poppler-link-extractor.cc
|
|
+ poppler-movie.cc
|
|
+ poppler-optcontent.cc
|
|
+ poppler-page.cc
|
|
+ poppler-base-converter.cc
|
|
+ poppler-pdf-converter.cc
|
|
+ poppler-private.cc
|
|
+ poppler-ps-converter.cc
|
|
+ poppler-qiodeviceoutstream.cc
|
|
+ poppler-sound.cc
|
|
+ poppler-textbox.cc
|
|
+ poppler-page-transition.cc
|
|
+ poppler-media.cc
|
|
+ ArthurOutputDev.cc
|
|
+)
|
|
+qt4_automoc(${poppler_qt4_SRCS})
|
|
+add_library(poppler-qt4 SHARED ${poppler_qt4_SRCS})
|
|
+set_target_properties(poppler-qt4 PROPERTIES VERSION 4.11.0 SOVERSION 4)
|
|
+if(MINGW)
|
|
+ get_target_property(POPPLER_QT4_SOVERSION poppler-qt4 SOVERSION)
|
|
+ set_target_properties(poppler-qt4 PROPERTIES SUFFIX "-${POPPLER_QT4_SOVERSION}${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
|
+endif()
|
|
+target_link_libraries(poppler-qt4 poppler ${QT4_QTCORE_LIBRARY} ${QT4_QTGUI_LIBRARY} ${QT4_QTXML_LIBRARY})
|
|
+if(MSVC)
|
|
+target_link_libraries(poppler-qt4 poppler ${poppler_LIBS})
|
|
+endif()
|
|
+install(TARGETS poppler-qt4 RUNTIME DESTINATION bin LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
|
+
|
|
+install(FILES
|
|
+ poppler-qt4.h
|
|
+ poppler-link.h
|
|
+ poppler-annotation.h
|
|
+ poppler-form.h
|
|
+ poppler-optcontent.h
|
|
+ poppler-export.h
|
|
+ poppler-page-transition.h
|
|
+ poppler-media.h
|
|
+ DESTINATION include/poppler/qt4)
|
|
+
|
|
diff --git a/qt4/src/Doxyfile b/qt4/src/Doxyfile
|
|
new file mode 100644
|
|
index 00000000..e68690ac
|
|
--- /dev/null
|
|
+++ b/qt4/src/Doxyfile
|
|
@@ -0,0 +1,1637 @@
|
|
+# Doxyfile 1.7.1
|
|
+
|
|
+# This file describes the settings to be used by the documentation system
|
|
+# doxygen (www.doxygen.org) for a project
|
|
+#
|
|
+# All text after a hash (#) is considered a comment and will be ignored
|
|
+# The format is:
|
|
+# TAG = value [value, ...]
|
|
+# For lists items can also be appended using:
|
|
+# TAG += value [value, ...]
|
|
+# Values that contain spaces should be placed between quotes (" ")
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# Project related configuration options
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# This tag specifies the encoding used for all characters in the config file
|
|
+# that follow. The default is UTF-8 which is also the encoding used for all
|
|
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
|
|
+# iconv built into libc) for the transcoding. See
|
|
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
|
|
+
|
|
+DOXYFILE_ENCODING = UTF-8
|
|
+
|
|
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
|
|
+# by quotes) that should identify the project.
|
|
+
|
|
+PROJECT_NAME = "Poppler Qt4 "
|
|
+
|
|
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
|
|
+# This could be handy for archiving the generated documentation or
|
|
+# if some version control system is used.
|
|
+
|
|
+PROJECT_NUMBER = 0.61.1
|
|
+
|
|
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
|
+# base path where the generated documentation will be put.
|
|
+# If a relative path is entered, it will be relative to the location
|
|
+# where doxygen was started. If left blank the current directory will be used.
|
|
+
|
|
+OUTPUT_DIRECTORY =
|
|
+
|
|
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
|
|
+# 4096 sub-directories (in 2 levels) under the output directory of each output
|
|
+# format and will distribute the generated files over these directories.
|
|
+# Enabling this option can be useful when feeding doxygen a huge amount of
|
|
+# source files, where putting all generated files in the same directory would
|
|
+# otherwise cause performance problems for the file system.
|
|
+
|
|
+CREATE_SUBDIRS = NO
|
|
+
|
|
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
|
+# documentation generated by doxygen is written. Doxygen will use this
|
|
+# information to generate all constant output in the proper language.
|
|
+# The default language is English, other supported languages are:
|
|
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
|
|
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
|
|
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
|
|
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
|
|
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
|
|
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
|
|
+
|
|
+OUTPUT_LANGUAGE = English
|
|
+
|
|
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
|
|
+# include brief member descriptions after the members that are listed in
|
|
+# the file and class documentation (similar to JavaDoc).
|
|
+# Set to NO to disable this.
|
|
+
|
|
+BRIEF_MEMBER_DESC = NO
|
|
+
|
|
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
|
|
+# the brief description of a member or function before the detailed description.
|
|
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
|
|
+# brief descriptions will be completely suppressed.
|
|
+
|
|
+REPEAT_BRIEF = YES
|
|
+
|
|
+# This tag implements a quasi-intelligent brief description abbreviator
|
|
+# that is used to form the text in various listings. Each string
|
|
+# in this list, if found as the leading text of the brief description, will be
|
|
+# stripped from the text and the result after processing the whole list, is
|
|
+# used as the annotated text. Otherwise, the brief description is used as-is.
|
|
+# If left blank, the following values are used ("$name" is automatically
|
|
+# replaced with the name of the entity): "The $name class" "The $name widget"
|
|
+# "The $name file" "is" "provides" "specifies" "contains"
|
|
+# "represents" "a" "an" "the"
|
|
+
|
|
+ABBREVIATE_BRIEF =
|
|
+
|
|
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
|
|
+# Doxygen will generate a detailed section even if there is only a brief
|
|
+# description.
|
|
+
|
|
+ALWAYS_DETAILED_SEC = NO
|
|
+
|
|
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
|
|
+# inherited members of a class in the documentation of that class as if those
|
|
+# members were ordinary class members. Constructors, destructors and assignment
|
|
+# operators of the base classes will not be shown.
|
|
+
|
|
+INLINE_INHERITED_MEMB = NO
|
|
+
|
|
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
|
|
+# path before files name in the file list and in the header files. If set
|
|
+# to NO the shortest path that makes the file name unique will be used.
|
|
+
|
|
+FULL_PATH_NAMES = YES
|
|
+
|
|
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
|
|
+# can be used to strip a user-defined part of the path. Stripping is
|
|
+# only done if one of the specified strings matches the left-hand part of
|
|
+# the path. The tag can be used to show relative paths in the file list.
|
|
+# If left blank the directory from which doxygen is run is used as the
|
|
+# path to strip.
|
|
+
|
|
+STRIP_FROM_PATH =
|
|
+
|
|
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
|
|
+# the path mentioned in the documentation of a class, which tells
|
|
+# the reader which header file to include in order to use a class.
|
|
+# If left blank only the name of the header file containing the class
|
|
+# definition is used. Otherwise one should specify the include paths that
|
|
+# are normally passed to the compiler using the -I flag.
|
|
+
|
|
+STRIP_FROM_INC_PATH =
|
|
+
|
|
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
|
|
+# (but less readable) file names. This can be useful is your file systems
|
|
+# doesn't support long names like on DOS, Mac, or CD-ROM.
|
|
+
|
|
+SHORT_NAMES = NO
|
|
+
|
|
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
|
|
+# will interpret the first line (until the first dot) of a JavaDoc-style
|
|
+# comment as the brief description. If set to NO, the JavaDoc
|
|
+# comments will behave just like regular Qt-style comments
|
|
+# (thus requiring an explicit @brief command for a brief description.)
|
|
+
|
|
+JAVADOC_AUTOBRIEF = YES
|
|
+
|
|
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
|
|
+# interpret the first line (until the first dot) of a Qt-style
|
|
+# comment as the brief description. If set to NO, the comments
|
|
+# will behave just like regular Qt-style comments (thus requiring
|
|
+# an explicit \brief command for a brief description.)
|
|
+
|
|
+QT_AUTOBRIEF = NO
|
|
+
|
|
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
|
|
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
|
|
+# comments) as a brief description. This used to be the default behaviour.
|
|
+# The new default is to treat a multi-line C++ comment block as a detailed
|
|
+# description. Set this tag to YES if you prefer the old behaviour instead.
|
|
+
|
|
+MULTILINE_CPP_IS_BRIEF = NO
|
|
+
|
|
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
|
|
+# member inherits the documentation from any documented member that it
|
|
+# re-implements.
|
|
+
|
|
+INHERIT_DOCS = YES
|
|
+
|
|
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
|
|
+# a new page for each member. If set to NO, the documentation of a member will
|
|
+# be part of the file/class/namespace that contains it.
|
|
+
|
|
+SEPARATE_MEMBER_PAGES = NO
|
|
+
|
|
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
|
|
+# Doxygen uses this value to replace tabs by spaces in code fragments.
|
|
+
|
|
+TAB_SIZE = 8
|
|
+
|
|
+# This tag can be used to specify a number of aliases that acts
|
|
+# as commands in the documentation. An alias has the form "name=value".
|
|
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
|
|
+# put the command \sideeffect (or @sideeffect) in the documentation, which
|
|
+# will result in a user-defined paragraph with heading "Side Effects:".
|
|
+# You can put \n's in the value part of an alias to insert newlines.
|
|
+
|
|
+ALIASES =
|
|
+
|
|
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
|
|
+# sources only. Doxygen will then generate output that is more tailored for C.
|
|
+# For instance, some of the names that are used will be different. The list
|
|
+# of all members will be omitted, etc.
|
|
+
|
|
+OPTIMIZE_OUTPUT_FOR_C = NO
|
|
+
|
|
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
|
|
+# sources only. Doxygen will then generate output that is more tailored for
|
|
+# Java. For instance, namespaces will be presented as packages, qualified
|
|
+# scopes will look different, etc.
|
|
+
|
|
+OPTIMIZE_OUTPUT_JAVA = NO
|
|
+
|
|
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
|
|
+# sources only. Doxygen will then generate output that is more tailored for
|
|
+# Fortran.
|
|
+
|
|
+OPTIMIZE_FOR_FORTRAN = NO
|
|
+
|
|
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
|
|
+# sources. Doxygen will then generate output that is tailored for
|
|
+# VHDL.
|
|
+
|
|
+OPTIMIZE_OUTPUT_VHDL = NO
|
|
+
|
|
+# Doxygen selects the parser to use depending on the extension of the files it
|
|
+# parses. With this tag you can assign which parser to use for a given extension.
|
|
+# Doxygen has a built-in mapping, but you can override or extend it using this
|
|
+# tag. The format is ext=language, where ext is a file extension, and language
|
|
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
|
|
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
|
|
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
|
|
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
|
|
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
|
|
+
|
|
+EXTENSION_MAPPING =
|
|
+
|
|
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
|
|
+# to include (a tag file for) the STL sources as input, then you should
|
|
+# set this tag to YES in order to let doxygen match functions declarations and
|
|
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
|
|
+# func(std::string) {}). This also make the inheritance and collaboration
|
|
+# diagrams that involve STL classes more complete and accurate.
|
|
+
|
|
+BUILTIN_STL_SUPPORT = NO
|
|
+
|
|
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
|
|
+# enable parsing support.
|
|
+
|
|
+CPP_CLI_SUPPORT = NO
|
|
+
|
|
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
|
|
+# Doxygen will parse them like normal C++ but will assume all classes use public
|
|
+# instead of private inheritance when no explicit protection keyword is present.
|
|
+
|
|
+SIP_SUPPORT = NO
|
|
+
|
|
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
|
|
+# and setter methods for a property. Setting this option to YES (the default)
|
|
+# will make doxygen to replace the get and set methods by a property in the
|
|
+# documentation. This will only work if the methods are indeed getting or
|
|
+# setting a simple type. If this is not the case, or you want to show the
|
|
+# methods anyway, you should set this option to NO.
|
|
+
|
|
+IDL_PROPERTY_SUPPORT = YES
|
|
+
|
|
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
|
|
+# tag is set to YES, then doxygen will reuse the documentation of the first
|
|
+# member in the group (if any) for the other members of the group. By default
|
|
+# all members of a group must be documented explicitly.
|
|
+
|
|
+DISTRIBUTE_GROUP_DOC = NO
|
|
+
|
|
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
|
|
+# the same type (for instance a group of public functions) to be put as a
|
|
+# subgroup of that type (e.g. under the Public Functions section). Set it to
|
|
+# NO to prevent subgrouping. Alternatively, this can be done per class using
|
|
+# the \nosubgrouping command.
|
|
+
|
|
+SUBGROUPING = YES
|
|
+
|
|
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
|
|
+# is documented as struct, union, or enum with the name of the typedef. So
|
|
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
|
|
+# with name TypeT. When disabled the typedef will appear as a member of a file,
|
|
+# namespace, or class. And the struct will be named TypeS. This can typically
|
|
+# be useful for C code in case the coding convention dictates that all compound
|
|
+# types are typedef'ed and only the typedef is referenced, never the tag name.
|
|
+
|
|
+TYPEDEF_HIDES_STRUCT = NO
|
|
+
|
|
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
|
|
+# determine which symbols to keep in memory and which to flush to disk.
|
|
+# When the cache is full, less often used symbols will be written to disk.
|
|
+# For small to medium size projects (<1000 input files) the default value is
|
|
+# probably good enough. For larger projects a too small cache size can cause
|
|
+# doxygen to be busy swapping symbols to and from disk most of the time
|
|
+# causing a significant performance penality.
|
|
+# If the system has enough physical memory increasing the cache will improve the
|
|
+# performance by keeping more symbols in memory. Note that the value works on
|
|
+# a logarithmic scale so increasing the size by one will rougly double the
|
|
+# memory usage. The cache size is given by this formula:
|
|
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
|
|
+# corresponding to a cache size of 2^16 = 65536 symbols
|
|
+
|
|
+SYMBOL_CACHE_SIZE = 0
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# Build related configuration options
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
|
|
+# documentation are documented, even if no documentation was available.
|
|
+# Private class members and static file members will be hidden unless
|
|
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
|
|
+
|
|
+EXTRACT_ALL = NO
|
|
+
|
|
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
|
|
+# will be included in the documentation.
|
|
+
|
|
+EXTRACT_PRIVATE = NO
|
|
+
|
|
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
|
|
+# will be included in the documentation.
|
|
+
|
|
+EXTRACT_STATIC = NO
|
|
+
|
|
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
|
|
+# defined locally in source files will be included in the documentation.
|
|
+# If set to NO only classes defined in header files are included.
|
|
+
|
|
+EXTRACT_LOCAL_CLASSES = NO
|
|
+
|
|
+# This flag is only useful for Objective-C code. When set to YES local
|
|
+# methods, which are defined in the implementation section but not in
|
|
+# the interface are included in the documentation.
|
|
+# If set to NO (the default) only methods in the interface are included.
|
|
+
|
|
+EXTRACT_LOCAL_METHODS = NO
|
|
+
|
|
+# If this flag is set to YES, the members of anonymous namespaces will be
|
|
+# extracted and appear in the documentation as a namespace called
|
|
+# 'anonymous_namespace{file}', where file will be replaced with the base
|
|
+# name of the file that contains the anonymous namespace. By default
|
|
+# anonymous namespace are hidden.
|
|
+
|
|
+EXTRACT_ANON_NSPACES = NO
|
|
+
|
|
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
|
|
+# undocumented members of documented classes, files or namespaces.
|
|
+# If set to NO (the default) these members will be included in the
|
|
+# various overviews, but no documentation section is generated.
|
|
+# This option has no effect if EXTRACT_ALL is enabled.
|
|
+
|
|
+HIDE_UNDOC_MEMBERS = NO
|
|
+
|
|
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
|
|
+# undocumented classes that are normally visible in the class hierarchy.
|
|
+# If set to NO (the default) these classes will be included in the various
|
|
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
|
|
+
|
|
+HIDE_UNDOC_CLASSES = NO
|
|
+
|
|
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
|
|
+# friend (class|struct|union) declarations.
|
|
+# If set to NO (the default) these declarations will be included in the
|
|
+# documentation.
|
|
+
|
|
+HIDE_FRIEND_COMPOUNDS = YES
|
|
+
|
|
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
|
|
+# documentation blocks found inside the body of a function.
|
|
+# If set to NO (the default) these blocks will be appended to the
|
|
+# function's detailed documentation block.
|
|
+
|
|
+HIDE_IN_BODY_DOCS = NO
|
|
+
|
|
+# The INTERNAL_DOCS tag determines if documentation
|
|
+# that is typed after a \internal command is included. If the tag is set
|
|
+# to NO (the default) then the documentation will be excluded.
|
|
+# Set it to YES to include the internal documentation.
|
|
+
|
|
+INTERNAL_DOCS = NO
|
|
+
|
|
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
|
|
+# file names in lower-case letters. If set to YES upper-case letters are also
|
|
+# allowed. This is useful if you have classes or files whose names only differ
|
|
+# in case and if your file system supports case sensitive file names. Windows
|
|
+# and Mac users are advised to set this option to NO.
|
|
+
|
|
+CASE_SENSE_NAMES = YES
|
|
+
|
|
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
|
|
+# will show members with their full class and namespace scopes in the
|
|
+# documentation. If set to YES the scope will be hidden.
|
|
+
|
|
+HIDE_SCOPE_NAMES = NO
|
|
+
|
|
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
|
|
+# will put a list of the files that are included by a file in the documentation
|
|
+# of that file.
|
|
+
|
|
+SHOW_INCLUDE_FILES = YES
|
|
+
|
|
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
|
|
+# will list include files with double quotes in the documentation
|
|
+# rather than with sharp brackets.
|
|
+
|
|
+FORCE_LOCAL_INCLUDES = NO
|
|
+
|
|
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
|
|
+# is inserted in the documentation for inline members.
|
|
+
|
|
+INLINE_INFO = NO
|
|
+
|
|
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
|
|
+# will sort the (detailed) documentation of file and class members
|
|
+# alphabetically by member name. If set to NO the members will appear in
|
|
+# declaration order.
|
|
+
|
|
+SORT_MEMBER_DOCS = YES
|
|
+
|
|
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
|
|
+# brief documentation of file, namespace and class members alphabetically
|
|
+# by member name. If set to NO (the default) the members will appear in
|
|
+# declaration order.
|
|
+
|
|
+SORT_BRIEF_DOCS = YES
|
|
+
|
|
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
|
|
+# will sort the (brief and detailed) documentation of class members so that
|
|
+# constructors and destructors are listed first. If set to NO (the default)
|
|
+# the constructors will appear in the respective orders defined by
|
|
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
|
|
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
|
|
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
|
|
+
|
|
+SORT_MEMBERS_CTORS_1ST = NO
|
|
+
|
|
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
|
|
+# hierarchy of group names into alphabetical order. If set to NO (the default)
|
|
+# the group names will appear in their defined order.
|
|
+
|
|
+SORT_GROUP_NAMES = NO
|
|
+
|
|
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
|
|
+# sorted by fully-qualified names, including namespaces. If set to
|
|
+# NO (the default), the class list will be sorted only by class name,
|
|
+# not including the namespace part.
|
|
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
|
|
+# Note: This option applies only to the class list, not to the
|
|
+# alphabetical list.
|
|
+
|
|
+SORT_BY_SCOPE_NAME = YES
|
|
+
|
|
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
|
|
+# disable (NO) the todo list. This list is created by putting \todo
|
|
+# commands in the documentation.
|
|
+
|
|
+GENERATE_TODOLIST = YES
|
|
+
|
|
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
|
|
+# disable (NO) the test list. This list is created by putting \test
|
|
+# commands in the documentation.
|
|
+
|
|
+GENERATE_TESTLIST = YES
|
|
+
|
|
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
|
|
+# disable (NO) the bug list. This list is created by putting \bug
|
|
+# commands in the documentation.
|
|
+
|
|
+GENERATE_BUGLIST = YES
|
|
+
|
|
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
|
|
+# disable (NO) the deprecated list. This list is created by putting
|
|
+# \deprecated commands in the documentation.
|
|
+
|
|
+GENERATE_DEPRECATEDLIST= YES
|
|
+
|
|
+# The ENABLED_SECTIONS tag can be used to enable conditional
|
|
+# documentation sections, marked by \if sectionname ... \endif.
|
|
+
|
|
+ENABLED_SECTIONS =
|
|
+
|
|
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
|
|
+# the initial value of a variable or define consists of for it to appear in
|
|
+# the documentation. If the initializer consists of more lines than specified
|
|
+# here it will be hidden. Use a value of 0 to hide initializers completely.
|
|
+# The appearance of the initializer of individual variables and defines in the
|
|
+# documentation can be controlled using \showinitializer or \hideinitializer
|
|
+# command in the documentation regardless of this setting.
|
|
+
|
|
+MAX_INITIALIZER_LINES = 30
|
|
+
|
|
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
|
|
+# at the bottom of the documentation of classes and structs. If set to YES the
|
|
+# list will mention the files that were used to generate the documentation.
|
|
+
|
|
+SHOW_USED_FILES = YES
|
|
+
|
|
+# If the sources in your project are distributed over multiple directories
|
|
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
|
|
+# in the documentation. The default is NO.
|
|
+
|
|
+SHOW_DIRECTORIES = NO
|
|
+
|
|
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
|
|
+# This will remove the Files entry from the Quick Index and from the
|
|
+# Folder Tree View (if specified). The default is YES.
|
|
+
|
|
+SHOW_FILES = YES
|
|
+
|
|
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
|
|
+# Namespaces page.
|
|
+# This will remove the Namespaces entry from the Quick Index
|
|
+# and from the Folder Tree View (if specified). The default is YES.
|
|
+
|
|
+SHOW_NAMESPACES = YES
|
|
+
|
|
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
|
|
+# doxygen should invoke to get the current version for each file (typically from
|
|
+# the version control system). Doxygen will invoke the program by executing (via
|
|
+# popen()) the command <command> <input-file>, where <command> is the value of
|
|
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
|
|
+# provided by doxygen. Whatever the program writes to standard output
|
|
+# is used as the file version. See the manual for examples.
|
|
+
|
|
+FILE_VERSION_FILTER =
|
|
+
|
|
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
|
|
+# by doxygen. The layout file controls the global structure of the generated
|
|
+# output files in an output format independent way. The create the layout file
|
|
+# that represents doxygen's defaults, run doxygen with the -l option.
|
|
+# You can optionally specify a file name after the option, if omitted
|
|
+# DoxygenLayout.xml will be used as the name of the layout file.
|
|
+
|
|
+LAYOUT_FILE =
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# configuration options related to warning and progress messages
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# The QUIET tag can be used to turn on/off the messages that are generated
|
|
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
|
|
+
|
|
+QUIET = NO
|
|
+
|
|
+# The WARNINGS tag can be used to turn on/off the warning messages that are
|
|
+# generated by doxygen. Possible values are YES and NO. If left blank
|
|
+# NO is used.
|
|
+
|
|
+WARNINGS = YES
|
|
+
|
|
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
|
|
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
|
|
+# automatically be disabled.
|
|
+
|
|
+WARN_IF_UNDOCUMENTED = YES
|
|
+
|
|
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
|
|
+# potential errors in the documentation, such as not documenting some
|
|
+# parameters in a documented function, or documenting parameters that
|
|
+# don't exist or using markup commands wrongly.
|
|
+
|
|
+WARN_IF_DOC_ERROR = YES
|
|
+
|
|
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
|
|
+# functions that are documented, but have no documentation for their parameters
|
|
+# or return value. If set to NO (the default) doxygen will only warn about
|
|
+# wrong or incomplete parameter documentation, but not about the absence of
|
|
+# documentation.
|
|
+
|
|
+WARN_NO_PARAMDOC = NO
|
|
+
|
|
+# The WARN_FORMAT tag determines the format of the warning messages that
|
|
+# doxygen can produce. The string should contain the $file, $line, and $text
|
|
+# tags, which will be replaced by the file and line number from which the
|
|
+# warning originated and the warning text. Optionally the format may contain
|
|
+# $version, which will be replaced by the version of the file (if it could
|
|
+# be obtained via FILE_VERSION_FILTER)
|
|
+
|
|
+WARN_FORMAT = "$file:$line: $text "
|
|
+
|
|
+# The WARN_LOGFILE tag can be used to specify a file to which warning
|
|
+# and error messages should be written. If left blank the output is written
|
|
+# to stderr.
|
|
+
|
|
+WARN_LOGFILE =
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# configuration options related to the input files
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# The INPUT tag can be used to specify the files and/or directories that contain
|
|
+# documented source files. You may enter file names like "myfile.cpp" or
|
|
+# directories like "/usr/src/myproject". Separate the files or directories
|
|
+# with spaces.
|
|
+
|
|
+INPUT = Mainpage.dox \
|
|
+ poppler-annotation.h \
|
|
+ poppler-form.h \
|
|
+ poppler-link.h \
|
|
+ poppler-qt4.h \
|
|
+ poppler-optcontent.h \
|
|
+ poppler-page-transition.h
|
|
+
|
|
+# This tag can be used to specify the character encoding of the source files
|
|
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
|
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
|
|
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
|
|
+# the list of possible encodings.
|
|
+
|
|
+INPUT_ENCODING = UTF-8
|
|
+
|
|
+# If the value of the INPUT tag contains directories, you can use the
|
|
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
|
+# and *.h) to filter out the source-files in the directories. If left
|
|
+# blank the following patterns are tested:
|
|
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
|
|
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
|
|
+
|
|
+FILE_PATTERNS =
|
|
+
|
|
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
|
|
+# should be searched for input files as well. Possible values are YES and NO.
|
|
+# If left blank NO is used.
|
|
+
|
|
+RECURSIVE = NO
|
|
+
|
|
+# The EXCLUDE tag can be used to specify files and/or directories that should
|
|
+# excluded from the INPUT source files. This way you can easily exclude a
|
|
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
|
|
+
|
|
+EXCLUDE =
|
|
+
|
|
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
|
|
+# directories that are symbolic links (a Unix filesystem feature) are excluded
|
|
+# from the input.
|
|
+
|
|
+EXCLUDE_SYMLINKS = NO
|
|
+
|
|
+# If the value of the INPUT tag contains directories, you can use the
|
|
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
|
|
+# certain files from those directories. Note that the wildcards are matched
|
|
+# against the file with absolute path, so to exclude all test directories
|
|
+# for example use the pattern */test/*
|
|
+
|
|
+EXCLUDE_PATTERNS =
|
|
+
|
|
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
|
|
+# (namespaces, classes, functions, etc.) that should be excluded from the
|
|
+# output. The symbol name can be a fully qualified name, a word, or if the
|
|
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
|
|
+# AClass::ANamespace, ANamespace::*Test
|
|
+
|
|
+EXCLUDE_SYMBOLS =
|
|
+
|
|
+# The EXAMPLE_PATH tag can be used to specify one or more files or
|
|
+# directories that contain example code fragments that are included (see
|
|
+# the \include command).
|
|
+
|
|
+EXAMPLE_PATH =
|
|
+
|
|
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
|
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
|
+# and *.h) to filter out the source-files in the directories. If left
|
|
+# blank all files are included.
|
|
+
|
|
+EXAMPLE_PATTERNS =
|
|
+
|
|
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
|
|
+# searched for input files to be used with the \include or \dontinclude
|
|
+# commands irrespective of the value of the RECURSIVE tag.
|
|
+# Possible values are YES and NO. If left blank NO is used.
|
|
+
|
|
+EXAMPLE_RECURSIVE = NO
|
|
+
|
|
+# The IMAGE_PATH tag can be used to specify one or more files or
|
|
+# directories that contain image that are included in the documentation (see
|
|
+# the \image command).
|
|
+
|
|
+IMAGE_PATH =
|
|
+
|
|
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
|
+# invoke to filter for each input file. Doxygen will invoke the filter program
|
|
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
|
|
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
|
|
+# input file. Doxygen will then use the output that the filter program writes
|
|
+# to standard output.
|
|
+# If FILTER_PATTERNS is specified, this tag will be
|
|
+# ignored.
|
|
+
|
|
+INPUT_FILTER =
|
|
+
|
|
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
|
|
+# basis.
|
|
+# Doxygen will compare the file name with each pattern and apply the
|
|
+# filter if there is a match.
|
|
+# The filters are a list of the form:
|
|
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
|
|
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
|
|
+# is applied to all files.
|
|
+
|
|
+FILTER_PATTERNS =
|
|
+
|
|
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
|
|
+# INPUT_FILTER) will be used to filter the input files when producing source
|
|
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
|
|
+
|
|
+FILTER_SOURCE_FILES = NO
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# configuration options related to source browsing
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
|
|
+# be generated. Documented entities will be cross-referenced with these sources.
|
|
+# Note: To get rid of all source code in the generated output, make sure also
|
|
+# VERBATIM_HEADERS is set to NO.
|
|
+
|
|
+SOURCE_BROWSER = NO
|
|
+
|
|
+# Setting the INLINE_SOURCES tag to YES will include the body
|
|
+# of functions and classes directly in the documentation.
|
|
+
|
|
+INLINE_SOURCES = NO
|
|
+
|
|
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
|
|
+# doxygen to hide any special comment blocks from generated source code
|
|
+# fragments. Normal C and C++ comments will always remain visible.
|
|
+
|
|
+STRIP_CODE_COMMENTS = YES
|
|
+
|
|
+# If the REFERENCED_BY_RELATION tag is set to YES
|
|
+# then for each documented function all documented
|
|
+# functions referencing it will be listed.
|
|
+
|
|
+REFERENCED_BY_RELATION = YES
|
|
+
|
|
+# If the REFERENCES_RELATION tag is set to YES
|
|
+# then for each documented function all documented entities
|
|
+# called/used by that function will be listed.
|
|
+
|
|
+REFERENCES_RELATION = YES
|
|
+
|
|
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
|
|
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
|
|
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
|
|
+# link to the source code.
|
|
+# Otherwise they will link to the documentation.
|
|
+
|
|
+REFERENCES_LINK_SOURCE = YES
|
|
+
|
|
+# If the USE_HTAGS tag is set to YES then the references to source code
|
|
+# will point to the HTML generated by the htags(1) tool instead of doxygen
|
|
+# built-in source browser. The htags tool is part of GNU's global source
|
|
+# tagging system (see http://www.gnu.org/software/global/global.html). You
|
|
+# will need version 4.8.6 or higher.
|
|
+
|
|
+USE_HTAGS = NO
|
|
+
|
|
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
|
|
+# will generate a verbatim copy of the header file for each class for
|
|
+# which an include is specified. Set to NO to disable this.
|
|
+
|
|
+VERBATIM_HEADERS = YES
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# configuration options related to the alphabetical class index
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
|
|
+# of all compounds will be generated. Enable this if the project
|
|
+# contains a lot of classes, structs, unions or interfaces.
|
|
+
|
|
+ALPHABETICAL_INDEX = YES
|
|
+
|
|
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
|
|
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
|
|
+# in which this list will be split (can be a number in the range [1..20])
|
|
+
|
|
+COLS_IN_ALPHA_INDEX = 5
|
|
+
|
|
+# In case all classes in a project start with a common prefix, all
|
|
+# classes will be put under the same header in the alphabetical index.
|
|
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
|
|
+# should be ignored while generating the index headers.
|
|
+
|
|
+IGNORE_PREFIX =
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# configuration options related to the HTML output
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
|
|
+# generate HTML output.
|
|
+
|
|
+GENERATE_HTML = YES
|
|
+
|
|
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
|
|
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
|
+# put in front of it. If left blank `html' will be used as the default path.
|
|
+
|
|
+HTML_OUTPUT = APIDOCS-html
|
|
+
|
|
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
|
|
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
|
|
+# doxygen will generate files with .html extension.
|
|
+
|
|
+HTML_FILE_EXTENSION = .html
|
|
+
|
|
+# The HTML_HEADER tag can be used to specify a personal HTML header for
|
|
+# each generated HTML page. If it is left blank doxygen will generate a
|
|
+# standard header.
|
|
+
|
|
+HTML_HEADER =
|
|
+
|
|
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
|
|
+# each generated HTML page. If it is left blank doxygen will generate a
|
|
+# standard footer.
|
|
+
|
|
+HTML_FOOTER =
|
|
+
|
|
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
|
|
+# style sheet that is used by each HTML page. It can be used to
|
|
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
|
|
+# will generate a default style sheet. Note that doxygen will try to copy
|
|
+# the style sheet file to the HTML output directory, so don't put your own
|
|
+# stylesheet in the HTML output directory as well, or it will be erased!
|
|
+
|
|
+HTML_STYLESHEET =
|
|
+
|
|
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
|
|
+# Doxygen will adjust the colors in the stylesheet and background images
|
|
+# according to this color. Hue is specified as an angle on a colorwheel,
|
|
+# see http://en.wikipedia.org/wiki/Hue for more information.
|
|
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
|
|
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
|
|
+# The allowed range is 0 to 359.
|
|
+
|
|
+HTML_COLORSTYLE_HUE = 220
|
|
+
|
|
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
|
|
+# the colors in the HTML output. For a value of 0 the output will use
|
|
+# grayscales only. A value of 255 will produce the most vivid colors.
|
|
+
|
|
+HTML_COLORSTYLE_SAT = 100
|
|
+
|
|
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
|
|
+# the luminance component of the colors in the HTML output. Values below
|
|
+# 100 gradually make the output lighter, whereas values above 100 make
|
|
+# the output darker. The value divided by 100 is the actual gamma applied,
|
|
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
|
|
+# and 100 does not change the gamma.
|
|
+
|
|
+HTML_COLORSTYLE_GAMMA = 80
|
|
+
|
|
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
|
|
+# page will contain the date and time when the page was generated. Setting
|
|
+# this to NO can help when comparing the output of multiple runs.
|
|
+
|
|
+HTML_TIMESTAMP = YES
|
|
+
|
|
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
|
|
+# files or namespaces will be aligned in HTML using tables. If set to
|
|
+# NO a bullet list will be used.
|
|
+
|
|
+HTML_ALIGN_MEMBERS = YES
|
|
+
|
|
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
|
|
+# documentation will contain sections that can be hidden and shown after the
|
|
+# page has loaded. For this to work a browser that supports
|
|
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
|
|
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
|
|
+
|
|
+HTML_DYNAMIC_SECTIONS = NO
|
|
+
|
|
+# If the GENERATE_DOCSET tag is set to YES, additional index files
|
|
+# will be generated that can be used as input for Apple's Xcode 3
|
|
+# integrated development environment, introduced with OSX 10.5 (Leopard).
|
|
+# To create a documentation set, doxygen will generate a Makefile in the
|
|
+# HTML output directory. Running make will produce the docset in that
|
|
+# directory and running "make install" will install the docset in
|
|
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
|
|
+# it at startup.
|
|
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
|
|
+# for more information.
|
|
+
|
|
+GENERATE_DOCSET = NO
|
|
+
|
|
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
|
|
+# feed. A documentation feed provides an umbrella under which multiple
|
|
+# documentation sets from a single provider (such as a company or product suite)
|
|
+# can be grouped.
|
|
+
|
|
+DOCSET_FEEDNAME = "Doxygen generated docs"
|
|
+
|
|
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
|
|
+# should uniquely identify the documentation set bundle. This should be a
|
|
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
|
|
+# will append .docset to the name.
|
|
+
|
|
+DOCSET_BUNDLE_ID = org.doxygen.Project
|
|
+
|
|
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
|
|
+# the documentation publisher. This should be a reverse domain-name style
|
|
+# string, e.g. com.mycompany.MyDocSet.documentation.
|
|
+
|
|
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
|
|
+
|
|
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
|
|
+
|
|
+DOCSET_PUBLISHER_NAME = Publisher
|
|
+
|
|
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
|
|
+# will be generated that can be used as input for tools like the
|
|
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
|
|
+# of the generated HTML documentation.
|
|
+
|
|
+GENERATE_HTMLHELP = NO
|
|
+
|
|
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
|
|
+# be used to specify the file name of the resulting .chm file. You
|
|
+# can add a path in front of the file if the result should not be
|
|
+# written to the html output directory.
|
|
+
|
|
+CHM_FILE =
|
|
+
|
|
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
|
|
+# be used to specify the location (absolute path including file name) of
|
|
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
|
|
+# the HTML help compiler on the generated index.hhp.
|
|
+
|
|
+HHC_LOCATION =
|
|
+
|
|
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
|
|
+# controls if a separate .chi index file is generated (YES) or that
|
|
+# it should be included in the master .chm file (NO).
|
|
+
|
|
+GENERATE_CHI = NO
|
|
+
|
|
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
|
|
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
|
|
+# content.
|
|
+
|
|
+CHM_INDEX_ENCODING =
|
|
+
|
|
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
|
|
+# controls whether a binary table of contents is generated (YES) or a
|
|
+# normal table of contents (NO) in the .chm file.
|
|
+
|
|
+BINARY_TOC = NO
|
|
+
|
|
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
|
|
+# to the contents of the HTML help documentation and to the tree view.
|
|
+
|
|
+TOC_EXPAND = NO
|
|
+
|
|
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
|
|
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
|
|
+# that can be used as input for Qt's qhelpgenerator to generate a
|
|
+# Qt Compressed Help (.qch) of the generated HTML documentation.
|
|
+
|
|
+GENERATE_QHP = YES
|
|
+
|
|
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
|
|
+# be used to specify the file name of the resulting .qch file.
|
|
+# The path specified is relative to the HTML output folder.
|
|
+
|
|
+QCH_FILE = poppler-qt4.qch
|
|
+
|
|
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
|
|
+# Qt Help Project output. For more information please see
|
|
+# http://doc.trolltech.com/qthelpproject.html#namespace
|
|
+
|
|
+QHP_NAMESPACE = org.freedesktop.poppler.qt4
|
|
+
|
|
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
|
|
+# Qt Help Project output. For more information please see
|
|
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
|
|
+
|
|
+QHP_VIRTUAL_FOLDER = doc
|
|
+
|
|
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
|
|
+# add. For more information please see
|
|
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
|
|
+
|
|
+QHP_CUST_FILTER_NAME = "Poppler 0.15.0"
|
|
+
|
|
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
|
|
+# custom filter to add. For more information please see
|
|
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
|
|
+# Qt Help Project / Custom Filters</a>.
|
|
+
|
|
+QHP_CUST_FILTER_ATTRS = poppler
|
|
+
|
|
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
|
|
+# project's
|
|
+# filter section matches.
|
|
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
|
|
+# Qt Help Project / Filter Attributes</a>.
|
|
+
|
|
+QHP_SECT_FILTER_ATTRS = poppler
|
|
+
|
|
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
|
|
+# be used to specify the location of Qt's qhelpgenerator.
|
|
+# If non-empty doxygen will try to run qhelpgenerator on the generated
|
|
+# .qhp file.
|
|
+
|
|
+QHG_LOCATION = qhelpgenerator
|
|
+
|
|
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
|
|
+# will be generated, which together with the HTML files, form an Eclipse help
|
|
+# plugin. To install this plugin and make it available under the help contents
|
|
+# menu in Eclipse, the contents of the directory containing the HTML and XML
|
|
+# files needs to be copied into the plugins directory of eclipse. The name of
|
|
+# the directory within the plugins directory should be the same as
|
|
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
|
|
+# the help appears.
|
|
+
|
|
+GENERATE_ECLIPSEHELP = NO
|
|
+
|
|
+# A unique identifier for the eclipse help plugin. When installing the plugin
|
|
+# the directory name containing the HTML and XML files should also have
|
|
+# this name.
|
|
+
|
|
+ECLIPSE_DOC_ID = org.doxygen.Project
|
|
+
|
|
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
|
|
+# top of each HTML page. The value NO (the default) enables the index and
|
|
+# the value YES disables it.
|
|
+
|
|
+DISABLE_INDEX = NO
|
|
+
|
|
+# This tag can be used to set the number of enum values (range [1..20])
|
|
+# that doxygen will group on one line in the generated HTML documentation.
|
|
+
|
|
+ENUM_VALUES_PER_LINE = 4
|
|
+
|
|
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
|
|
+# structure should be generated to display hierarchical information.
|
|
+# If the tag value is set to YES, a side panel will be generated
|
|
+# containing a tree-like index structure (just like the one that
|
|
+# is generated for HTML Help). For this to work a browser that supports
|
|
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
|
|
+# Windows users are probably better off using the HTML help feature.
|
|
+
|
|
+GENERATE_TREEVIEW = NO
|
|
+
|
|
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
|
|
+# and Class Hierarchy pages using a tree view instead of an ordered list.
|
|
+
|
|
+USE_INLINE_TREES = NO
|
|
+
|
|
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
|
|
+# used to set the initial width (in pixels) of the frame in which the tree
|
|
+# is shown.
|
|
+
|
|
+TREEVIEW_WIDTH = 250
|
|
+
|
|
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
|
|
+# links to external symbols imported via tag files in a separate window.
|
|
+
|
|
+EXT_LINKS_IN_WINDOW = NO
|
|
+
|
|
+# Use this tag to change the font size of Latex formulas included
|
|
+# as images in the HTML documentation. The default is 10. Note that
|
|
+# when you change the font size after a successful doxygen run you need
|
|
+# to manually remove any form_*.png images from the HTML output directory
|
|
+# to force them to be regenerated.
|
|
+
|
|
+FORMULA_FONTSIZE = 10
|
|
+
|
|
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
|
|
+# generated for formulas are transparent PNGs. Transparent PNGs are
|
|
+# not supported properly for IE 6.0, but are supported on all modern browsers.
|
|
+# Note that when changing this option you need to delete any form_*.png files
|
|
+# in the HTML output before the changes have effect.
|
|
+
|
|
+FORMULA_TRANSPARENT = YES
|
|
+
|
|
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
|
|
+# for the HTML output. The underlying search engine uses javascript
|
|
+# and DHTML and should work on any modern browser. Note that when using
|
|
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
|
|
+# (GENERATE_DOCSET) there is already a search function so this one should
|
|
+# typically be disabled. For large projects the javascript based search engine
|
|
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
|
|
+
|
|
+SEARCHENGINE = NO
|
|
+
|
|
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
|
|
+# implemented using a PHP enabled web server instead of at the web client
|
|
+# using Javascript. Doxygen will generate the search PHP script and index
|
|
+# file to put on the web server. The advantage of the server
|
|
+# based approach is that it scales better to large projects and allows
|
|
+# full text search. The disadvances is that it is more difficult to setup
|
|
+# and does not have live searching capabilities.
|
|
+
|
|
+SERVER_BASED_SEARCH = NO
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# configuration options related to the LaTeX output
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
|
|
+# generate Latex output.
|
|
+
|
|
+GENERATE_LATEX = YES
|
|
+
|
|
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
|
|
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
|
+# put in front of it. If left blank `latex' will be used as the default path.
|
|
+
|
|
+LATEX_OUTPUT = APIDOCS-latex
|
|
+
|
|
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
|
|
+# invoked. If left blank `latex' will be used as the default command name.
|
|
+# Note that when enabling USE_PDFLATEX this option is only used for
|
|
+# generating bitmaps for formulas in the HTML output, but not in the
|
|
+# Makefile that is written to the output directory.
|
|
+
|
|
+LATEX_CMD_NAME = latex
|
|
+
|
|
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
|
|
+# generate index for LaTeX. If left blank `makeindex' will be used as the
|
|
+# default command name.
|
|
+
|
|
+MAKEINDEX_CMD_NAME = makeindex
|
|
+
|
|
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
|
|
+# LaTeX documents. This may be useful for small projects and may help to
|
|
+# save some trees in general.
|
|
+
|
|
+COMPACT_LATEX = NO
|
|
+
|
|
+# The PAPER_TYPE tag can be used to set the paper type that is used
|
|
+# by the printer. Possible values are: a4, a4wide, letter, legal and
|
|
+# executive. If left blank a4wide will be used.
|
|
+
|
|
+PAPER_TYPE = a4wide
|
|
+
|
|
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
|
|
+# packages that should be included in the LaTeX output.
|
|
+
|
|
+EXTRA_PACKAGES =
|
|
+
|
|
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
|
|
+# the generated latex document. The header should contain everything until
|
|
+# the first chapter. If it is left blank doxygen will generate a
|
|
+# standard header. Notice: only use this tag if you know what you are doing!
|
|
+
|
|
+LATEX_HEADER =
|
|
+
|
|
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
|
|
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
|
|
+# contain links (just like the HTML output) instead of page references
|
|
+# This makes the output suitable for online browsing using a pdf viewer.
|
|
+
|
|
+PDF_HYPERLINKS = NO
|
|
+
|
|
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
|
|
+# plain latex in the generated Makefile. Set this option to YES to get a
|
|
+# higher quality PDF documentation.
|
|
+
|
|
+USE_PDFLATEX = NO
|
|
+
|
|
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
|
|
+# command to the generated LaTeX files. This will instruct LaTeX to keep
|
|
+# running if errors occur, instead of asking the user for help.
|
|
+# This option is also used when generating formulas in HTML.
|
|
+
|
|
+LATEX_BATCHMODE = NO
|
|
+
|
|
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
|
|
+# include the index chapters (such as File Index, Compound Index, etc.)
|
|
+# in the output.
|
|
+
|
|
+LATEX_HIDE_INDICES = NO
|
|
+
|
|
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
|
|
+# source code with syntax highlighting in the LaTeX output.
|
|
+# Note that which sources are shown also depends on other settings
|
|
+# such as SOURCE_BROWSER.
|
|
+
|
|
+LATEX_SOURCE_CODE = NO
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# configuration options related to the RTF output
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
|
|
+# The RTF output is optimized for Word 97 and may not look very pretty with
|
|
+# other RTF readers or editors.
|
|
+
|
|
+GENERATE_RTF = NO
|
|
+
|
|
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
|
|
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
|
+# put in front of it. If left blank `rtf' will be used as the default path.
|
|
+
|
|
+RTF_OUTPUT = rtf
|
|
+
|
|
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
|
|
+# RTF documents. This may be useful for small projects and may help to
|
|
+# save some trees in general.
|
|
+
|
|
+COMPACT_RTF = NO
|
|
+
|
|
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
|
|
+# will contain hyperlink fields. The RTF file will
|
|
+# contain links (just like the HTML output) instead of page references.
|
|
+# This makes the output suitable for online browsing using WORD or other
|
|
+# programs which support those fields.
|
|
+# Note: wordpad (write) and others do not support links.
|
|
+
|
|
+RTF_HYPERLINKS = NO
|
|
+
|
|
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
|
|
+# config file, i.e. a series of assignments. You only have to provide
|
|
+# replacements, missing definitions are set to their default value.
|
|
+
|
|
+RTF_STYLESHEET_FILE =
|
|
+
|
|
+# Set optional variables used in the generation of an rtf document.
|
|
+# Syntax is similar to doxygen's config file.
|
|
+
|
|
+RTF_EXTENSIONS_FILE =
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# configuration options related to the man page output
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
|
|
+# generate man pages
|
|
+
|
|
+GENERATE_MAN = NO
|
|
+
|
|
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
|
|
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
|
+# put in front of it. If left blank `man' will be used as the default path.
|
|
+
|
|
+MAN_OUTPUT = man
|
|
+
|
|
+# The MAN_EXTENSION tag determines the extension that is added to
|
|
+# the generated man pages (default is the subroutine's section .3)
|
|
+
|
|
+MAN_EXTENSION = .3
|
|
+
|
|
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
|
|
+# then it will generate one additional man file for each entity
|
|
+# documented in the real man page(s). These additional files
|
|
+# only source the real man page, but without them the man command
|
|
+# would be unable to find the correct page. The default is NO.
|
|
+
|
|
+MAN_LINKS = NO
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# configuration options related to the XML output
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# If the GENERATE_XML tag is set to YES Doxygen will
|
|
+# generate an XML file that captures the structure of
|
|
+# the code including all documentation.
|
|
+
|
|
+GENERATE_XML = NO
|
|
+
|
|
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
|
|
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
|
+# put in front of it. If left blank `xml' will be used as the default path.
|
|
+
|
|
+XML_OUTPUT = xml
|
|
+
|
|
+# The XML_SCHEMA tag can be used to specify an XML schema,
|
|
+# which can be used by a validating XML parser to check the
|
|
+# syntax of the XML files.
|
|
+
|
|
+XML_SCHEMA =
|
|
+
|
|
+# The XML_DTD tag can be used to specify an XML DTD,
|
|
+# which can be used by a validating XML parser to check the
|
|
+# syntax of the XML files.
|
|
+
|
|
+XML_DTD =
|
|
+
|
|
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
|
|
+# dump the program listings (including syntax highlighting
|
|
+# and cross-referencing information) to the XML output. Note that
|
|
+# enabling this will significantly increase the size of the XML output.
|
|
+
|
|
+XML_PROGRAMLISTING = YES
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# configuration options for the AutoGen Definitions output
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
|
|
+# generate an AutoGen Definitions (see autogen.sf.net) file
|
|
+# that captures the structure of the code including all
|
|
+# documentation. Note that this feature is still experimental
|
|
+# and incomplete at the moment.
|
|
+
|
|
+GENERATE_AUTOGEN_DEF = NO
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# configuration options related to the Perl module output
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
|
|
+# generate a Perl module file that captures the structure of
|
|
+# the code including all documentation. Note that this
|
|
+# feature is still experimental and incomplete at the
|
|
+# moment.
|
|
+
|
|
+GENERATE_PERLMOD = NO
|
|
+
|
|
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
|
|
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
|
|
+# to generate PDF and DVI output from the Perl module output.
|
|
+
|
|
+PERLMOD_LATEX = NO
|
|
+
|
|
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
|
|
+# nicely formatted so it can be parsed by a human reader.
|
|
+# This is useful
|
|
+# if you want to understand what is going on.
|
|
+# On the other hand, if this
|
|
+# tag is set to NO the size of the Perl module output will be much smaller
|
|
+# and Perl will parse it just the same.
|
|
+
|
|
+PERLMOD_PRETTY = YES
|
|
+
|
|
+# The names of the make variables in the generated doxyrules.make file
|
|
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
|
|
+# This is useful so different doxyrules.make files included by the same
|
|
+# Makefile don't overwrite each other's variables.
|
|
+
|
|
+PERLMOD_MAKEVAR_PREFIX =
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# Configuration options related to the preprocessor
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
|
|
+# evaluate all C-preprocessor directives found in the sources and include
|
|
+# files.
|
|
+
|
|
+ENABLE_PREPROCESSING = YES
|
|
+
|
|
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
|
|
+# names in the source code. If set to NO (the default) only conditional
|
|
+# compilation will be performed. Macro expansion can be done in a controlled
|
|
+# way by setting EXPAND_ONLY_PREDEF to YES.
|
|
+
|
|
+MACRO_EXPANSION = YES
|
|
+
|
|
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
|
|
+# then the macro expansion is limited to the macros specified with the
|
|
+# PREDEFINED and EXPAND_AS_DEFINED tags.
|
|
+
|
|
+EXPAND_ONLY_PREDEF = YES
|
|
+
|
|
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
|
|
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
|
|
+
|
|
+SEARCH_INCLUDES = YES
|
|
+
|
|
+# The INCLUDE_PATH tag can be used to specify one or more directories that
|
|
+# contain include files that are not input files but should be processed by
|
|
+# the preprocessor.
|
|
+
|
|
+INCLUDE_PATH =
|
|
+
|
|
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
|
|
+# patterns (like *.h and *.hpp) to filter out the header-files in the
|
|
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
|
|
+# be used.
|
|
+
|
|
+INCLUDE_FILE_PATTERNS =
|
|
+
|
|
+# The PREDEFINED tag can be used to specify one or more macro names that
|
|
+# are defined before the preprocessor is started (similar to the -D option of
|
|
+# gcc). The argument of the tag is a list of macros of the form: name
|
|
+# or name=definition (no spaces). If the definition and the = are
|
|
+# omitted =1 is assumed. To prevent a macro definition from being
|
|
+# undefined via #undef or recursively expanded use the := operator
|
|
+# instead of the = operator.
|
|
+
|
|
+PREDEFINED = "Q_DECL_DEPRECATED=" \
|
|
+ "POPPLER_QT4_EXPORT="
|
|
+
|
|
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
|
|
+# this tag can be used to specify a list of macro names that should be expanded.
|
|
+# The macro definition that is found in the sources will be used.
|
|
+# Use the PREDEFINED tag if you want to use a different macro definition.
|
|
+
|
|
+EXPAND_AS_DEFINED =
|
|
+
|
|
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
|
|
+# doxygen's preprocessor will remove all function-like macros that are alone
|
|
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
|
|
+# function macros are typically used for boiler-plate code, and will confuse
|
|
+# the parser if not removed.
|
|
+
|
|
+SKIP_FUNCTION_MACROS = YES
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# Configuration::additions related to external references
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# The TAGFILES option can be used to specify one or more tagfiles.
|
|
+# Optionally an initial location of the external documentation
|
|
+# can be added for each tagfile. The format of a tag file without
|
|
+# this location is as follows:
|
|
+#
|
|
+# TAGFILES = file1 file2 ...
|
|
+# Adding location for the tag files is done as follows:
|
|
+#
|
|
+# TAGFILES = file1=loc1 "file2 = loc2" ...
|
|
+# where "loc1" and "loc2" can be relative or absolute paths or
|
|
+# URLs. If a location is present for each tag, the installdox tool
|
|
+# does not have to be run to correct the links.
|
|
+# Note that each tag file must have a unique name
|
|
+# (where the name does NOT include the path)
|
|
+# If a tag file is not located in the directory in which doxygen
|
|
+# is run, you must also specify the path to the tagfile here.
|
|
+
|
|
+TAGFILES =
|
|
+
|
|
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
|
|
+# a tag file that is based on the input files it reads.
|
|
+
|
|
+GENERATE_TAGFILE =
|
|
+
|
|
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
|
|
+# in the class index. If set to NO only the inherited external classes
|
|
+# will be listed.
|
|
+
|
|
+ALLEXTERNALS = NO
|
|
+
|
|
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
|
|
+# in the modules index. If set to NO, only the current project's groups will
|
|
+# be listed.
|
|
+
|
|
+EXTERNAL_GROUPS = YES
|
|
+
|
|
+# The PERL_PATH should be the absolute path and name of the perl script
|
|
+# interpreter (i.e. the result of `which perl').
|
|
+
|
|
+PERL_PATH = /usr/bin/perl
|
|
+
|
|
+#---------------------------------------------------------------------------
|
|
+# Configuration options related to the dot tool
|
|
+#---------------------------------------------------------------------------
|
|
+
|
|
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
|
|
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
|
|
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
|
|
+# this option is superseded by the HAVE_DOT option below. This is only a
|
|
+# fallback. It is recommended to install and use dot, since it yields more
|
|
+# powerful graphs.
|
|
+
|
|
+CLASS_DIAGRAMS = YES
|
|
+
|
|
+# You can define message sequence charts within doxygen comments using the \msc
|
|
+# command. Doxygen will then run the mscgen tool (see
|
|
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
|
|
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
|
|
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
|
|
+# default search path.
|
|
+
|
|
+MSCGEN_PATH =
|
|
+
|
|
+# If set to YES, the inheritance and collaboration graphs will hide
|
|
+# inheritance and usage relations if the target is undocumented
|
|
+# or is not a class.
|
|
+
|
|
+HIDE_UNDOC_RELATIONS = YES
|
|
+
|
|
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
|
|
+# available from the path. This tool is part of Graphviz, a graph visualization
|
|
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
|
|
+# have no effect if this option is set to NO (the default)
|
|
+
|
|
+HAVE_DOT = YES
|
|
+
|
|
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
|
|
+# allowed to run in parallel. When set to 0 (the default) doxygen will
|
|
+# base this on the number of processors available in the system. You can set it
|
|
+# explicitly to a value larger than 0 to get control over the balance
|
|
+# between CPU load and processing speed.
|
|
+
|
|
+DOT_NUM_THREADS = 0
|
|
+
|
|
+# By default doxygen will write a font called FreeSans.ttf to the output
|
|
+# directory and reference it in all dot files that doxygen generates. This
|
|
+# font does not include all possible unicode characters however, so when you need
|
|
+# these (or just want a differently looking font) you can specify the font name
|
|
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
|
|
+# which can be done by putting it in a standard location or by setting the
|
|
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
|
|
+# containing the font.
|
|
+
|
|
+DOT_FONTNAME = FreeSans.ttf
|
|
+
|
|
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
|
|
+# The default size is 10pt.
|
|
+
|
|
+DOT_FONTSIZE = 10
|
|
+
|
|
+# By default doxygen will tell dot to use the output directory to look for the
|
|
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
|
|
+# different font using DOT_FONTNAME you can set the path where dot
|
|
+# can find it using this tag.
|
|
+
|
|
+DOT_FONTPATH =
|
|
+
|
|
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
|
+# will generate a graph for each documented class showing the direct and
|
|
+# indirect inheritance relations. Setting this tag to YES will force the
|
|
+# the CLASS_DIAGRAMS tag to NO.
|
|
+
|
|
+CLASS_GRAPH = YES
|
|
+
|
|
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
|
+# will generate a graph for each documented class showing the direct and
|
|
+# indirect implementation dependencies (inheritance, containment, and
|
|
+# class references variables) of the class with other documented classes.
|
|
+
|
|
+COLLABORATION_GRAPH = YES
|
|
+
|
|
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
|
|
+# will generate a graph for groups, showing the direct groups dependencies
|
|
+
|
|
+GROUP_GRAPHS = YES
|
|
+
|
|
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
|
|
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
|
|
+# Language.
|
|
+
|
|
+UML_LOOK = NO
|
|
+
|
|
+# If set to YES, the inheritance and collaboration graphs will show the
|
|
+# relations between templates and their instances.
|
|
+
|
|
+TEMPLATE_RELATIONS = NO
|
|
+
|
|
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
|
|
+# tags are set to YES then doxygen will generate a graph for each documented
|
|
+# file showing the direct and indirect include dependencies of the file with
|
|
+# other documented files.
|
|
+
|
|
+INCLUDE_GRAPH = YES
|
|
+
|
|
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
|
|
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
|
|
+# documented header file showing the documented files that directly or
|
|
+# indirectly include this file.
|
|
+
|
|
+INCLUDED_BY_GRAPH = YES
|
|
+
|
|
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
|
|
+# doxygen will generate a call dependency graph for every global function
|
|
+# or class method. Note that enabling this option will significantly increase
|
|
+# the time of a run. So in most cases it will be better to enable call graphs
|
|
+# for selected functions only using the \callgraph command.
|
|
+
|
|
+CALL_GRAPH = NO
|
|
+
|
|
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
|
|
+# doxygen will generate a caller dependency graph for every global function
|
|
+# or class method. Note that enabling this option will significantly increase
|
|
+# the time of a run. So in most cases it will be better to enable caller
|
|
+# graphs for selected functions only using the \callergraph command.
|
|
+
|
|
+CALLER_GRAPH = NO
|
|
+
|
|
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
|
|
+# will graphical hierarchy of all classes instead of a textual one.
|
|
+
|
|
+GRAPHICAL_HIERARCHY = YES
|
|
+
|
|
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
|
|
+# then doxygen will show the dependencies a directory has on other directories
|
|
+# in a graphical way. The dependency relations are determined by the #include
|
|
+# relations between the files in the directories.
|
|
+
|
|
+DIRECTORY_GRAPH = YES
|
|
+
|
|
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
|
+# generated by dot. Possible values are png, jpg, or gif
|
|
+# If left blank png will be used.
|
|
+
|
|
+DOT_IMAGE_FORMAT = png
|
|
+
|
|
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
|
|
+# found. If left blank, it is assumed the dot tool can be found in the path.
|
|
+
|
|
+DOT_PATH =
|
|
+
|
|
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
|
|
+# contain dot files that are included in the documentation (see the
|
|
+# \dotfile command).
|
|
+
|
|
+DOTFILE_DIRS =
|
|
+
|
|
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
|
|
+# nodes that will be shown in the graph. If the number of nodes in a graph
|
|
+# becomes larger than this value, doxygen will truncate the graph, which is
|
|
+# visualized by representing a node as a red box. Note that doxygen if the
|
|
+# number of direct children of the root node in a graph is already larger than
|
|
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
|
|
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
|
|
+
|
|
+DOT_GRAPH_MAX_NODES = 50
|
|
+
|
|
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
|
|
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
|
|
+# from the root by following a path via at most 3 edges will be shown. Nodes
|
|
+# that lay further from the root node will be omitted. Note that setting this
|
|
+# option to 1 or 2 may greatly reduce the computation time needed for large
|
|
+# code bases. Also note that the size of a graph can be further restricted by
|
|
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
|
|
+
|
|
+MAX_DOT_GRAPH_DEPTH = 0
|
|
+
|
|
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
|
|
+# background. This is disabled by default, because dot on Windows does not
|
|
+# seem to support this out of the box. Warning: Depending on the platform used,
|
|
+# enabling this option may lead to badly anti-aliased labels on the edges of
|
|
+# a graph (i.e. they become hard to read).
|
|
+
|
|
+DOT_TRANSPARENT = NO
|
|
+
|
|
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
|
|
+# files in one run (i.e. multiple -o and -T options on the command line). This
|
|
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
|
|
+# support this, this feature is disabled by default.
|
|
+
|
|
+DOT_MULTI_TARGETS = NO
|
|
+
|
|
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
|
|
+# generate a legend page explaining the meaning of the various boxes and
|
|
+# arrows in the dot generated graphs.
|
|
+
|
|
+GENERATE_LEGEND = YES
|
|
+
|
|
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
|
|
+# remove the intermediate dot files that are used to generate
|
|
+# the various graphs.
|
|
+
|
|
+DOT_CLEANUP = YES
|
|
diff --git a/qt4/src/Mainpage.dox b/qt4/src/Mainpage.dox
|
|
new file mode 100644
|
|
index 00000000..30398c3d
|
|
--- /dev/null
|
|
+++ b/qt4/src/Mainpage.dox
|
|
@@ -0,0 +1,85 @@
|
|
+/**
|
|
+@mainpage The Poppler Qt4 interface library
|
|
+
|
|
+The %Poppler Qt4 interface library, libpoppler-qt4, is a library that
|
|
+allows Qt4 programmers to easily load and render PDF files. The
|
|
+%Poppler Qt4 interface library uses poppler internally to do its job,
|
|
+but the Qt4 programmer will never have to worry about poppler
|
|
+internals.
|
|
+
|
|
+
|
|
+@section help Current Status
|
|
+
|
|
+The %Poppler Qt4 interface library is quite stable and working.
|
|
+
|
|
+@section refimpl Example Programs
|
|
+
|
|
+Examples programs can be found in the qt4/test directory. The %Poppler
|
|
+Qt4 interface library is also used in the KDE's
|
|
+document viewer <a href="http://okular.kde.org">Okular</a>. The source files
|
|
+for Okular's PDF plugin (%Poppler-based) can be found on the git server
|
|
+of the KDE project, under
|
|
+<a
|
|
+href="http://quickgit.kde.org/?p=okular.git&a=tree&f=generators/poppler">this
|
|
+URL</a>.
|
|
+
|
|
+
|
|
+@section req How to use the Poppler Qt4 interface library in three easy steps
|
|
+
|
|
+Programmer who would like to use the %Poppler Qt4 interface library
|
|
+simply need to add the following line to their C++ source files:
|
|
+
|
|
+@code
|
|
+#include <poppler-qt4.h>
|
|
+@endcode
|
|
+
|
|
+A PDF document can then be loaded as follows:
|
|
+@code
|
|
+QString filename;
|
|
+
|
|
+Poppler::Document* document = Poppler::Document::load(filename);
|
|
+if (!document || document->isLocked()) {
|
|
+
|
|
+ // ... error message ....
|
|
+
|
|
+ delete document;
|
|
+ return;
|
|
+}
|
|
+@endcode
|
|
+
|
|
+Pages can be rendered to QImages with the following commands:
|
|
+
|
|
+@code
|
|
+// Paranoid safety check
|
|
+if (document == 0) {
|
|
+ // ... error message ...
|
|
+ return;
|
|
+}
|
|
+
|
|
+// Access page of the PDF file
|
|
+Poppler::Page* pdfPage = document->page(pageNumber); // Document starts at page 0
|
|
+if (pdfPage == 0) {
|
|
+ // ... error message ...
|
|
+ return;
|
|
+}
|
|
+
|
|
+// Generate a QImage of the rendered page
|
|
+QImage image = pdfPage->renderToImage(xres, yres, x, y, width, height);
|
|
+if (image.isNull()) {
|
|
+ // ... error message ...
|
|
+ return;
|
|
+}
|
|
+
|
|
+// ... use image ...
|
|
+
|
|
+// after the usage, the page must be deleted
|
|
+delete pdfPage;
|
|
+@endcode
|
|
+
|
|
+Finally, don't forget to destroy the document:
|
|
+
|
|
+@code
|
|
+delete document;
|
|
+@endcode
|
|
+ */
|
|
+
|
|
diff --git a/qt4/src/poppler-annotation-helper.h b/qt4/src/poppler-annotation-helper.h
|
|
new file mode 100644
|
|
index 00000000..3150569c
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-annotation-helper.h
|
|
@@ -0,0 +1,183 @@
|
|
+/* poppler-annotation-helper.h: qt interface to poppler
|
|
+ * Copyright (C) 2006, 2008, 2017, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2012, Fabio D'Urso <fabiodurso@hotmail.it>
|
|
+ * Adapting code from
|
|
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include <memory>
|
|
+
|
|
+#include <QtCore/QDebug>
|
|
+
|
|
+#include <Object.h>
|
|
+
|
|
+class QColor;
|
|
+
|
|
+class AnnotColor;
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+class XPDFReader
|
|
+{
|
|
+ public:
|
|
+ // find named symbol and parse it
|
|
+ static inline void lookupName( Dict *, char *, QString & dest );
|
|
+ static inline void lookupString( Dict *, char *, QString & dest );
|
|
+ static inline void lookupBool( Dict *, char *, bool & dest );
|
|
+ static inline void lookupInt( Dict *, char *, int & dest );
|
|
+ static inline void lookupNum( Dict *, char *, double & dest );
|
|
+ static inline int lookupNumArray( Dict *, char *, double * dest, int len );
|
|
+ static inline void lookupColor( Dict *, char *, QColor & color );
|
|
+ static inline void lookupIntRef( Dict *, char *, int & dest );
|
|
+ static inline void lookupDate( Dict *, char *, QDateTime & dest );
|
|
+ // transform from user coords to normalized ones using the matrix M
|
|
+ static inline void transform( double * M, double x, double y, QPointF &res );
|
|
+ static inline void invTransform( double * M, const QPointF &p, double &x, double &y );
|
|
+};
|
|
+
|
|
+void XPDFReader::lookupName( Dict * dict, char * type, QString & dest )
|
|
+{
|
|
+ Object nameObj = dict->lookup( type );
|
|
+ if ( nameObj.isNull() )
|
|
+ return;
|
|
+ if ( nameObj.isName() )
|
|
+ dest = nameObj.getName();
|
|
+ else
|
|
+ qDebug() << type << " is not Name." << endl;
|
|
+}
|
|
+
|
|
+void XPDFReader::lookupString( Dict * dict, char * type, QString & dest )
|
|
+{
|
|
+ Object stringObj = dict->lookup( type );
|
|
+ if ( stringObj.isNull() )
|
|
+ return;
|
|
+ if ( stringObj.isString() )
|
|
+ dest = stringObj.getString()->c_str();
|
|
+ else
|
|
+ qDebug() << type << " is not String." << endl;
|
|
+}
|
|
+
|
|
+void XPDFReader::lookupBool( Dict * dict, char * type, bool & dest )
|
|
+{
|
|
+ Object boolObj = dict->lookup( type );
|
|
+ if ( boolObj.isNull() )
|
|
+ return;
|
|
+ if ( boolObj.isBool() )
|
|
+ dest = boolObj.getBool() == true;
|
|
+ else
|
|
+ qDebug() << type << " is not Bool." << endl;
|
|
+}
|
|
+
|
|
+void XPDFReader::lookupInt( Dict * dict, char * type, int & dest )
|
|
+{
|
|
+ Object intObj = dict->lookup( type );
|
|
+ if ( intObj.isNull() )
|
|
+ return;
|
|
+ if ( intObj.isInt() )
|
|
+ dest = intObj.getInt();
|
|
+ else
|
|
+ qDebug() << type << " is not Int." << endl;
|
|
+}
|
|
+
|
|
+void XPDFReader::lookupNum( Dict * dict, char * type, double & dest )
|
|
+{
|
|
+ Object numObj = dict->lookup( type );
|
|
+ if ( numObj.isNull() )
|
|
+ return;
|
|
+ if ( numObj.isNum() )
|
|
+ dest = numObj.getNum();
|
|
+ else
|
|
+ qDebug() << type << " is not Num." << endl;
|
|
+}
|
|
+
|
|
+int XPDFReader::lookupNumArray( Dict * dict, char * type, double * dest, int len )
|
|
+{
|
|
+ Object arrObj = dict->lookup( type );
|
|
+ if ( arrObj.isNull() )
|
|
+ return 0;
|
|
+ if ( arrObj.isArray() )
|
|
+ {
|
|
+ len = qMin( len, arrObj.arrayGetLength() );
|
|
+ for ( int i = 0; i < len; i++ )
|
|
+ {
|
|
+ Object numObj = arrObj.arrayGet( i );
|
|
+ dest[i] = numObj.getNum();
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ len = 0;
|
|
+ qDebug() << type << "is not Array." << endl;
|
|
+ }
|
|
+ return len;
|
|
+}
|
|
+
|
|
+void XPDFReader::lookupColor( Dict * dict, char * type, QColor & dest )
|
|
+{
|
|
+ double c[3];
|
|
+ if ( XPDFReader::lookupNumArray( dict, type, c, 3 ) == 3 )
|
|
+ dest = QColor( (int)(c[0]*255.0), (int)(c[1]*255.0), (int)(c[2]*255.0));
|
|
+}
|
|
+
|
|
+void XPDFReader::lookupIntRef( Dict * dict, char * type, int & dest )
|
|
+{
|
|
+ Object refObj = dict->lookupNF( type ).copy();
|
|
+ if ( refObj.isNull() )
|
|
+ return;
|
|
+ if ( refObj.isRef() )
|
|
+ dest = refObj.getRefNum();
|
|
+ else
|
|
+ qDebug() << type << " is not Ref." << endl;
|
|
+}
|
|
+
|
|
+void XPDFReader::lookupDate( Dict * dict, char * type, QDateTime & dest )
|
|
+{
|
|
+ Object dateObj = dict->lookup( type );
|
|
+ if ( dateObj.isNull() )
|
|
+ return;
|
|
+ if ( dateObj.isString() )
|
|
+ {
|
|
+ dest = convertDate( dateObj.getString()->c_str() );
|
|
+ }
|
|
+ else
|
|
+ qDebug() << type << " is not Date" << endl;
|
|
+}
|
|
+
|
|
+void XPDFReader::transform( double * M, double x, double y, QPointF &res )
|
|
+{
|
|
+ res.setX( M[0] * x + M[2] * y + M[4] );
|
|
+ res.setY( M[1] * x + M[3] * y + M[5] );
|
|
+}
|
|
+
|
|
+void XPDFReader::invTransform( double * M, const QPointF &p, double &x, double &y )
|
|
+{
|
|
+ const double det = M[0]*M[3] - M[1]*M[2];
|
|
+ Q_ASSERT(det != 0);
|
|
+
|
|
+ const double invM[4] = { M[3]/det, -M[1]/det, -M[2]/det, M[0]/det };
|
|
+ const double xt = p.x() - M[4];
|
|
+ const double yt = p.y() - M[5];
|
|
+
|
|
+ x = invM[0] * xt + invM[2] * yt;
|
|
+ y = invM[1] * xt + invM[3] * yt;
|
|
+}
|
|
+
|
|
+QColor convertAnnotColor( const AnnotColor *color );
|
|
+std::unique_ptr<AnnotColor> convertQColor( const QColor &c );
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-annotation-private.h b/qt4/src/poppler-annotation-private.h
|
|
new file mode 100644
|
|
index 00000000..b530e2f2
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-annotation-private.h
|
|
@@ -0,0 +1,112 @@
|
|
+/* poppler-annotation-private.h: qt interface to poppler
|
|
+ * Copyright (C) 2007, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2012, Tobias Koenig <tokoe@kdab.com>
|
|
+ * Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
|
|
+ * Copyright (C) 2012, 2014, Albert Astals Cid <aacid@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef _POPPLER_ANNOTATION_PRIVATE_H_
|
|
+#define _POPPLER_ANNOTATION_PRIVATE_H_
|
|
+
|
|
+#include <QtCore/QLinkedList>
|
|
+#include <QtCore/QPointF>
|
|
+#include <QtCore/QSharedDataPointer>
|
|
+
|
|
+#include "poppler-annotation.h"
|
|
+
|
|
+#include <Object.h>
|
|
+
|
|
+class Annot;
|
|
+class AnnotPath;
|
|
+class Link;
|
|
+class Page;
|
|
+class PDFRectangle;
|
|
+
|
|
+namespace Poppler
|
|
+{
|
|
+class DocumentData;
|
|
+
|
|
+class AnnotationPrivate : public QSharedData
|
|
+{
|
|
+ public:
|
|
+ AnnotationPrivate();
|
|
+ virtual ~AnnotationPrivate();
|
|
+
|
|
+ void addRevision(Annotation *ann, Annotation::RevScope scope, Annotation::RevType type);
|
|
+
|
|
+ /* Returns an Annotation of the right subclass whose d_ptr points to
|
|
+ * this AnnotationPrivate */
|
|
+ virtual Annotation * makeAlias() = 0;
|
|
+
|
|
+ /* properties: contents related */
|
|
+ QString author;
|
|
+ QString contents;
|
|
+ QString uniqueName;
|
|
+ QDateTime modDate; // before or equal to currentDateTime()
|
|
+ QDateTime creationDate; // before or equal to modifyDate
|
|
+
|
|
+ /* properties: look/interaction related */
|
|
+ int flags;
|
|
+ QRectF boundary;
|
|
+
|
|
+ /* style and popup */
|
|
+ Annotation::Style style;
|
|
+ Annotation::Popup popup;
|
|
+
|
|
+ /* revisions */
|
|
+ Annotation::RevScope revisionScope;
|
|
+ Annotation::RevType revisionType;
|
|
+ QList<Annotation*> revisions;
|
|
+
|
|
+ /* After this call, the Annotation object will behave like a wrapper for
|
|
+ * the specified Annot object. All cached values are discarded */
|
|
+ void tieToNativeAnnot(Annot *ann, ::Page *page, DocumentData *doc);
|
|
+
|
|
+ /* Creates a new Annot object on the specified page, flushes current
|
|
+ * values to that object and ties this Annotation to that object */
|
|
+ virtual Annot* createNativeAnnot(::Page *destPage, DocumentData *doc) = 0;
|
|
+
|
|
+ /* Inited to 0 (i.e. untied annotation) */
|
|
+ Annot *pdfAnnot;
|
|
+ ::Page *pdfPage;
|
|
+ DocumentData * parentDoc;
|
|
+
|
|
+ /* The following helpers only work if pdfPage is set */
|
|
+ void flushBaseAnnotationProperties();
|
|
+ void fillNormalizationMTX(double MTX[6], int pageRotation) const;
|
|
+ void fillTransformationMTX(double MTX[6]) const;
|
|
+ QRectF fromPdfRectangle(const PDFRectangle &r) const;
|
|
+ PDFRectangle boundaryToPdfRectangle(const QRectF &r, int flags) const;
|
|
+ AnnotPath * toAnnotPath(const QLinkedList<QPointF> &l) const;
|
|
+
|
|
+ /* Scan page for annotations, parentId=0 searches for root annotations, subtypes empty means all subtypes */
|
|
+ static QList<Annotation*> findAnnotations(::Page *pdfPage, DocumentData *doc, const QSet<Annotation::SubType> &subtypes, int parentId = 0);
|
|
+
|
|
+ /* Add given annotation to given page */
|
|
+ static void addAnnotationToPage(::Page *pdfPage, DocumentData *doc, const Annotation * ann);
|
|
+
|
|
+ /* Remove annotation from page and destroy ann */
|
|
+ static void removeAnnotationFromPage(::Page *pdfPage, const Annotation * ann);
|
|
+
|
|
+ Ref pdfObjectReference() const;
|
|
+
|
|
+ Link* additionalAction( Annotation::AdditionalActionType type ) const;
|
|
+};
|
|
+
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-annotation.cc b/qt4/src/poppler-annotation.cc
|
|
new file mode 100644
|
|
index 00000000..8a7f60b1
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-annotation.cc
|
|
@@ -0,0 +1,5118 @@
|
|
+/* poppler-annotation.cc: qt interface to poppler
|
|
+ * Copyright (C) 2006, 2009, 2012-2015 Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2006, 2008, 2010 Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2012, Guillermo A. Amaral B. <gamaral@kde.org>
|
|
+ * Copyright (C) 2012-2014 Fabio D'Urso <fabiodurso@hotmail.it>
|
|
+ * Copyright (C) 2012, 2015, Tobias Koenig <tokoe@kdab.com>
|
|
+ * Adapting code from
|
|
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+// qt/kde includes
|
|
+#include <QtCore/QRegExp>
|
|
+#include <QtCore/QtAlgorithms>
|
|
+#include <QtXml/QDomElement>
|
|
+#include <QtGui/QColor>
|
|
+#include <QtGui/QTransform>
|
|
+
|
|
+// local includes
|
|
+#include "poppler-annotation.h"
|
|
+#include "poppler-link.h"
|
|
+#include "poppler-qt4.h"
|
|
+#include "poppler-annotation-helper.h"
|
|
+#include "poppler-annotation-private.h"
|
|
+#include "poppler-page-private.h"
|
|
+#include "poppler-private.h"
|
|
+
|
|
+// poppler includes
|
|
+#include <Page.h>
|
|
+#include <Annot.h>
|
|
+#include <Gfx.h>
|
|
+#include <Error.h>
|
|
+#include <FileSpec.h>
|
|
+#include <Link.h>
|
|
+
|
|
+/* Almost all getters directly query the underlying poppler annotation, with
|
|
+ * the exceptions of link, file attachment, sound, movie and screen annotations,
|
|
+ * Whose data retrieval logic has not been moved yet. Their getters return
|
|
+ * static data set at creation time by findAnnotations
|
|
+ */
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+//BEGIN AnnotationUtils implementation
|
|
+Annotation * AnnotationUtils::createAnnotation( const QDomElement & annElement )
|
|
+{
|
|
+ // safety check on annotation element
|
|
+ if ( !annElement.hasAttribute( "type" ) )
|
|
+ return nullptr;
|
|
+
|
|
+ // build annotation of given type
|
|
+ Annotation * annotation = nullptr;
|
|
+ int typeNumber = annElement.attribute( "type" ).toInt();
|
|
+ switch ( typeNumber )
|
|
+ {
|
|
+ case Annotation::AText:
|
|
+ annotation = new TextAnnotation( annElement );
|
|
+ break;
|
|
+ case Annotation::ALine:
|
|
+ annotation = new LineAnnotation( annElement );
|
|
+ break;
|
|
+ case Annotation::AGeom:
|
|
+ annotation = new GeomAnnotation( annElement );
|
|
+ break;
|
|
+ case Annotation::AHighlight:
|
|
+ annotation = new HighlightAnnotation( annElement );
|
|
+ break;
|
|
+ case Annotation::AStamp:
|
|
+ annotation = new StampAnnotation( annElement );
|
|
+ break;
|
|
+ case Annotation::AInk:
|
|
+ annotation = new InkAnnotation( annElement );
|
|
+ break;
|
|
+ case Annotation::ACaret:
|
|
+ annotation = new CaretAnnotation( annElement );
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ // return created annotation
|
|
+ return annotation;
|
|
+}
|
|
+
|
|
+void AnnotationUtils::storeAnnotation( const Annotation * ann, QDomElement & annElement,
|
|
+ QDomDocument & document )
|
|
+{
|
|
+ // save annotation's type as element's attribute
|
|
+ annElement.setAttribute( "type", (uint)ann->subType() );
|
|
+
|
|
+ // append all annotation data as children of this node
|
|
+ ann->store( annElement, document );
|
|
+}
|
|
+
|
|
+QDomElement AnnotationUtils::findChildElement( const QDomNode & parentNode,
|
|
+ const QString & name )
|
|
+{
|
|
+ // loop through the whole children and return a 'name' named element
|
|
+ QDomNode subNode = parentNode.firstChild();
|
|
+ while( subNode.isElement() )
|
|
+ {
|
|
+ QDomElement element = subNode.toElement();
|
|
+ if ( element.tagName() == name )
|
|
+ return element;
|
|
+ subNode = subNode.nextSibling();
|
|
+ }
|
|
+ // if the name can't be found, return a dummy null element
|
|
+ return QDomElement();
|
|
+}
|
|
+//END AnnotationUtils implementation
|
|
+
|
|
+
|
|
+//BEGIN Annotation implementation
|
|
+AnnotationPrivate::AnnotationPrivate()
|
|
+ : flags( 0 ), revisionScope ( Annotation::Root ),
|
|
+ revisionType ( Annotation::None ), pdfAnnot ( nullptr ), pdfPage ( nullptr ),
|
|
+ parentDoc ( nullptr )
|
|
+{
|
|
+}
|
|
+
|
|
+void AnnotationPrivate::addRevision( Annotation *ann, Annotation::RevScope scope, Annotation::RevType type )
|
|
+{
|
|
+ /* Since ownership stays with the caller, create an alias of ann */
|
|
+ revisions.append( ann->d_ptr->makeAlias() );
|
|
+
|
|
+ /* Set revision properties */
|
|
+ revisionScope = scope;
|
|
+ revisionType = type;
|
|
+}
|
|
+
|
|
+AnnotationPrivate::~AnnotationPrivate()
|
|
+{
|
|
+ // Delete all children revisions
|
|
+ qDeleteAll( revisions );
|
|
+
|
|
+ // Release Annot object
|
|
+ if (pdfAnnot)
|
|
+ pdfAnnot->decRefCnt();
|
|
+}
|
|
+
|
|
+void AnnotationPrivate::tieToNativeAnnot(Annot *ann, ::Page *page, Poppler::DocumentData * doc)
|
|
+{
|
|
+ if (pdfAnnot)
|
|
+ {
|
|
+ error(errIO, -1, "Annotation is already tied");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ pdfAnnot = ann;
|
|
+ pdfPage = page;
|
|
+ parentDoc = doc;
|
|
+
|
|
+ pdfAnnot->incRefCnt();
|
|
+}
|
|
+
|
|
+/* This method is called when a new annotation is created, after pdfAnnot and
|
|
+ * pdfPage have been set */
|
|
+void AnnotationPrivate::flushBaseAnnotationProperties()
|
|
+{
|
|
+ Q_ASSERT ( pdfPage );
|
|
+
|
|
+ Annotation *q = makeAlias(); // Setters are defined in the public class
|
|
+
|
|
+ // Since pdfAnnot has been set, this calls will write in the Annot object
|
|
+ q->setAuthor(author);
|
|
+ q->setContents(contents);
|
|
+ q->setUniqueName(uniqueName);
|
|
+ q->setModificationDate(modDate);
|
|
+ q->setCreationDate(creationDate);
|
|
+ q->setFlags(flags);
|
|
+ //q->setBoundary(boundary); -- already set by subclass-specific code
|
|
+ q->setStyle(style);
|
|
+ q->setPopup(popup);
|
|
+
|
|
+ // Flush revisions
|
|
+ foreach (Annotation *r, revisions)
|
|
+ {
|
|
+ // TODO: Flush revision
|
|
+ delete r; // Object is no longer needed
|
|
+ }
|
|
+
|
|
+ delete q;
|
|
+
|
|
+ // Clear some members to save memory
|
|
+ author.clear();
|
|
+ contents.clear();
|
|
+ uniqueName.clear();
|
|
+ revisions.clear();
|
|
+}
|
|
+
|
|
+// Returns matrix to convert from user space coords (oriented according to the
|
|
+// specified rotation) to normalized coords
|
|
+void AnnotationPrivate::fillNormalizationMTX(double MTX[6], int pageRotation) const
|
|
+{
|
|
+ Q_ASSERT ( pdfPage );
|
|
+
|
|
+ // build a normalized transform matrix for this page at 100% scale
|
|
+ GfxState * gfxState = new GfxState( 72.0, 72.0, pdfPage->getCropBox(), pageRotation, true );
|
|
+ const double * gfxCTM = gfxState->getCTM();
|
|
+
|
|
+ double w = pdfPage->getCropWidth();
|
|
+ double h = pdfPage->getCropHeight();
|
|
+
|
|
+ // Swap width and height if the page is rotated landscape or seascape
|
|
+ if ( pageRotation == 90 || pageRotation == 270 )
|
|
+ {
|
|
+ double t = w;
|
|
+ w = h;
|
|
+ h = t;
|
|
+ }
|
|
+
|
|
+ for ( int i = 0; i < 6; i+=2 )
|
|
+ {
|
|
+ MTX[i] = gfxCTM[i] / w;
|
|
+ MTX[i+1] = gfxCTM[i+1] / h;
|
|
+ }
|
|
+ delete gfxState;
|
|
+}
|
|
+
|
|
+// Returns matrix to convert from user space coords (i.e. those that are stored
|
|
+// in the PDF file) to normalized coords (i.e. those that we expose to clients).
|
|
+// This method also applies a rotation around the top-left corner if the
|
|
+// FixedRotation flag is set.
|
|
+void AnnotationPrivate::fillTransformationMTX(double MTX[6]) const
|
|
+{
|
|
+ Q_ASSERT ( pdfPage );
|
|
+ Q_ASSERT ( pdfAnnot );
|
|
+
|
|
+ const int pageRotate = pdfPage->getRotate();
|
|
+
|
|
+ if ( pageRotate == 0 || ( pdfAnnot->getFlags() & Annot::flagNoRotate ) == 0 )
|
|
+ {
|
|
+ // Use the normalization matrix for this page's rotation
|
|
+ fillNormalizationMTX( MTX, pageRotate );
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ // Clients expect coordinates relative to this page's rotation, but
|
|
+ // FixedRotation annotations internally use unrotated coordinates:
|
|
+ // construct matrix to both normalize and rotate coordinates using the
|
|
+ // top-left corner as rotation pivot
|
|
+
|
|
+ double MTXnorm[6];
|
|
+ fillNormalizationMTX( MTXnorm, pageRotate );
|
|
+
|
|
+ QTransform transform( MTXnorm[0], MTXnorm[1], MTXnorm[2],
|
|
+ MTXnorm[3], MTXnorm[4], MTXnorm[5] );
|
|
+ transform.translate( +pdfAnnot->getXMin(), +pdfAnnot->getYMax() );
|
|
+ transform.rotate( pageRotate );
|
|
+ transform.translate( -pdfAnnot->getXMin(), -pdfAnnot->getYMax() );
|
|
+
|
|
+ MTX[0] = transform.m11();
|
|
+ MTX[1] = transform.m12();
|
|
+ MTX[2] = transform.m21();
|
|
+ MTX[3] = transform.m22();
|
|
+ MTX[4] = transform.dx();
|
|
+ MTX[5] = transform.dy();
|
|
+ }
|
|
+}
|
|
+
|
|
+QRectF AnnotationPrivate::fromPdfRectangle(const PDFRectangle &r) const
|
|
+{
|
|
+ double swp, MTX[6];
|
|
+ fillTransformationMTX(MTX);
|
|
+
|
|
+ QPointF p1, p2;
|
|
+ XPDFReader::transform( MTX, r.x1, r.y1, p1 );
|
|
+ XPDFReader::transform( MTX, r.x2, r.y2, p2 );
|
|
+
|
|
+ double tl_x = p1.x();
|
|
+ double tl_y = p1.y();
|
|
+ double br_x = p2.x();
|
|
+ double br_y = p2.y();
|
|
+
|
|
+ if (tl_x > br_x)
|
|
+ {
|
|
+ swp = tl_x;
|
|
+ tl_x = br_x;
|
|
+ br_x = swp;
|
|
+ }
|
|
+
|
|
+ if (tl_y > br_y)
|
|
+ {
|
|
+ swp = tl_y;
|
|
+ tl_y = br_y;
|
|
+ br_y = swp;
|
|
+ }
|
|
+
|
|
+ return QRectF( QPointF(tl_x,tl_y) , QPointF(br_x,br_y) );
|
|
+}
|
|
+
|
|
+// This function converts a boundary QRectF in normalized coords to a
|
|
+// PDFRectangle in user coords. If the FixedRotation flag is set, this function
|
|
+// also applies a rotation around the top-left corner: it's the inverse of
|
|
+// the transformation produced by fillTransformationMTX, but we can't use
|
|
+// fillTransformationMTX here because it relies on the native annotation
|
|
+// object's boundary rect to be already set up.
|
|
+PDFRectangle AnnotationPrivate::boundaryToPdfRectangle(const QRectF &r, int flags) const
|
|
+{
|
|
+ Q_ASSERT ( pdfPage );
|
|
+
|
|
+ const int pageRotate = pdfPage->getRotate();
|
|
+
|
|
+ double MTX[6];
|
|
+ fillNormalizationMTX( MTX, pageRotate );
|
|
+
|
|
+ double tl_x, tl_y, br_x, br_y, swp;
|
|
+ XPDFReader::invTransform( MTX, r.topLeft(), tl_x, tl_y );
|
|
+ XPDFReader::invTransform( MTX, r.bottomRight(), br_x, br_y );
|
|
+
|
|
+ if (tl_x > br_x)
|
|
+ {
|
|
+ swp = tl_x;
|
|
+ tl_x = br_x;
|
|
+ br_x = swp;
|
|
+ }
|
|
+
|
|
+ if (tl_y > br_y)
|
|
+ {
|
|
+ swp = tl_y;
|
|
+ tl_y = br_y;
|
|
+ br_y = swp;
|
|
+ }
|
|
+
|
|
+ const int rotationFixUp = ( flags & Annotation::FixedRotation ) ? pageRotate : 0;
|
|
+ const double width = br_x - tl_x;
|
|
+ const double height = br_y - tl_y;
|
|
+
|
|
+ if ( rotationFixUp == 0 )
|
|
+ return PDFRectangle(tl_x, tl_y, br_x, br_y);
|
|
+ else if ( rotationFixUp == 90 )
|
|
+ return PDFRectangle(tl_x, tl_y - width, tl_x + height, tl_y);
|
|
+ else if ( rotationFixUp == 180 )
|
|
+ return PDFRectangle(br_x, tl_y - height, br_x + width, tl_y);
|
|
+ else // rotationFixUp == 270
|
|
+ return PDFRectangle(br_x, br_y - width, br_x + height, br_y);
|
|
+}
|
|
+
|
|
+AnnotPath * AnnotationPrivate::toAnnotPath(const QLinkedList<QPointF> &list) const
|
|
+{
|
|
+ const int count = list.size();
|
|
+ std::vector<AnnotCoord> ac;
|
|
+ ac.reserve(count);
|
|
+
|
|
+ double MTX[6];
|
|
+ fillTransformationMTX(MTX);
|
|
+
|
|
+ foreach (const QPointF &p, list)
|
|
+ {
|
|
+ double x, y;
|
|
+ XPDFReader::invTransform( MTX, p, x, y );
|
|
+ ac.emplace_back(x, y);
|
|
+ }
|
|
+
|
|
+ return new AnnotPath(std::move(ac));
|
|
+}
|
|
+
|
|
+QList<Annotation*> AnnotationPrivate::findAnnotations(::Page *pdfPage, DocumentData *doc, const QSet<Annotation::SubType> &subtypes, int parentID)
|
|
+{
|
|
+ Annots* annots = pdfPage->getAnnots();
|
|
+ const uint numAnnotations = annots->getNumAnnots();
|
|
+ if ( numAnnotations == 0 )
|
|
+ {
|
|
+ return QList<Annotation*>();
|
|
+ }
|
|
+
|
|
+ const bool wantTextAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::AText);
|
|
+ const bool wantLineAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::ALine);
|
|
+ const bool wantGeomAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::AGeom);
|
|
+ const bool wantHighlightAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::AHighlight);
|
|
+ const bool wantStampAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::AStamp);
|
|
+ const bool wantInkAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::AInk);
|
|
+ const bool wantLinkAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::ALink);
|
|
+ const bool wantCaretAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::ACaret);
|
|
+ const bool wantFileAttachmentAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::AFileAttachment);
|
|
+ const bool wantSoundAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::ASound);
|
|
+ const bool wantMovieAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::AMovie);
|
|
+ const bool wantScreenAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::AScreen);
|
|
+ const bool wantWidgetAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::AWidget);
|
|
+
|
|
+ // Create Annotation objects and tie to their native Annot
|
|
+ QList<Annotation*> res;
|
|
+ for ( uint j = 0; j < numAnnotations; j++ )
|
|
+ {
|
|
+ // get the j-th annotation
|
|
+ Annot * ann = annots->getAnnot( j );
|
|
+ if ( !ann )
|
|
+ {
|
|
+ error(errInternal, -1, "Annot {0:ud} is null", j);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ // Check parent annotation
|
|
+ AnnotMarkup * markupann = dynamic_cast< AnnotMarkup * >( ann );
|
|
+ if (!markupann)
|
|
+ {
|
|
+ // Assume it's a root annotation, and skip if user didn't request it
|
|
+ if (parentID != 0)
|
|
+ continue;
|
|
+ }
|
|
+ else if (markupann->getInReplyToID() != parentID)
|
|
+ continue;
|
|
+
|
|
+ /* Create Annotation of the right subclass */
|
|
+ Annotation * annotation = nullptr;
|
|
+ Annot::AnnotSubtype subType = ann->getType();
|
|
+
|
|
+ switch ( subType )
|
|
+ {
|
|
+ case Annot::typeText:
|
|
+ if (!wantTextAnnotations)
|
|
+ continue;
|
|
+ annotation = new TextAnnotation(TextAnnotation::Linked);
|
|
+ break;
|
|
+ case Annot::typeFreeText:
|
|
+ if (!wantTextAnnotations)
|
|
+ continue;
|
|
+ annotation = new TextAnnotation(TextAnnotation::InPlace);
|
|
+ break;
|
|
+ case Annot::typeLine:
|
|
+ if (!wantLineAnnotations)
|
|
+ continue;
|
|
+ annotation = new LineAnnotation(LineAnnotation::StraightLine);
|
|
+ break;
|
|
+ case Annot::typePolygon:
|
|
+ case Annot::typePolyLine:
|
|
+ if (!wantLineAnnotations)
|
|
+ continue;
|
|
+ annotation = new LineAnnotation(LineAnnotation::Polyline);
|
|
+ break;
|
|
+ case Annot::typeSquare:
|
|
+ case Annot::typeCircle:
|
|
+ if (!wantGeomAnnotations)
|
|
+ continue;
|
|
+ annotation = new GeomAnnotation();
|
|
+ break;
|
|
+ case Annot::typeHighlight:
|
|
+ case Annot::typeUnderline:
|
|
+ case Annot::typeSquiggly:
|
|
+ case Annot::typeStrikeOut:
|
|
+ if (!wantHighlightAnnotations)
|
|
+ continue;
|
|
+ annotation = new HighlightAnnotation();
|
|
+ break;
|
|
+ case Annot::typeStamp:
|
|
+ if (!wantStampAnnotations)
|
|
+ continue;
|
|
+ annotation = new StampAnnotation();
|
|
+ break;
|
|
+ case Annot::typeInk:
|
|
+ if (!wantInkAnnotations)
|
|
+ continue;
|
|
+ annotation = new InkAnnotation();
|
|
+ break;
|
|
+ case Annot::typeLink: /* TODO: Move logic to getters */
|
|
+ {
|
|
+ if (!wantLinkAnnotations)
|
|
+ continue;
|
|
+ // parse Link params
|
|
+ AnnotLink * linkann = static_cast< AnnotLink * >( ann );
|
|
+ LinkAnnotation * l = new LinkAnnotation();
|
|
+ annotation = l;
|
|
+
|
|
+ // -> hlMode
|
|
+ l->setLinkHighlightMode( (LinkAnnotation::HighlightMode)linkann->getLinkEffect() );
|
|
+
|
|
+ // -> link region
|
|
+ // TODO
|
|
+
|
|
+ // reading link action
|
|
+ if ( linkann->getAction() )
|
|
+ {
|
|
+ Link * popplerLink = PageData::convertLinkActionToLink( linkann->getAction(), doc, QRectF() );
|
|
+ if ( popplerLink )
|
|
+ {
|
|
+ l->setLinkDestination( popplerLink );
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ case Annot::typeCaret:
|
|
+ if (!wantCaretAnnotations)
|
|
+ continue;
|
|
+ annotation = new CaretAnnotation();
|
|
+ break;
|
|
+ case Annot::typeFileAttachment: /* TODO: Move logic to getters */
|
|
+ {
|
|
+ if (!wantFileAttachmentAnnotations)
|
|
+ continue;
|
|
+ AnnotFileAttachment * attachann = static_cast< AnnotFileAttachment * >( ann );
|
|
+ FileAttachmentAnnotation * f = new FileAttachmentAnnotation();
|
|
+ annotation = f;
|
|
+ // -> fileIcon
|
|
+ f->setFileIconName( QString::fromLatin1( attachann->getName()->c_str() ) );
|
|
+ // -> embeddedFile
|
|
+ FileSpec *filespec = new FileSpec( attachann->getFile() );
|
|
+ f->setEmbeddedFile( new EmbeddedFile( *new EmbeddedFileData( filespec ) ) );
|
|
+ break;
|
|
+ }
|
|
+ case Annot::typeSound: /* TODO: Move logic to getters */
|
|
+ {
|
|
+ if (!wantSoundAnnotations)
|
|
+ continue;
|
|
+ AnnotSound * soundann = static_cast< AnnotSound * >( ann );
|
|
+ SoundAnnotation * s = new SoundAnnotation();
|
|
+ annotation = s;
|
|
+
|
|
+ // -> soundIcon
|
|
+ s->setSoundIconName( QString::fromLatin1( soundann->getName()->c_str() ) );
|
|
+ // -> sound
|
|
+ s->setSound( new SoundObject( soundann->getSound() ) );
|
|
+ break;
|
|
+ }
|
|
+ case Annot::typeMovie: /* TODO: Move logic to getters */
|
|
+ {
|
|
+ if (!wantMovieAnnotations)
|
|
+ continue;
|
|
+ AnnotMovie * movieann = static_cast< AnnotMovie * >( ann );
|
|
+ MovieAnnotation * m = new MovieAnnotation();
|
|
+ annotation = m;
|
|
+
|
|
+ // -> movie
|
|
+ MovieObject *movie = new MovieObject( movieann );
|
|
+ m->setMovie( movie );
|
|
+ // -> movieTitle
|
|
+ const GooString * movietitle = movieann->getTitle();
|
|
+ if ( movietitle )
|
|
+ m->setMovieTitle( QString::fromLatin1( movietitle->c_str() ) );
|
|
+ break;
|
|
+ }
|
|
+ case Annot::typeScreen:
|
|
+ {
|
|
+ if (!wantScreenAnnotations)
|
|
+ continue;
|
|
+ AnnotScreen * screenann = static_cast< AnnotScreen * >( ann );
|
|
+ if (!screenann->getAction())
|
|
+ continue;
|
|
+ ScreenAnnotation * s = new ScreenAnnotation();
|
|
+ annotation = s;
|
|
+
|
|
+ // -> screen
|
|
+ Link * popplerLink = PageData::convertLinkActionToLink( screenann->getAction(), doc, QRectF() );
|
|
+ s->setAction( static_cast<Poppler::LinkRendition *>(popplerLink) );
|
|
+
|
|
+ // -> screenTitle
|
|
+ const GooString * screentitle = screenann->getTitle();
|
|
+ if ( screentitle )
|
|
+ s->setScreenTitle( UnicodeParsedString( screentitle ) );
|
|
+ break;
|
|
+ }
|
|
+ case Annot::typePopup:
|
|
+ continue; // popups are parsed by Annotation's window() getter
|
|
+ case Annot::typeUnknown:
|
|
+ continue; // special case for ignoring unknown annotations
|
|
+ case Annot::typeWidget:
|
|
+ if (!wantWidgetAnnotations)
|
|
+ continue;
|
|
+ annotation = new WidgetAnnotation();
|
|
+ break;
|
|
+ case Annot::typeRichMedia:
|
|
+ {
|
|
+ const AnnotRichMedia * annotRichMedia = static_cast< AnnotRichMedia * >( ann );
|
|
+
|
|
+ RichMediaAnnotation *richMediaAnnotation = new RichMediaAnnotation;
|
|
+
|
|
+ const AnnotRichMedia::Settings *annotSettings = annotRichMedia->getSettings();
|
|
+ if ( annotSettings ) {
|
|
+ RichMediaAnnotation::Settings *settings = new RichMediaAnnotation::Settings;
|
|
+
|
|
+ if ( annotSettings->getActivation() ) {
|
|
+ RichMediaAnnotation::Activation *activation = new RichMediaAnnotation::Activation;
|
|
+
|
|
+ switch ( annotSettings->getActivation()->getCondition() )
|
|
+ {
|
|
+ case AnnotRichMedia::Activation::conditionPageOpened:
|
|
+ activation->setCondition( RichMediaAnnotation::Activation::PageOpened );
|
|
+ break;
|
|
+ case AnnotRichMedia::Activation::conditionPageVisible:
|
|
+ activation->setCondition( RichMediaAnnotation::Activation::PageVisible );
|
|
+ break;
|
|
+ case AnnotRichMedia::Activation::conditionUserAction:
|
|
+ activation->setCondition( RichMediaAnnotation::Activation::UserAction );
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ settings->setActivation( activation );
|
|
+ }
|
|
+
|
|
+ if ( annotSettings->getDeactivation() ) {
|
|
+ RichMediaAnnotation::Deactivation *deactivation = new RichMediaAnnotation::Deactivation;
|
|
+
|
|
+ switch ( annotSettings->getDeactivation()->getCondition() )
|
|
+ {
|
|
+ case AnnotRichMedia::Deactivation::conditionPageClosed:
|
|
+ deactivation->setCondition( RichMediaAnnotation::Deactivation::PageClosed );
|
|
+ break;
|
|
+ case AnnotRichMedia::Deactivation::conditionPageInvisible:
|
|
+ deactivation->setCondition( RichMediaAnnotation::Deactivation::PageInvisible );
|
|
+ break;
|
|
+ case AnnotRichMedia::Deactivation::conditionUserAction:
|
|
+ deactivation->setCondition( RichMediaAnnotation::Deactivation::UserAction );
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ settings->setDeactivation( deactivation );
|
|
+ }
|
|
+
|
|
+ richMediaAnnotation->setSettings( settings );
|
|
+ }
|
|
+
|
|
+ const AnnotRichMedia::Content *annotContent = annotRichMedia->getContent();
|
|
+ if ( annotContent ) {
|
|
+ RichMediaAnnotation::Content *content = new RichMediaAnnotation::Content;
|
|
+
|
|
+ const int configurationsCount = annotContent->getConfigurationsCount();
|
|
+ if ( configurationsCount > 0 ) {
|
|
+ QList< RichMediaAnnotation::Configuration* > configurations;
|
|
+
|
|
+ for ( int i = 0; i < configurationsCount; ++i ) {
|
|
+ const AnnotRichMedia::Configuration *annotConfiguration = annotContent->getConfiguration( i );
|
|
+ if ( !annotConfiguration )
|
|
+ continue;
|
|
+
|
|
+ RichMediaAnnotation::Configuration *configuration = new RichMediaAnnotation::Configuration;
|
|
+
|
|
+ if ( annotConfiguration->getName() )
|
|
+ configuration->setName( UnicodeParsedString( annotConfiguration->getName() ) );
|
|
+
|
|
+ switch ( annotConfiguration->getType() )
|
|
+ {
|
|
+ case AnnotRichMedia::Configuration::type3D:
|
|
+ configuration->setType( RichMediaAnnotation::Configuration::Type3D );
|
|
+ break;
|
|
+ case AnnotRichMedia::Configuration::typeFlash:
|
|
+ configuration->setType( RichMediaAnnotation::Configuration::TypeFlash );
|
|
+ break;
|
|
+ case AnnotRichMedia::Configuration::typeSound:
|
|
+ configuration->setType( RichMediaAnnotation::Configuration::TypeSound );
|
|
+ break;
|
|
+ case AnnotRichMedia::Configuration::typeVideo:
|
|
+ configuration->setType( RichMediaAnnotation::Configuration::TypeVideo );
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ const int instancesCount = annotConfiguration->getInstancesCount();
|
|
+ if ( instancesCount > 0 ) {
|
|
+ QList< RichMediaAnnotation::Instance* > instances;
|
|
+
|
|
+ for ( int j = 0; j < instancesCount; ++j ) {
|
|
+ const AnnotRichMedia::Instance *annotInstance = annotConfiguration->getInstance( j );
|
|
+ if ( !annotInstance )
|
|
+ continue;
|
|
+
|
|
+ RichMediaAnnotation::Instance *instance = new RichMediaAnnotation::Instance;
|
|
+
|
|
+ switch ( annotInstance->getType() )
|
|
+ {
|
|
+ case AnnotRichMedia::Instance::type3D:
|
|
+ instance->setType( RichMediaAnnotation::Instance::Type3D );
|
|
+ break;
|
|
+ case AnnotRichMedia::Instance::typeFlash:
|
|
+ instance->setType( RichMediaAnnotation::Instance::TypeFlash );
|
|
+ break;
|
|
+ case AnnotRichMedia::Instance::typeSound:
|
|
+ instance->setType( RichMediaAnnotation::Instance::TypeSound );
|
|
+ break;
|
|
+ case AnnotRichMedia::Instance::typeVideo:
|
|
+ instance->setType( RichMediaAnnotation::Instance::TypeVideo );
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ const AnnotRichMedia::Params *annotParams = annotInstance->getParams();
|
|
+ if ( annotParams ) {
|
|
+ RichMediaAnnotation::Params *params = new RichMediaAnnotation::Params;
|
|
+
|
|
+ if ( annotParams->getFlashVars() )
|
|
+ params->setFlashVars( UnicodeParsedString( annotParams->getFlashVars() ) );
|
|
+
|
|
+ instance->setParams( params );
|
|
+ }
|
|
+
|
|
+ instances.append( instance );
|
|
+ }
|
|
+
|
|
+ configuration->setInstances( instances );
|
|
+ }
|
|
+
|
|
+ configurations.append( configuration );
|
|
+ }
|
|
+
|
|
+ content->setConfigurations( configurations );
|
|
+ }
|
|
+
|
|
+ const int assetsCount = annotContent->getAssetsCount();
|
|
+ if ( assetsCount > 0 ) {
|
|
+ QList< RichMediaAnnotation::Asset* > assets;
|
|
+
|
|
+ for ( int i = 0; i < assetsCount; ++i ) {
|
|
+ const AnnotRichMedia::Asset *annotAsset = annotContent->getAsset( i );
|
|
+ if ( !annotAsset )
|
|
+ continue;
|
|
+
|
|
+ RichMediaAnnotation::Asset *asset = new RichMediaAnnotation::Asset;
|
|
+
|
|
+ if ( annotAsset->getName() )
|
|
+ asset->setName( UnicodeParsedString( annotAsset->getName() ) );
|
|
+
|
|
+ FileSpec *fileSpec = new FileSpec( annotAsset->getFileSpec() );
|
|
+ asset->setEmbeddedFile( new EmbeddedFile( *new EmbeddedFileData( fileSpec ) ) );
|
|
+
|
|
+ assets.append( asset );
|
|
+ }
|
|
+
|
|
+ content->setAssets( assets );
|
|
+ }
|
|
+
|
|
+ richMediaAnnotation->setContent( content );
|
|
+ }
|
|
+
|
|
+ annotation = richMediaAnnotation;
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ default:
|
|
+ {
|
|
+#define CASE_FOR_TYPE( thetype ) \
|
|
+ case Annot::type ## thetype: \
|
|
+ error(errUnimplemented, -1, "Annotation " #thetype " not supported"); \
|
|
+ break;
|
|
+ switch ( subType )
|
|
+ {
|
|
+ CASE_FOR_TYPE( PrinterMark )
|
|
+ CASE_FOR_TYPE( TrapNet )
|
|
+ CASE_FOR_TYPE( Watermark )
|
|
+ CASE_FOR_TYPE( 3D )
|
|
+ default: error(errUnimplemented, -1, "Annotation {0:d} not supported", subType);
|
|
+ }
|
|
+ continue;
|
|
+#undef CASE_FOR_TYPE
|
|
+ }
|
|
+ }
|
|
+
|
|
+ annotation->d_ptr->tieToNativeAnnot(ann, pdfPage, doc);
|
|
+ res.append(annotation);
|
|
+ }
|
|
+
|
|
+ return res;
|
|
+}
|
|
+
|
|
+Ref AnnotationPrivate::pdfObjectReference() const
|
|
+{
|
|
+ if (pdfAnnot == nullptr)
|
|
+ {
|
|
+ const Ref invalid_ref = { -1, -1 };
|
|
+ return invalid_ref;
|
|
+ }
|
|
+
|
|
+ return pdfAnnot->getRef();
|
|
+}
|
|
+
|
|
+Link* AnnotationPrivate::additionalAction( Annotation::AdditionalActionType type ) const
|
|
+{
|
|
+ if ( pdfAnnot->getType() != Annot::typeScreen && pdfAnnot->getType() != Annot::typeWidget )
|
|
+ return nullptr;
|
|
+
|
|
+ Annot::AdditionalActionsType actionType = Annot::actionCursorEntering;
|
|
+ switch ( type )
|
|
+ {
|
|
+ case Annotation::CursorEnteringAction: actionType = Annot::actionCursorEntering; break;
|
|
+ case Annotation::CursorLeavingAction: actionType = Annot::actionCursorLeaving; break;
|
|
+ case Annotation::MousePressedAction: actionType = Annot::actionMousePressed; break;
|
|
+ case Annotation::MouseReleasedAction: actionType = Annot::actionMouseReleased; break;
|
|
+ case Annotation::FocusInAction: actionType = Annot::actionFocusIn; break;
|
|
+ case Annotation::FocusOutAction: actionType = Annot::actionFocusOut; break;
|
|
+ case Annotation::PageOpeningAction: actionType = Annot::actionPageOpening; break;
|
|
+ case Annotation::PageClosingAction: actionType = Annot::actionPageClosing; break;
|
|
+ case Annotation::PageVisibleAction: actionType = Annot::actionPageVisible; break;
|
|
+ case Annotation::PageInvisibleAction: actionType = Annot::actionPageInvisible; break;
|
|
+ }
|
|
+
|
|
+ ::LinkAction *linkAction = nullptr;
|
|
+ if ( pdfAnnot->getType() == Annot::typeScreen )
|
|
+ linkAction = static_cast<AnnotScreen*>( pdfAnnot )->getAdditionalAction( actionType );
|
|
+ else
|
|
+ linkAction = static_cast<AnnotWidget*>( pdfAnnot )->getAdditionalAction( actionType );
|
|
+
|
|
+ Link *link = nullptr;
|
|
+
|
|
+ if ( linkAction )
|
|
+ link = PageData::convertLinkActionToLink( linkAction, parentDoc, QRectF() );
|
|
+
|
|
+ return link;
|
|
+}
|
|
+
|
|
+void AnnotationPrivate::addAnnotationToPage(::Page *pdfPage, DocumentData *doc, const Annotation * ann)
|
|
+{
|
|
+ if (ann->d_ptr->pdfAnnot != nullptr)
|
|
+ {
|
|
+ error(errIO, -1, "Annotation is already tied");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Unimplemented annotations can't be created by the user because their ctor
|
|
+ // is private. Therefore, createNativeAnnot will never return 0
|
|
+ Annot *nativeAnnot = ann->d_ptr->createNativeAnnot(pdfPage, doc);
|
|
+ Q_ASSERT(nativeAnnot);
|
|
+ pdfPage->addAnnot(nativeAnnot);
|
|
+}
|
|
+
|
|
+void AnnotationPrivate::removeAnnotationFromPage(::Page *pdfPage, const Annotation * ann)
|
|
+{
|
|
+ if (ann->d_ptr->pdfAnnot == nullptr)
|
|
+ {
|
|
+ error(errIO, -1, "Annotation is not tied");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (ann->d_ptr->pdfPage != pdfPage)
|
|
+ {
|
|
+ error(errIO, -1, "Annotation doesn't belong to the specified page");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Remove annotation
|
|
+ pdfPage->removeAnnot(ann->d_ptr->pdfAnnot);
|
|
+
|
|
+ // Destroy object
|
|
+ delete ann;
|
|
+}
|
|
+
|
|
+class Annotation::Style::Private : public QSharedData
|
|
+{
|
|
+ public:
|
|
+ Private()
|
|
+ : opacity( 1.0 ), width( 1.0 ), lineStyle( Solid ), xCorners( 0.0 ),
|
|
+ yCorners( 0.0 ), lineEffect( NoEffect ), effectIntensity( 1.0 )
|
|
+ {
|
|
+ dashArray.resize(1);
|
|
+ dashArray[0] = 3;
|
|
+ }
|
|
+
|
|
+ QColor color;
|
|
+ double opacity;
|
|
+ double width;
|
|
+ Annotation::LineStyle lineStyle;
|
|
+ double xCorners;
|
|
+ double yCorners;
|
|
+ QVector<double> dashArray;
|
|
+ Annotation::LineEffect lineEffect;
|
|
+ double effectIntensity;
|
|
+};
|
|
+
|
|
+Annotation::Style::Style()
|
|
+ : d ( new Private )
|
|
+{
|
|
+}
|
|
+
|
|
+Annotation::Style::Style( const Style &other )
|
|
+ : d( other.d )
|
|
+{
|
|
+}
|
|
+
|
|
+Annotation::Style& Annotation::Style::operator=( const Style &other )
|
|
+{
|
|
+ if ( this != &other )
|
|
+ d = other.d;
|
|
+
|
|
+ return *this;
|
|
+}
|
|
+
|
|
+Annotation::Style::~Style()
|
|
+{
|
|
+}
|
|
+
|
|
+QColor Annotation::Style::color() const
|
|
+{
|
|
+ return d->color;
|
|
+}
|
|
+
|
|
+void Annotation::Style::setColor(const QColor &color)
|
|
+{
|
|
+ d->color = color;
|
|
+}
|
|
+
|
|
+double Annotation::Style::opacity() const
|
|
+{
|
|
+ return d->opacity;
|
|
+}
|
|
+
|
|
+void Annotation::Style::setOpacity(double opacity)
|
|
+{
|
|
+ d->opacity = opacity;
|
|
+}
|
|
+
|
|
+double Annotation::Style::width() const
|
|
+{
|
|
+ return d->width;
|
|
+}
|
|
+
|
|
+void Annotation::Style::setWidth(double width)
|
|
+{
|
|
+ d->width = width;
|
|
+}
|
|
+
|
|
+Annotation::LineStyle Annotation::Style::lineStyle() const
|
|
+{
|
|
+ return d->lineStyle;
|
|
+}
|
|
+
|
|
+void Annotation::Style::setLineStyle(Annotation::LineStyle style)
|
|
+{
|
|
+ d->lineStyle = style;
|
|
+}
|
|
+
|
|
+double Annotation::Style::xCorners() const
|
|
+{
|
|
+ return d->xCorners;
|
|
+}
|
|
+
|
|
+void Annotation::Style::setXCorners(double radius)
|
|
+{
|
|
+ d->xCorners = radius;
|
|
+}
|
|
+
|
|
+double Annotation::Style::yCorners() const
|
|
+{
|
|
+ return d->yCorners;
|
|
+}
|
|
+
|
|
+void Annotation::Style::setYCorners(double radius)
|
|
+{
|
|
+ d->yCorners = radius;
|
|
+}
|
|
+
|
|
+const QVector<double>& Annotation::Style::dashArray() const
|
|
+{
|
|
+ return d->dashArray;
|
|
+}
|
|
+
|
|
+void Annotation::Style::setDashArray(const QVector<double> &array)
|
|
+{
|
|
+ d->dashArray = array;
|
|
+}
|
|
+
|
|
+Annotation::LineEffect Annotation::Style::lineEffect() const
|
|
+{
|
|
+ return d->lineEffect;
|
|
+}
|
|
+
|
|
+void Annotation::Style::setLineEffect(Annotation::LineEffect effect)
|
|
+{
|
|
+ d->lineEffect = effect;
|
|
+}
|
|
+
|
|
+double Annotation::Style::effectIntensity() const
|
|
+{
|
|
+ return d->effectIntensity;
|
|
+}
|
|
+
|
|
+void Annotation::Style::setEffectIntensity(double intens)
|
|
+{
|
|
+ d->effectIntensity = intens;
|
|
+}
|
|
+
|
|
+class Annotation::Popup::Private : public QSharedData
|
|
+{
|
|
+ public:
|
|
+ Private()
|
|
+ : flags( -1 ) {}
|
|
+
|
|
+ int flags;
|
|
+ QRectF geometry;
|
|
+ QString title;
|
|
+ QString summary;
|
|
+ QString text;
|
|
+};
|
|
+
|
|
+Annotation::Popup::Popup()
|
|
+ : d ( new Private )
|
|
+{
|
|
+}
|
|
+
|
|
+Annotation::Popup::Popup( const Popup &other )
|
|
+ : d( other.d )
|
|
+{
|
|
+}
|
|
+
|
|
+Annotation::Popup& Annotation::Popup::operator=( const Popup &other )
|
|
+{
|
|
+ if ( this != &other )
|
|
+ d = other.d;
|
|
+
|
|
+ return *this;
|
|
+}
|
|
+
|
|
+Annotation::Popup::~Popup()
|
|
+{
|
|
+}
|
|
+
|
|
+int Annotation::Popup::flags() const
|
|
+{
|
|
+ return d->flags;
|
|
+}
|
|
+
|
|
+void Annotation::Popup::setFlags( int flags )
|
|
+{
|
|
+ d->flags = flags;
|
|
+}
|
|
+
|
|
+QRectF Annotation::Popup::geometry() const
|
|
+{
|
|
+ return d->geometry;
|
|
+}
|
|
+
|
|
+void Annotation::Popup::setGeometry( const QRectF &geom )
|
|
+{
|
|
+ d->geometry = geom;
|
|
+}
|
|
+
|
|
+QString Annotation::Popup::title() const
|
|
+{
|
|
+ return d->title;
|
|
+}
|
|
+
|
|
+void Annotation::Popup::setTitle( const QString &title )
|
|
+{
|
|
+ d->title = title;
|
|
+}
|
|
+
|
|
+QString Annotation::Popup::summary() const
|
|
+{
|
|
+ return d->summary;
|
|
+}
|
|
+
|
|
+void Annotation::Popup::setSummary( const QString &summary )
|
|
+{
|
|
+ d->summary = summary;
|
|
+}
|
|
+
|
|
+QString Annotation::Popup::text() const
|
|
+{
|
|
+ return d->text;
|
|
+}
|
|
+
|
|
+void Annotation::Popup::setText( const QString &text )
|
|
+{
|
|
+ d->text = text;
|
|
+}
|
|
+
|
|
+Annotation::Annotation( AnnotationPrivate &dd )
|
|
+ : d_ptr( &dd )
|
|
+{
|
|
+ window.width = window.height = 0;
|
|
+}
|
|
+
|
|
+Annotation::~Annotation()
|
|
+{
|
|
+}
|
|
+
|
|
+Annotation::Annotation( AnnotationPrivate &dd, const QDomNode &annNode )
|
|
+ : d_ptr( &dd )
|
|
+{
|
|
+ Q_D( Annotation );
|
|
+
|
|
+ window.width = window.height = 0;
|
|
+
|
|
+ // get the [base] element of the annotation node
|
|
+ QDomElement e = AnnotationUtils::findChildElement( annNode, "base" );
|
|
+ if ( e.isNull() )
|
|
+ return;
|
|
+
|
|
+ Style s;
|
|
+ Popup w;
|
|
+
|
|
+ // parse -contents- attributes
|
|
+ if ( e.hasAttribute( "author" ) )
|
|
+ setAuthor(e.attribute( "author" ));
|
|
+ if ( e.hasAttribute( "contents" ) )
|
|
+ setContents(e.attribute( "contents" ));
|
|
+ if ( e.hasAttribute( "uniqueName" ) )
|
|
+ setUniqueName(e.attribute( "uniqueName" ));
|
|
+ if ( e.hasAttribute( "modifyDate" ) )
|
|
+ setModificationDate(QDateTime::fromString( e.attribute( "modifyDate" ) ));
|
|
+ if ( e.hasAttribute( "creationDate" ) )
|
|
+ setCreationDate(QDateTime::fromString( e.attribute( "creationDate" ) ));
|
|
+
|
|
+ // parse -other- attributes
|
|
+ if ( e.hasAttribute( "flags" ) )
|
|
+ setFlags(e.attribute( "flags" ).toInt());
|
|
+ if ( e.hasAttribute( "color" ) )
|
|
+ s.setColor(QColor( e.attribute( "color" ) ));
|
|
+ if ( e.hasAttribute( "opacity" ) )
|
|
+ s.setOpacity(e.attribute( "opacity" ).toDouble());
|
|
+
|
|
+ // parse -the-subnodes- (describing Style, Window, Revision(s) structures)
|
|
+ // Note: all subnodes if present must be 'attributes complete'
|
|
+ QDomNode eSubNode = e.firstChild();
|
|
+ while ( eSubNode.isElement() )
|
|
+ {
|
|
+ QDomElement ee = eSubNode.toElement();
|
|
+ eSubNode = eSubNode.nextSibling();
|
|
+
|
|
+ // parse boundary
|
|
+ if ( ee.tagName() == "boundary" )
|
|
+ {
|
|
+ QRectF brect;
|
|
+ brect.setLeft(ee.attribute( "l" ).toDouble());
|
|
+ brect.setTop(ee.attribute( "t" ).toDouble());
|
|
+ brect.setRight(ee.attribute( "r" ).toDouble());
|
|
+ brect.setBottom(ee.attribute( "b" ).toDouble());
|
|
+ setBoundary(brect);
|
|
+ }
|
|
+ // parse penStyle if not default
|
|
+ else if ( ee.tagName() == "penStyle" )
|
|
+ {
|
|
+ s.setWidth(ee.attribute( "width" ).toDouble());
|
|
+ s.setLineStyle((LineStyle)ee.attribute( "style" ).toInt());
|
|
+ s.setXCorners(ee.attribute( "xcr" ).toDouble());
|
|
+ s.setYCorners(ee.attribute( "ycr" ).toDouble());
|
|
+
|
|
+ // Try to parse dash array (new format)
|
|
+ QVector<double> dashArray;
|
|
+
|
|
+ QDomNode eeSubNode = ee.firstChild();
|
|
+ while ( eeSubNode.isElement() )
|
|
+ {
|
|
+ QDomElement eee = eeSubNode.toElement();
|
|
+ eeSubNode = eeSubNode.nextSibling();
|
|
+
|
|
+ if ( eee.tagName() != "dashsegm" )
|
|
+ continue;
|
|
+
|
|
+ dashArray.append(eee.attribute( "len" ).toDouble());
|
|
+ }
|
|
+
|
|
+ // If no segments were found use marks/spaces (old format)
|
|
+ if ( dashArray.size() == 0 )
|
|
+ {
|
|
+ dashArray.append(ee.attribute( "marks" ).toDouble());
|
|
+ dashArray.append(ee.attribute( "spaces" ).toDouble());
|
|
+ }
|
|
+
|
|
+ s.setDashArray(dashArray);
|
|
+ }
|
|
+ // parse effectStyle if not default
|
|
+ else if ( ee.tagName() == "penEffect" )
|
|
+ {
|
|
+ s.setLineEffect((LineEffect)ee.attribute( "effect" ).toInt());
|
|
+ s.setEffectIntensity(ee.attribute( "intensity" ).toDouble());
|
|
+ }
|
|
+ // parse window if present
|
|
+ else if ( ee.tagName() == "window" )
|
|
+ {
|
|
+ QRectF geom;
|
|
+ geom.setX(ee.attribute( "top" ).toDouble());
|
|
+ geom.setY(ee.attribute( "left" ).toDouble());
|
|
+
|
|
+ if (ee.hasAttribute("widthDouble"))
|
|
+ geom.setWidth(ee.attribute( "widthDouble" ).toDouble());
|
|
+ else
|
|
+ geom.setWidth(ee.attribute( "width" ).toDouble());
|
|
+
|
|
+ if (ee.hasAttribute("widthDouble"))
|
|
+ geom.setHeight(ee.attribute( "heightDouble" ).toDouble());
|
|
+ else
|
|
+ geom.setHeight(ee.attribute( "height" ).toDouble());
|
|
+
|
|
+ w.setGeometry(geom);
|
|
+
|
|
+ w.setFlags(ee.attribute( "flags" ).toInt());
|
|
+ w.setTitle(ee.attribute( "title" ));
|
|
+ w.setSummary(ee.attribute( "summary" ));
|
|
+ // parse window subnodes
|
|
+ QDomNode winNode = ee.firstChild();
|
|
+ for ( ; winNode.isElement(); winNode = winNode.nextSibling() )
|
|
+ {
|
|
+ QDomElement winElement = winNode.toElement();
|
|
+ if ( winElement.tagName() == "text" )
|
|
+ w.setText(winElement.firstChild().toCDATASection().data());
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ setStyle(s); // assign parsed style
|
|
+ setPopup(w); // assign parsed window
|
|
+
|
|
+ // get the [revisions] element of the annotation node
|
|
+ QDomNode revNode = annNode.firstChild();
|
|
+ for ( ; revNode.isElement(); revNode = revNode.nextSibling() )
|
|
+ {
|
|
+ QDomElement revElement = revNode.toElement();
|
|
+ if ( revElement.tagName() != "revision" )
|
|
+ continue;
|
|
+
|
|
+ Annotation *reply = AnnotationUtils::createAnnotation( revElement );
|
|
+
|
|
+ if (reply) // if annotation is valid, add as a revision of this annotation
|
|
+ {
|
|
+ RevScope scope = (RevScope)revElement.attribute( "revScope" ).toInt();
|
|
+ RevType type = (RevType)revElement.attribute( "revType" ).toInt();
|
|
+ d->addRevision(reply, scope, type);
|
|
+ delete reply;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void Annotation::storeBaseAnnotationProperties( QDomNode & annNode, QDomDocument & document ) const
|
|
+{
|
|
+ // create [base] element of the annotation node
|
|
+ QDomElement e = document.createElement( "base" );
|
|
+ annNode.appendChild( e );
|
|
+
|
|
+ const Style s = style();
|
|
+ const Popup w = popup();
|
|
+
|
|
+ // store -contents- attributes
|
|
+ if ( !author().isEmpty() )
|
|
+ e.setAttribute( "author", author() );
|
|
+ if ( !contents().isEmpty() )
|
|
+ e.setAttribute( "contents", contents() );
|
|
+ if ( !uniqueName().isEmpty() )
|
|
+ e.setAttribute( "uniqueName", uniqueName() );
|
|
+ if ( modificationDate().isValid() )
|
|
+ e.setAttribute( "modifyDate", modificationDate().toString() );
|
|
+ if ( creationDate().isValid() )
|
|
+ e.setAttribute( "creationDate", creationDate().toString() );
|
|
+
|
|
+ // store -other- attributes
|
|
+ if ( flags() )
|
|
+ e.setAttribute( "flags", flags() );
|
|
+ if ( s.color().isValid() )
|
|
+ e.setAttribute( "color", s.color().name() );
|
|
+ if ( s.opacity() != 1.0 )
|
|
+ e.setAttribute( "opacity", QString::number( s.opacity() ) );
|
|
+
|
|
+ // Sub-Node-1 - boundary
|
|
+ const QRectF brect = boundary();
|
|
+ QDomElement bE = document.createElement( "boundary" );
|
|
+ e.appendChild( bE );
|
|
+ bE.setAttribute( "l", QString::number( (double)brect.left() ) );
|
|
+ bE.setAttribute( "t", QString::number( (double)brect.top() ) );
|
|
+ bE.setAttribute( "r", QString::number( (double)brect.right() ) );
|
|
+ bE.setAttribute( "b", QString::number( (double)brect.bottom() ) );
|
|
+
|
|
+ // Sub-Node-2 - penStyle
|
|
+ const QVector<double> dashArray = s.dashArray();
|
|
+ if ( s.width() != 1 || s.lineStyle() != Solid || s.xCorners() != 0 ||
|
|
+ s.yCorners() != 0.0 || dashArray.size() != 1 || dashArray[0] != 3 )
|
|
+ {
|
|
+ QDomElement psE = document.createElement( "penStyle" );
|
|
+ e.appendChild( psE );
|
|
+ psE.setAttribute( "width", QString::number( s.width() ) );
|
|
+ psE.setAttribute( "style", (int)s.lineStyle() );
|
|
+ psE.setAttribute( "xcr", QString::number( s.xCorners() ) );
|
|
+ psE.setAttribute( "ycr", QString::number( s.yCorners() ) );
|
|
+
|
|
+ int marks = 3, spaces = 0; // Do not break code relying on marks/spaces
|
|
+ if (dashArray.size() != 0)
|
|
+ marks = (int)dashArray[0];
|
|
+ if (dashArray.size() > 1)
|
|
+ spaces = (int)dashArray[1];
|
|
+
|
|
+ psE.setAttribute( "marks", marks );
|
|
+ psE.setAttribute( "spaces", spaces );
|
|
+
|
|
+ foreach (double segm, dashArray)
|
|
+ {
|
|
+ QDomElement pattE = document.createElement( "dashsegm" );
|
|
+ pattE.setAttribute( "len", QString::number( segm ) );
|
|
+ psE.appendChild(pattE);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Sub-Node-3 - penEffect
|
|
+ if ( s.lineEffect() != NoEffect || s.effectIntensity() != 1.0 )
|
|
+ {
|
|
+ QDomElement peE = document.createElement( "penEffect" );
|
|
+ e.appendChild( peE );
|
|
+ peE.setAttribute( "effect", (int)s.lineEffect() );
|
|
+ peE.setAttribute( "intensity", QString::number( s.effectIntensity() ) );
|
|
+ }
|
|
+
|
|
+ // Sub-Node-4 - window
|
|
+ if ( w.flags() != -1 || !w.title().isEmpty() || !w.summary().isEmpty() ||
|
|
+ !w.text().isEmpty() )
|
|
+ {
|
|
+ QDomElement wE = document.createElement( "window" );
|
|
+ const QRectF geom = w.geometry();
|
|
+ e.appendChild( wE );
|
|
+ wE.setAttribute( "flags", w.flags() );
|
|
+ wE.setAttribute( "top", QString::number( geom.x() ) );
|
|
+ wE.setAttribute( "left", QString::number( geom.y() ) );
|
|
+ wE.setAttribute( "width", (int)geom.width() );
|
|
+ wE.setAttribute( "height", (int)geom.height() );
|
|
+ wE.setAttribute( "widthDouble", QString::number( geom.width() ) );
|
|
+ wE.setAttribute( "heightDouble", QString::number( geom.height() ) );
|
|
+ wE.setAttribute( "title", w.title() );
|
|
+ wE.setAttribute( "summary", w.summary() );
|
|
+ // store window.text as a subnode, because we need escaped data
|
|
+ if ( !w.text().isEmpty() )
|
|
+ {
|
|
+ QDomElement escapedText = document.createElement( "text" );
|
|
+ wE.appendChild( escapedText );
|
|
+ QDomCDATASection textCData = document.createCDATASection( w.text() );
|
|
+ escapedText.appendChild( textCData );
|
|
+ }
|
|
+ }
|
|
+
|
|
+ const QList<Annotation*> revs = revisions();
|
|
+
|
|
+ // create [revision] element of the annotation node (if any)
|
|
+ if ( revs.isEmpty() )
|
|
+ return;
|
|
+
|
|
+ // add all revisions as children of revisions element
|
|
+ foreach (const Annotation *rev, revs)
|
|
+ {
|
|
+ QDomElement r = document.createElement( "revision" );
|
|
+ annNode.appendChild( r );
|
|
+ // set element attributes
|
|
+ r.setAttribute( "revScope", (int)rev->revisionScope() );
|
|
+ r.setAttribute( "revType", (int)rev->revisionType() );
|
|
+ // use revision as the annotation element, so fill it up
|
|
+ AnnotationUtils::storeAnnotation( rev, r, document );
|
|
+ delete rev;
|
|
+ }
|
|
+}
|
|
+
|
|
+QString Annotation::author() const
|
|
+{
|
|
+ Q_D( const Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->author;
|
|
+
|
|
+ const AnnotMarkup *markupann = dynamic_cast<const AnnotMarkup*>(d->pdfAnnot);
|
|
+ return markupann ? UnicodeParsedString( markupann->getLabel() ) : QString();
|
|
+}
|
|
+
|
|
+void Annotation::setAuthor( const QString &author )
|
|
+{
|
|
+ Q_D( Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->author = author;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ AnnotMarkup *markupann = dynamic_cast<AnnotMarkup*>(d->pdfAnnot);
|
|
+ if (markupann)
|
|
+ {
|
|
+ GooString *s = QStringToUnicodeGooString(author);
|
|
+ markupann->setLabel(s);
|
|
+ delete s;
|
|
+ }
|
|
+}
|
|
+
|
|
+QString Annotation::contents() const
|
|
+{
|
|
+ Q_D( const Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->contents;
|
|
+
|
|
+ return UnicodeParsedString( d->pdfAnnot->getContents() );
|
|
+}
|
|
+
|
|
+void Annotation::setContents( const QString &contents )
|
|
+{
|
|
+ Q_D( Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->contents = contents;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ GooString *s = QStringToUnicodeGooString(contents);
|
|
+ d->pdfAnnot->setContents(s);
|
|
+ delete s;
|
|
+}
|
|
+
|
|
+QString Annotation::uniqueName() const
|
|
+{
|
|
+ Q_D( const Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->uniqueName;
|
|
+
|
|
+ return UnicodeParsedString( d->pdfAnnot->getName() );
|
|
+}
|
|
+
|
|
+void Annotation::setUniqueName( const QString &uniqueName )
|
|
+{
|
|
+ Q_D( Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->uniqueName = uniqueName;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ QByteArray ascii = uniqueName.toAscii();
|
|
+ GooString s(ascii.constData());
|
|
+ d->pdfAnnot->setName(&s);
|
|
+}
|
|
+
|
|
+QDateTime Annotation::modificationDate() const
|
|
+{
|
|
+ Q_D( const Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->modDate;
|
|
+
|
|
+ if ( d->pdfAnnot->getModified() )
|
|
+ return convertDate( d->pdfAnnot->getModified()->c_str() );
|
|
+ else
|
|
+ return QDateTime();
|
|
+}
|
|
+
|
|
+void Annotation::setModificationDate( const QDateTime &date )
|
|
+{
|
|
+ Q_D( Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->modDate = date;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+#if 0 // TODO: Conversion routine is broken
|
|
+ if (d->pdfAnnot)
|
|
+ {
|
|
+ time_t t = date.toTime_t();
|
|
+ GooString *s = timeToDateString(&t);
|
|
+ d->pdfAnnot->setModified(s);
|
|
+ delete s;
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+
|
|
+QDateTime Annotation::creationDate() const
|
|
+{
|
|
+ Q_D( const Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->creationDate;
|
|
+
|
|
+ const AnnotMarkup *markupann = dynamic_cast<const AnnotMarkup*>(d->pdfAnnot);
|
|
+
|
|
+ if (markupann && markupann->getDate())
|
|
+ return convertDate( markupann->getDate()->c_str() );
|
|
+
|
|
+ return modificationDate();
|
|
+}
|
|
+
|
|
+void Annotation::setCreationDate( const QDateTime &date )
|
|
+{
|
|
+ Q_D( Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->creationDate = date;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+#if 0 // TODO: Conversion routine is broken
|
|
+ AnnotMarkup *markupann = dynamic_cast<AnnotMarkup*>(d->pdfAnnot);
|
|
+ if (markupann)
|
|
+ {
|
|
+ time_t t = date.toTime_t();
|
|
+ GooString *s = timeToDateString(&t);
|
|
+ markupann->setDate(s);
|
|
+ delete s;
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+
|
|
+static int fromPdfFlags(int flags)
|
|
+{
|
|
+ int qtflags = 0;
|
|
+
|
|
+ if ( flags & Annot::flagHidden )
|
|
+ qtflags |= Annotation::Hidden;
|
|
+ if ( flags & Annot::flagNoZoom )
|
|
+ qtflags |= Annotation::FixedSize;
|
|
+ if ( flags & Annot::flagNoRotate )
|
|
+ qtflags |= Annotation::FixedRotation;
|
|
+ if ( !( flags & Annot::flagPrint ) )
|
|
+ qtflags |= Annotation::DenyPrint;
|
|
+ if ( flags & Annot::flagReadOnly )
|
|
+ qtflags |= (Annotation::DenyWrite | Annotation::DenyDelete);
|
|
+ if ( flags & Annot::flagLocked )
|
|
+ qtflags |= Annotation::DenyDelete;
|
|
+ if ( flags & Annot::flagToggleNoView )
|
|
+ qtflags |= Annotation::ToggleHidingOnMouse;
|
|
+
|
|
+ return qtflags;
|
|
+}
|
|
+
|
|
+static int toPdfFlags(int qtflags)
|
|
+{
|
|
+ int flags = 0;
|
|
+
|
|
+ if ( qtflags & Annotation::Hidden )
|
|
+ flags |= Annot::flagHidden;
|
|
+ if ( qtflags & Annotation::FixedSize )
|
|
+ flags |= Annot::flagNoZoom;
|
|
+ if ( qtflags & Annotation::FixedRotation )
|
|
+ flags |= Annot::flagNoRotate;
|
|
+ if ( !( qtflags & Annotation::DenyPrint ) )
|
|
+ flags |= Annot::flagPrint;
|
|
+ if ( qtflags & Annotation::DenyWrite )
|
|
+ flags |= Annot::flagReadOnly;
|
|
+ if ( qtflags & Annotation::DenyDelete )
|
|
+ flags |= Annot::flagLocked;
|
|
+ if ( qtflags & Annotation::ToggleHidingOnMouse )
|
|
+ flags |= Annot::flagToggleNoView;
|
|
+
|
|
+ return flags;
|
|
+}
|
|
+
|
|
+int Annotation::flags() const
|
|
+{
|
|
+ Q_D( const Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->flags;
|
|
+
|
|
+ return fromPdfFlags( d->pdfAnnot->getFlags() );
|
|
+}
|
|
+
|
|
+void Annotation::setFlags( int flags )
|
|
+{
|
|
+ Q_D( Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->flags = flags;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ d->pdfAnnot->setFlags(toPdfFlags( flags ));
|
|
+}
|
|
+
|
|
+QRectF Annotation::boundary() const
|
|
+{
|
|
+ Q_D( const Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->boundary;
|
|
+
|
|
+ const PDFRectangle * rect = d->pdfAnnot->getRect();
|
|
+ return d->fromPdfRectangle( *rect );
|
|
+}
|
|
+
|
|
+void Annotation::setBoundary( const QRectF &boundary )
|
|
+{
|
|
+ Q_D( Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->boundary = boundary;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ PDFRectangle rect = d->boundaryToPdfRectangle( boundary, flags() );
|
|
+ d->pdfAnnot->setRect(&rect);
|
|
+}
|
|
+
|
|
+Annotation::Style Annotation::style() const
|
|
+{
|
|
+ Q_D( const Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->style;
|
|
+
|
|
+ Style s;
|
|
+ s.setColor(convertAnnotColor( d->pdfAnnot->getColor() ));
|
|
+
|
|
+ const AnnotMarkup *markupann = dynamic_cast<const AnnotMarkup*>(d->pdfAnnot);
|
|
+ if (markupann)
|
|
+ s.setOpacity( markupann->getOpacity() );
|
|
+
|
|
+ const AnnotBorder *border = d->pdfAnnot->getBorder();
|
|
+ if (border)
|
|
+ {
|
|
+ if ( border->getType() == AnnotBorder::typeArray )
|
|
+ {
|
|
+ const AnnotBorderArray *border_array = static_cast<const AnnotBorderArray*>(border);
|
|
+ s.setXCorners( border_array->getHorizontalCorner() );
|
|
+ s.setYCorners( border_array->getVerticalCorner() );
|
|
+ }
|
|
+
|
|
+ s.setWidth( border->getWidth() );
|
|
+ s.setLineStyle((Annotation::LineStyle)( 1 << border->getStyle() ));
|
|
+
|
|
+ const int dashArrLen = border->getDashLength();
|
|
+ const double* dashArrData = border->getDash();
|
|
+ QVector<double> dashArrVect( dashArrLen );
|
|
+ for (int i = 0; i < dashArrLen; ++i)
|
|
+ dashArrVect[i] = dashArrData[i];
|
|
+ s.setDashArray(dashArrVect);
|
|
+ }
|
|
+
|
|
+ AnnotBorderEffect *border_effect;
|
|
+ switch (d->pdfAnnot->getType())
|
|
+ {
|
|
+ case Annot::typeFreeText:
|
|
+ border_effect = static_cast<AnnotFreeText*>(d->pdfAnnot)->getBorderEffect();
|
|
+ break;
|
|
+ case Annot::typeSquare:
|
|
+ case Annot::typeCircle:
|
|
+ border_effect = static_cast<AnnotGeometry*>(d->pdfAnnot)->getBorderEffect();
|
|
+ break;
|
|
+ default:
|
|
+ border_effect = nullptr;
|
|
+ }
|
|
+ if (border_effect)
|
|
+ {
|
|
+ s.setLineEffect( (Annotation::LineEffect)border_effect->getEffectType() );
|
|
+ s.setEffectIntensity( border_effect->getIntensity() );
|
|
+ }
|
|
+
|
|
+ return s;
|
|
+}
|
|
+
|
|
+void Annotation::setStyle( const Annotation::Style& style )
|
|
+{
|
|
+ Q_D( Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->style = style;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ d->pdfAnnot->setColor(convertQColor( style.color() ));
|
|
+
|
|
+ AnnotMarkup *markupann = dynamic_cast<AnnotMarkup*>(d->pdfAnnot);
|
|
+ if (markupann)
|
|
+ markupann->setOpacity( style.opacity() );
|
|
+
|
|
+ auto border = std::make_unique<AnnotBorderArray>();
|
|
+ border->setWidth( style.width() );
|
|
+ border->setHorizontalCorner( style.xCorners() );
|
|
+ border->setVerticalCorner( style.yCorners() );
|
|
+ d->pdfAnnot->setBorder(std::move(border));
|
|
+}
|
|
+
|
|
+Annotation::Popup Annotation::popup() const
|
|
+{
|
|
+ Q_D( const Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->popup;
|
|
+
|
|
+ Popup w;
|
|
+ AnnotPopup *popup = nullptr;
|
|
+ int flags = -1; // Not initialized
|
|
+
|
|
+ const AnnotMarkup *markupann = dynamic_cast<const AnnotMarkup*>(d->pdfAnnot);
|
|
+ if (markupann)
|
|
+ {
|
|
+ popup = markupann->getPopup();
|
|
+ w.setSummary(UnicodeParsedString( markupann->getSubject() ));
|
|
+ }
|
|
+
|
|
+ if (popup)
|
|
+ {
|
|
+ flags = fromPdfFlags( popup->getFlags() ) & ( Annotation::Hidden |
|
|
+ Annotation::FixedSize | Annotation::FixedRotation );
|
|
+
|
|
+ if (!popup->getOpen())
|
|
+ flags |= Annotation::Hidden;
|
|
+
|
|
+ const PDFRectangle * rect = popup->getRect();
|
|
+ w.setGeometry( d->fromPdfRectangle( *rect ) );
|
|
+ }
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeText)
|
|
+ {
|
|
+ const AnnotText * textann = static_cast<const AnnotText*>(d->pdfAnnot);
|
|
+
|
|
+ // Text annotations default to same rect as annotation
|
|
+ if (flags == -1)
|
|
+ {
|
|
+ flags = 0;
|
|
+ w.setGeometry( boundary() );
|
|
+ }
|
|
+
|
|
+ // If text is not 'opened', force window hiding. if the window
|
|
+ // was parsed from popup, the flag should already be set
|
|
+ if ( !textann->getOpen() && flags != -1 )
|
|
+ flags |= Annotation::Hidden;
|
|
+ }
|
|
+
|
|
+ w.setFlags(flags);
|
|
+
|
|
+ return w;
|
|
+}
|
|
+
|
|
+void Annotation::setPopup( const Annotation::Popup& popup )
|
|
+{
|
|
+ Q_D( Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->popup = popup;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+#if 0 /* TODO: Remove old popup and add AnnotPopup to page */
|
|
+ AnnotMarkup *markupann = dynamic_cast<AnnotMarkup*>(d->pdfAnnot);
|
|
+ if (!markupann)
|
|
+ return;
|
|
+
|
|
+ // Create a new AnnotPopup and assign it to pdfAnnot
|
|
+ PDFRectangle rect = d->toPdfRectangle( popup.geometry() );
|
|
+ AnnotPopup * p = new AnnotPopup( d->pdfPage->getDoc(), &rect );
|
|
+ p->setOpen( !(popup.flags() & Annotation::Hidden) );
|
|
+ if (!popup.summary().isEmpty())
|
|
+ {
|
|
+ GooString *s = QStringToUnicodeGooString(popup.summary());
|
|
+ markupann->setLabel(s);
|
|
+ delete s;
|
|
+ }
|
|
+ markupann->setPopup(p);
|
|
+#endif
|
|
+}
|
|
+
|
|
+Annotation::RevScope Annotation::revisionScope() const
|
|
+{
|
|
+ Q_D( const Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->revisionScope;
|
|
+
|
|
+ const AnnotMarkup *markupann = dynamic_cast<const AnnotMarkup*>(d->pdfAnnot);
|
|
+
|
|
+ if (markupann && markupann->getInReplyToID() != 0)
|
|
+ {
|
|
+ switch (markupann->getReplyTo())
|
|
+ {
|
|
+ case AnnotMarkup::replyTypeR:
|
|
+ return Annotation::Reply;
|
|
+ case AnnotMarkup::replyTypeGroup:
|
|
+ return Annotation::Group;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return Annotation::Root; // It's not a revision
|
|
+}
|
|
+
|
|
+Annotation::RevType Annotation::revisionType() const
|
|
+{
|
|
+ Q_D( const Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->revisionType;
|
|
+
|
|
+ const AnnotText *textann = dynamic_cast<const AnnotText*>(d->pdfAnnot);
|
|
+
|
|
+ if (textann && textann->getInReplyToID() != 0)
|
|
+ {
|
|
+ switch (textann->getState())
|
|
+ {
|
|
+ case AnnotText::stateMarked:
|
|
+ return Annotation::Marked;
|
|
+ case AnnotText::stateUnmarked:
|
|
+ return Annotation::Unmarked;
|
|
+ case AnnotText::stateAccepted:
|
|
+ return Annotation::Accepted;
|
|
+ case AnnotText::stateRejected:
|
|
+ return Annotation::Rejected;
|
|
+ case AnnotText::stateCancelled:
|
|
+ return Annotation::Cancelled;
|
|
+ case AnnotText::stateCompleted:
|
|
+ return Annotation::Completed;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return Annotation::None;
|
|
+}
|
|
+
|
|
+QList<Annotation*> Annotation::revisions() const
|
|
+{
|
|
+ Q_D( const Annotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ /* Return aliases, whose ownership goes to the caller */
|
|
+ QList<Annotation*> res;
|
|
+ foreach (Annotation *rev, d->revisions)
|
|
+ res.append( rev->d_ptr->makeAlias() );
|
|
+ return res;
|
|
+ }
|
|
+
|
|
+ /* If the annotation doesn't live in a object on its own (eg bug51361), it
|
|
+ * has no ref, therefore it can't have revisions */
|
|
+ if ( !d->pdfAnnot->getHasRef() )
|
|
+ return QList<Annotation*>();
|
|
+
|
|
+ return AnnotationPrivate::findAnnotations( d->pdfPage, d->parentDoc, QSet<Annotation::SubType>(), d->pdfAnnot->getId() );
|
|
+}
|
|
+
|
|
+//END Annotation implementation
|
|
+
|
|
+
|
|
+/** TextAnnotation [Annotation] */
|
|
+class TextAnnotationPrivate : public AnnotationPrivate
|
|
+{
|
|
+ public:
|
|
+ TextAnnotationPrivate();
|
|
+ Annotation * makeAlias();
|
|
+ Annot* createNativeAnnot(::Page *destPage, DocumentData *doc);
|
|
+ void setDefaultAppearanceToNative();
|
|
+ std::unique_ptr<DefaultAppearance> getDefaultAppearanceFromNative() const;
|
|
+
|
|
+ // data fields
|
|
+ TextAnnotation::TextType textType;
|
|
+ QString textIcon;
|
|
+ QFont textFont;
|
|
+ QColor textColor;
|
|
+ int inplaceAlign; // 0:left, 1:center, 2:right
|
|
+ QVector<QPointF> inplaceCallout;
|
|
+ TextAnnotation::InplaceIntent inplaceIntent;
|
|
+};
|
|
+
|
|
+TextAnnotationPrivate::TextAnnotationPrivate()
|
|
+ : AnnotationPrivate(), textType( TextAnnotation::Linked ),
|
|
+ textIcon( "Note" ), inplaceAlign( 0 ),
|
|
+ inplaceIntent( TextAnnotation::Unknown )
|
|
+{
|
|
+}
|
|
+
|
|
+Annotation * TextAnnotationPrivate::makeAlias()
|
|
+{
|
|
+ return new TextAnnotation(*this);
|
|
+}
|
|
+
|
|
+Annot* TextAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
|
|
+{
|
|
+ // Setters are defined in the public class
|
|
+ TextAnnotation *q = static_cast<TextAnnotation*>( makeAlias() );
|
|
+
|
|
+ // Set page and contents
|
|
+ pdfPage = destPage;
|
|
+ parentDoc = doc;
|
|
+
|
|
+ // Set pdfAnnot
|
|
+ PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
|
|
+ if (textType == TextAnnotation::Linked) {
|
|
+ pdfAnnot = new AnnotText(destPage->getDoc(), &rect);
|
|
+ } else {
|
|
+ DefaultAppearance da{ { objName, "Invalid_font" }, static_cast<double>( textFont.pointSize() ), std::unique_ptr<AnnotColor>{ convertQColor( textColor ) } };
|
|
+ pdfAnnot = new AnnotFreeText(destPage->getDoc(), &rect, da);
|
|
+ }
|
|
+
|
|
+ // Set properties
|
|
+ flushBaseAnnotationProperties();
|
|
+ q->setTextIcon(textIcon);
|
|
+ q->setInplaceAlign(inplaceAlign);
|
|
+ q->setCalloutPoints(inplaceCallout);
|
|
+ q->setInplaceIntent(inplaceIntent);
|
|
+
|
|
+ delete q;
|
|
+
|
|
+ inplaceCallout.clear(); // Free up memory
|
|
+
|
|
+ return pdfAnnot;
|
|
+}
|
|
+
|
|
+void TextAnnotationPrivate::setDefaultAppearanceToNative()
|
|
+{
|
|
+ if (pdfAnnot && pdfAnnot->getType() == Annot::typeFreeText) {
|
|
+ AnnotFreeText * ftextann = static_cast<AnnotFreeText*>(pdfAnnot);
|
|
+ DefaultAppearance da{ { objName, "Invalid_font" }, static_cast<double>( textFont.pointSize() ), std::unique_ptr<AnnotColor>{ convertQColor( textColor ) } };
|
|
+ ftextann->setDefaultAppearance( da );
|
|
+ }
|
|
+}
|
|
+
|
|
+std::unique_ptr<DefaultAppearance> TextAnnotationPrivate::getDefaultAppearanceFromNative() const
|
|
+{
|
|
+ if (pdfAnnot && pdfAnnot->getType() == Annot::typeFreeText) {
|
|
+ AnnotFreeText * ftextann = static_cast<AnnotFreeText*>(pdfAnnot);
|
|
+ return ftextann->getDefaultAppearance();
|
|
+ } else {
|
|
+ return nullptr;
|
|
+ }
|
|
+}
|
|
+
|
|
+TextAnnotation::TextAnnotation( TextAnnotation::TextType type )
|
|
+ : Annotation( *new TextAnnotationPrivate() )
|
|
+{
|
|
+ setTextType( type );
|
|
+}
|
|
+
|
|
+TextAnnotation::TextAnnotation(TextAnnotationPrivate &dd)
|
|
+ : Annotation( dd )
|
|
+{}
|
|
+
|
|
+TextAnnotation::TextAnnotation( const QDomNode & node )
|
|
+ : Annotation( *new TextAnnotationPrivate, node )
|
|
+{
|
|
+ // loop through the whole children looking for a 'text' element
|
|
+ QDomNode subNode = node.firstChild();
|
|
+ while( subNode.isElement() )
|
|
+ {
|
|
+ QDomElement e = subNode.toElement();
|
|
+ subNode = subNode.nextSibling();
|
|
+ if ( e.tagName() != "text" )
|
|
+ continue;
|
|
+
|
|
+ // parse the attributes
|
|
+ if ( e.hasAttribute( "type" ) )
|
|
+ setTextType((TextAnnotation::TextType)e.attribute( "type" ).toInt());
|
|
+ if ( e.hasAttribute( "icon" ) )
|
|
+ setTextIcon(e.attribute( "icon" ));
|
|
+ if ( e.hasAttribute( "font" ) )
|
|
+ {
|
|
+ QFont font;
|
|
+ font.fromString( e.attribute( "font" ) );
|
|
+ setTextFont(font);
|
|
+ if ( e.hasAttribute( "fontColor" ) )
|
|
+ {
|
|
+ const QColor color = QColor(e.attribute( "fontColor" ) );
|
|
+ setTextColor(color);
|
|
+ }
|
|
+ }
|
|
+ if ( e.hasAttribute( "align" ) )
|
|
+ setInplaceAlign(e.attribute( "align" ).toInt());
|
|
+ if ( e.hasAttribute( "intent" ) )
|
|
+ setInplaceIntent((TextAnnotation::InplaceIntent)e.attribute( "intent" ).toInt());
|
|
+
|
|
+ // parse the subnodes
|
|
+ QDomNode eSubNode = e.firstChild();
|
|
+ while ( eSubNode.isElement() )
|
|
+ {
|
|
+ QDomElement ee = eSubNode.toElement();
|
|
+ eSubNode = eSubNode.nextSibling();
|
|
+
|
|
+ if ( ee.tagName() == "escapedText" )
|
|
+ {
|
|
+ setInplaceText(ee.firstChild().toCDATASection().data());
|
|
+ }
|
|
+ else if ( ee.tagName() == "callout" )
|
|
+ {
|
|
+ QVector<QPointF> points(3);
|
|
+ points[0] = QPointF(ee.attribute( "ax" ).toDouble(),
|
|
+ ee.attribute( "ay" ).toDouble());
|
|
+ points[1] = QPointF(ee.attribute( "bx" ).toDouble(),
|
|
+ ee.attribute( "by" ).toDouble());
|
|
+ points[2] = QPointF(ee.attribute( "cx" ).toDouble(),
|
|
+ ee.attribute( "cy" ).toDouble());
|
|
+ setCalloutPoints(points);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // loading complete
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+TextAnnotation::~TextAnnotation()
|
|
+{
|
|
+}
|
|
+
|
|
+void TextAnnotation::store( QDomNode & node, QDomDocument & document ) const
|
|
+{
|
|
+ // store base annotation properties
|
|
+ storeBaseAnnotationProperties( node, document );
|
|
+
|
|
+ // create [text] element
|
|
+ QDomElement textElement = document.createElement( "text" );
|
|
+ node.appendChild( textElement );
|
|
+
|
|
+ // store the optional attributes
|
|
+ if ( textType() != Linked )
|
|
+ textElement.setAttribute( "type", (int)textType() );
|
|
+ if ( textIcon() != "Note" )
|
|
+ textElement.setAttribute( "icon", textIcon() );
|
|
+ if ( inplaceAlign() )
|
|
+ textElement.setAttribute( "align", inplaceAlign() );
|
|
+ if ( inplaceIntent() != Unknown )
|
|
+ textElement.setAttribute( "intent", (int)inplaceIntent() );
|
|
+
|
|
+ textElement.setAttribute( "font", textFont().toString() );
|
|
+ textElement.setAttribute( "fontColor", textColor().name() );
|
|
+
|
|
+ // Sub-Node-1 - escapedText
|
|
+ if ( !inplaceText().isEmpty() )
|
|
+ {
|
|
+ QDomElement escapedText = document.createElement( "escapedText" );
|
|
+ textElement.appendChild( escapedText );
|
|
+ QDomCDATASection textCData = document.createCDATASection( inplaceText() );
|
|
+ escapedText.appendChild( textCData );
|
|
+ }
|
|
+
|
|
+ // Sub-Node-2 - callout
|
|
+ if ( calloutPoint(0).x() != 0.0 )
|
|
+ {
|
|
+ QDomElement calloutElement = document.createElement( "callout" );
|
|
+ textElement.appendChild( calloutElement );
|
|
+ calloutElement.setAttribute( "ax", QString::number( calloutPoint(0).x() ) );
|
|
+ calloutElement.setAttribute( "ay", QString::number( calloutPoint(0).y() ) );
|
|
+ calloutElement.setAttribute( "bx", QString::number( calloutPoint(1).x() ) );
|
|
+ calloutElement.setAttribute( "by", QString::number( calloutPoint(1).y() ) );
|
|
+ calloutElement.setAttribute( "cx", QString::number( calloutPoint(2).x() ) );
|
|
+ calloutElement.setAttribute( "cy", QString::number( calloutPoint(2).y() ) );
|
|
+ }
|
|
+}
|
|
+
|
|
+Annotation::SubType TextAnnotation::subType() const
|
|
+{
|
|
+ return AText;
|
|
+}
|
|
+
|
|
+TextAnnotation::TextType TextAnnotation::textType() const
|
|
+{
|
|
+ Q_D( const TextAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->textType;
|
|
+
|
|
+ return d->pdfAnnot->getType() == Annot::typeText ?
|
|
+ TextAnnotation::Linked : TextAnnotation::InPlace;
|
|
+}
|
|
+
|
|
+void TextAnnotation::setTextType( TextAnnotation::TextType type )
|
|
+{
|
|
+ Q_D( TextAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->textType = type;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Type cannot be changed if annotation is already tied
|
|
+}
|
|
+
|
|
+QString TextAnnotation::textIcon() const
|
|
+{
|
|
+ Q_D( const TextAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->textIcon;
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeText)
|
|
+ {
|
|
+ const AnnotText * textann = static_cast<const AnnotText*>(d->pdfAnnot);
|
|
+ return QString::fromLatin1( textann->getIcon()->c_str() );
|
|
+ }
|
|
+
|
|
+ return QString();
|
|
+}
|
|
+
|
|
+void TextAnnotation::setTextIcon( const QString &icon )
|
|
+{
|
|
+ Q_D( TextAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->textIcon = icon;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeText)
|
|
+ {
|
|
+ AnnotText * textann = static_cast<AnnotText*>(d->pdfAnnot);
|
|
+ QByteArray encoded = icon.toLatin1();
|
|
+ GooString s(encoded.constData());
|
|
+ textann->setIcon(&s);
|
|
+ }
|
|
+}
|
|
+
|
|
+QFont TextAnnotation::textFont() const
|
|
+{
|
|
+ Q_D( const TextAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->textFont;
|
|
+
|
|
+ QFont font;
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeFreeText)
|
|
+ {
|
|
+ if ( std::unique_ptr<DefaultAppearance> da{ d->getDefaultAppearanceFromNative() } )
|
|
+ {
|
|
+ font.setPointSize( da->getFontPtSize() );
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return font;
|
|
+}
|
|
+
|
|
+void TextAnnotation::setTextFont( const QFont &font )
|
|
+{
|
|
+ Q_D( TextAnnotation );
|
|
+ d->textFont = font;
|
|
+ d->textColor = Qt::black;
|
|
+
|
|
+ d->setDefaultAppearanceToNative();
|
|
+}
|
|
+
|
|
+QColor TextAnnotation::textColor() const
|
|
+{
|
|
+ Q_D( const TextAnnotation );
|
|
+
|
|
+ if ( !d->pdfAnnot )
|
|
+ return d->textColor;
|
|
+
|
|
+ if ( std::unique_ptr<DefaultAppearance> da{ d->getDefaultAppearanceFromNative() } )
|
|
+ {
|
|
+ return convertAnnotColor( da->getFontColor() );
|
|
+ }
|
|
+
|
|
+ return {};
|
|
+}
|
|
+
|
|
+void TextAnnotation::setTextColor( const QColor &color )
|
|
+{
|
|
+ Q_D( TextAnnotation );
|
|
+ d->textColor = color;
|
|
+
|
|
+ d->setDefaultAppearanceToNative();
|
|
+}
|
|
+
|
|
+int TextAnnotation::inplaceAlign() const
|
|
+{
|
|
+ Q_D( const TextAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->inplaceAlign;
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeFreeText)
|
|
+ {
|
|
+ const AnnotFreeText * ftextann = static_cast<const AnnotFreeText*>(d->pdfAnnot);
|
|
+ return ftextann->getQuadding();
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void TextAnnotation::setInplaceAlign( int align )
|
|
+{
|
|
+ Q_D( TextAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->inplaceAlign = align;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeFreeText)
|
|
+ {
|
|
+ AnnotFreeText * ftextann = static_cast<AnnotFreeText*>(d->pdfAnnot);
|
|
+ ftextann->setQuadding((AnnotFreeText::AnnotFreeTextQuadding)align);
|
|
+ }
|
|
+}
|
|
+
|
|
+QString TextAnnotation::inplaceText() const
|
|
+{
|
|
+ return contents();
|
|
+}
|
|
+
|
|
+void TextAnnotation::setInplaceText( const QString &text )
|
|
+{
|
|
+ setContents(text);
|
|
+}
|
|
+
|
|
+QPointF TextAnnotation::calloutPoint( int id ) const
|
|
+{
|
|
+ const QVector<QPointF> points = calloutPoints();
|
|
+ if ( id < 0 || id >= points.size() )
|
|
+ return QPointF();
|
|
+ else
|
|
+ return points[id];
|
|
+}
|
|
+
|
|
+QVector<QPointF> TextAnnotation::calloutPoints() const
|
|
+{
|
|
+ Q_D( const TextAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->inplaceCallout;
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeText)
|
|
+ return QVector<QPointF>();
|
|
+
|
|
+ const AnnotFreeText * ftextann = static_cast<const AnnotFreeText*>(d->pdfAnnot);
|
|
+ const AnnotCalloutLine *callout = ftextann->getCalloutLine();
|
|
+
|
|
+ if (!callout)
|
|
+ return QVector<QPointF>();
|
|
+
|
|
+ double MTX[6];
|
|
+ d->fillTransformationMTX(MTX);
|
|
+
|
|
+ const AnnotCalloutMultiLine * callout_v6 = dynamic_cast<const AnnotCalloutMultiLine*>(callout);
|
|
+ QVector<QPointF> res(callout_v6 ? 3 : 2);
|
|
+ XPDFReader::transform(MTX, callout->getX1(), callout->getY1(), res[0]);
|
|
+ XPDFReader::transform(MTX, callout->getX2(), callout->getY2(), res[1]);
|
|
+ if (callout_v6)
|
|
+ XPDFReader::transform(MTX, callout_v6->getX3(), callout_v6->getY3(), res[2]);
|
|
+ return res;
|
|
+}
|
|
+
|
|
+void TextAnnotation::setCalloutPoints( const QVector<QPointF> &points )
|
|
+{
|
|
+ Q_D( TextAnnotation );
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->inplaceCallout = points;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (d->pdfAnnot->getType() != Annot::typeFreeText)
|
|
+ return;
|
|
+
|
|
+ AnnotFreeText * ftextann = static_cast<AnnotFreeText*>(d->pdfAnnot);
|
|
+ const int count = points.size();
|
|
+
|
|
+ if (count == 0)
|
|
+ {
|
|
+ ftextann->setCalloutLine(0);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (count != 2 && count != 3)
|
|
+ {
|
|
+ error(errSyntaxError, -1, "Expected zero, two or three points for callout");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ AnnotCalloutLine *callout;
|
|
+ double x1, y1, x2, y2;
|
|
+ double MTX[6];
|
|
+ d->fillTransformationMTX(MTX);
|
|
+
|
|
+ XPDFReader::invTransform( MTX, points[0], x1, y1 );
|
|
+ XPDFReader::invTransform( MTX, points[1], x2, y2 );
|
|
+ if (count == 3)
|
|
+ {
|
|
+ double x3, y3;
|
|
+ XPDFReader::invTransform( MTX, points[2], x3, y3 );
|
|
+ callout = new AnnotCalloutMultiLine(x1, y1, x2, y2, x3, y3);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ callout = new AnnotCalloutLine(x1, y1, x2, y2);
|
|
+ }
|
|
+
|
|
+ ftextann->setCalloutLine(callout);
|
|
+ delete callout;
|
|
+}
|
|
+
|
|
+TextAnnotation::InplaceIntent TextAnnotation::inplaceIntent() const
|
|
+{
|
|
+ Q_D( const TextAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->inplaceIntent;
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeFreeText)
|
|
+ {
|
|
+ const AnnotFreeText * ftextann = static_cast<const AnnotFreeText*>(d->pdfAnnot);
|
|
+ return (TextAnnotation::InplaceIntent)ftextann->getIntent();
|
|
+ }
|
|
+
|
|
+ return TextAnnotation::Unknown;
|
|
+}
|
|
+
|
|
+void TextAnnotation::setInplaceIntent( TextAnnotation::InplaceIntent intent )
|
|
+{
|
|
+ Q_D( TextAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->inplaceIntent = intent;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeFreeText)
|
|
+ {
|
|
+ AnnotFreeText * ftextann = static_cast<AnnotFreeText*>(d->pdfAnnot);
|
|
+ ftextann->setIntent((AnnotFreeText::AnnotFreeTextIntent)intent);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+/** LineAnnotation [Annotation] */
|
|
+class LineAnnotationPrivate : public AnnotationPrivate
|
|
+{
|
|
+ public:
|
|
+ LineAnnotationPrivate();
|
|
+ Annotation * makeAlias();
|
|
+ Annot* createNativeAnnot(::Page *destPage, DocumentData *doc);
|
|
+
|
|
+ // data fields (note uses border for rendering style)
|
|
+ QLinkedList<QPointF> linePoints;
|
|
+ LineAnnotation::TermStyle lineStartStyle;
|
|
+ LineAnnotation::TermStyle lineEndStyle;
|
|
+ bool lineClosed : 1; // (if true draw close shape)
|
|
+ bool lineShowCaption : 1;
|
|
+ LineAnnotation::LineType lineType;
|
|
+ QColor lineInnerColor;
|
|
+ double lineLeadingFwdPt;
|
|
+ double lineLeadingBackPt;
|
|
+ LineAnnotation::LineIntent lineIntent;
|
|
+};
|
|
+
|
|
+LineAnnotationPrivate::LineAnnotationPrivate()
|
|
+ : AnnotationPrivate(), lineStartStyle( LineAnnotation::None ),
|
|
+ lineEndStyle( LineAnnotation::None ), lineClosed( false ),
|
|
+ lineShowCaption( false ), lineLeadingFwdPt( 0 ),
|
|
+ lineLeadingBackPt( 0 ), lineIntent( LineAnnotation::Unknown )
|
|
+{
|
|
+}
|
|
+
|
|
+Annotation * LineAnnotationPrivate::makeAlias()
|
|
+{
|
|
+ return new LineAnnotation(*this);
|
|
+}
|
|
+
|
|
+Annot* LineAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
|
|
+{
|
|
+ // Setters are defined in the public class
|
|
+ LineAnnotation *q = static_cast<LineAnnotation*>( makeAlias() );
|
|
+
|
|
+ // Set page and document
|
|
+ pdfPage = destPage;
|
|
+ parentDoc = doc;
|
|
+
|
|
+ // Set pdfAnnot
|
|
+ PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
|
|
+ if (lineType == LineAnnotation::StraightLine)
|
|
+ {
|
|
+ pdfAnnot = new AnnotLine(doc->doc, &rect);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ pdfAnnot = new AnnotPolygon(doc->doc, &rect,
|
|
+ lineClosed ? Annot::typePolygon : Annot::typePolyLine );
|
|
+ }
|
|
+
|
|
+ // Set properties
|
|
+ flushBaseAnnotationProperties();
|
|
+ q->setLinePoints(linePoints);
|
|
+ q->setLineStartStyle(lineStartStyle);
|
|
+ q->setLineEndStyle(lineEndStyle);
|
|
+ q->setLineInnerColor(lineInnerColor);
|
|
+ q->setLineLeadingForwardPoint(lineLeadingFwdPt);
|
|
+ q->setLineLeadingBackPoint(lineLeadingBackPt);
|
|
+ q->setLineShowCaption(lineShowCaption);
|
|
+ q->setLineIntent(lineIntent);
|
|
+
|
|
+ delete q;
|
|
+
|
|
+ linePoints.clear(); // Free up memory
|
|
+
|
|
+ return pdfAnnot;
|
|
+}
|
|
+
|
|
+LineAnnotation::LineAnnotation( LineAnnotation::LineType type )
|
|
+ : Annotation( *new LineAnnotationPrivate() )
|
|
+{
|
|
+ setLineType(type);
|
|
+}
|
|
+
|
|
+LineAnnotation::LineAnnotation(LineAnnotationPrivate &dd)
|
|
+ : Annotation( dd )
|
|
+{}
|
|
+
|
|
+LineAnnotation::LineAnnotation( const QDomNode & node )
|
|
+ : Annotation( *new LineAnnotationPrivate(), node )
|
|
+{
|
|
+ // loop through the whole children looking for a 'line' element
|
|
+ QDomNode subNode = node.firstChild();
|
|
+ while( subNode.isElement() )
|
|
+ {
|
|
+ QDomElement e = subNode.toElement();
|
|
+ subNode = subNode.nextSibling();
|
|
+ if ( e.tagName() != "line" )
|
|
+ continue;
|
|
+
|
|
+ // parse the attributes
|
|
+ if ( e.hasAttribute( "startStyle" ) )
|
|
+ setLineStartStyle((LineAnnotation::TermStyle)e.attribute( "startStyle" ).toInt());
|
|
+ if ( e.hasAttribute( "endStyle" ) )
|
|
+ setLineEndStyle((LineAnnotation::TermStyle)e.attribute( "endStyle" ).toInt());
|
|
+ if ( e.hasAttribute( "closed" ) )
|
|
+ setLineClosed(e.attribute( "closed" ).toInt());
|
|
+ if ( e.hasAttribute( "innerColor" ) )
|
|
+ setLineInnerColor(QColor( e.attribute( "innerColor" ) ));
|
|
+ if ( e.hasAttribute( "leadFwd" ) )
|
|
+ setLineLeadingForwardPoint(e.attribute( "leadFwd" ).toDouble());
|
|
+ if ( e.hasAttribute( "leadBack" ) )
|
|
+ setLineLeadingBackPoint(e.attribute( "leadBack" ).toDouble());
|
|
+ if ( e.hasAttribute( "showCaption" ) )
|
|
+ setLineShowCaption(e.attribute( "showCaption" ).toInt());
|
|
+ if ( e.hasAttribute( "intent" ) )
|
|
+ setLineIntent((LineAnnotation::LineIntent)e.attribute( "intent" ).toInt());
|
|
+
|
|
+ // parse all 'point' subnodes
|
|
+ QLinkedList<QPointF> points;
|
|
+ QDomNode pointNode = e.firstChild();
|
|
+ while ( pointNode.isElement() )
|
|
+ {
|
|
+ QDomElement pe = pointNode.toElement();
|
|
+ pointNode = pointNode.nextSibling();
|
|
+
|
|
+ if ( pe.tagName() != "point" )
|
|
+ continue;
|
|
+
|
|
+ QPointF p(pe.attribute( "x", "0.0" ).toDouble(), pe.attribute( "y", "0.0" ).toDouble());
|
|
+ points.append( p );
|
|
+ }
|
|
+ setLinePoints(points);
|
|
+ setLineType(points.size() == 2 ? StraightLine : Polyline);
|
|
+
|
|
+ // loading complete
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+LineAnnotation::~LineAnnotation()
|
|
+{
|
|
+}
|
|
+
|
|
+void LineAnnotation::store( QDomNode & node, QDomDocument & document ) const
|
|
+{
|
|
+ // store base annotation properties
|
|
+ storeBaseAnnotationProperties( node, document );
|
|
+
|
|
+ // create [line] element
|
|
+ QDomElement lineElement = document.createElement( "line" );
|
|
+ node.appendChild( lineElement );
|
|
+
|
|
+ // store the attributes
|
|
+ if ( lineStartStyle() != None )
|
|
+ lineElement.setAttribute( "startStyle", (int)lineStartStyle() );
|
|
+ if ( lineEndStyle() != None )
|
|
+ lineElement.setAttribute( "endStyle", (int)lineEndStyle() );
|
|
+ if ( isLineClosed() )
|
|
+ lineElement.setAttribute( "closed", isLineClosed() );
|
|
+ if ( lineInnerColor().isValid() )
|
|
+ lineElement.setAttribute( "innerColor", lineInnerColor().name() );
|
|
+ if ( lineLeadingForwardPoint() != 0.0 )
|
|
+ lineElement.setAttribute( "leadFwd", QString::number( lineLeadingForwardPoint() ) );
|
|
+ if ( lineLeadingBackPoint() != 0.0 )
|
|
+ lineElement.setAttribute( "leadBack", QString::number( lineLeadingBackPoint() ) );
|
|
+ if ( lineShowCaption() )
|
|
+ lineElement.setAttribute( "showCaption", lineShowCaption() );
|
|
+ if ( lineIntent() != Unknown )
|
|
+ lineElement.setAttribute( "intent", lineIntent() );
|
|
+
|
|
+ // append the list of points
|
|
+ const QLinkedList<QPointF> points = linePoints();
|
|
+ if ( points.count() > 1 )
|
|
+ {
|
|
+ QLinkedList<QPointF>::const_iterator it = points.begin(), end = points.end();
|
|
+ while ( it != end )
|
|
+ {
|
|
+ const QPointF & p = *it;
|
|
+ QDomElement pElement = document.createElement( "point" );
|
|
+ lineElement.appendChild( pElement );
|
|
+ pElement.setAttribute( "x", QString::number( p.x() ) );
|
|
+ pElement.setAttribute( "y", QString::number( p.y() ) );
|
|
+ ++it;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+Annotation::SubType LineAnnotation::subType() const
|
|
+{
|
|
+ return ALine;
|
|
+}
|
|
+
|
|
+LineAnnotation::LineType LineAnnotation::lineType() const
|
|
+{
|
|
+ Q_D( const LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->lineType;
|
|
+
|
|
+ return (d->pdfAnnot->getType() == Annot::typeLine) ?
|
|
+ LineAnnotation::StraightLine : LineAnnotation::Polyline;
|
|
+}
|
|
+
|
|
+void LineAnnotation::setLineType( LineAnnotation::LineType type )
|
|
+{
|
|
+ Q_D( LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->lineType = type;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Type cannot be changed if annotation is already tied
|
|
+}
|
|
+
|
|
+QLinkedList<QPointF> LineAnnotation::linePoints() const
|
|
+{
|
|
+ Q_D( const LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->linePoints;
|
|
+
|
|
+ double MTX[6];
|
|
+ d->fillTransformationMTX(MTX);
|
|
+
|
|
+ QLinkedList<QPointF> res;
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ const AnnotLine * lineann = static_cast<const AnnotLine*>(d->pdfAnnot);
|
|
+ QPointF p;
|
|
+ XPDFReader::transform(MTX, lineann->getX1(), lineann->getY1(), p);
|
|
+ res.append(p);
|
|
+ XPDFReader::transform(MTX, lineann->getX2(), lineann->getY2(), p);
|
|
+ res.append(p);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ const AnnotPolygon * polyann = static_cast<const AnnotPolygon*>(d->pdfAnnot);
|
|
+ const AnnotPath * vertices = polyann->getVertices();
|
|
+
|
|
+ for (int i = 0; i < vertices->getCoordsLength(); ++i)
|
|
+ {
|
|
+ QPointF p;
|
|
+ XPDFReader::transform(MTX, vertices->getX(i), vertices->getY(i), p);
|
|
+ res.append(p);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return res;
|
|
+}
|
|
+
|
|
+void LineAnnotation::setLinePoints( const QLinkedList<QPointF> &points )
|
|
+{
|
|
+ Q_D( LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->linePoints = points;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ AnnotLine *lineann = static_cast<AnnotLine*>(d->pdfAnnot);
|
|
+ if (points.size() != 2)
|
|
+ {
|
|
+ error(errSyntaxError, -1, "Expected two points for a straight line");
|
|
+ return;
|
|
+ }
|
|
+ double x1, y1, x2, y2;
|
|
+ double MTX[6];
|
|
+ d->fillTransformationMTX(MTX);
|
|
+ XPDFReader::invTransform( MTX, points.first(), x1, y1 );
|
|
+ XPDFReader::invTransform( MTX, points.last(), x2, y2 );
|
|
+ lineann->setVertices(x1, y1, x2, y2);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ AnnotPolygon *polyann = static_cast<AnnotPolygon*>(d->pdfAnnot);
|
|
+ AnnotPath * p = d->toAnnotPath(points);
|
|
+ polyann->setVertices(p);
|
|
+ delete p;
|
|
+ }
|
|
+}
|
|
+
|
|
+LineAnnotation::TermStyle LineAnnotation::lineStartStyle() const
|
|
+{
|
|
+ Q_D( const LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->lineStartStyle;
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ const AnnotLine * lineann = static_cast<const AnnotLine*>(d->pdfAnnot);
|
|
+ return (LineAnnotation::TermStyle)lineann->getStartStyle();
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ const AnnotPolygon * polyann = static_cast<const AnnotPolygon*>(d->pdfAnnot);
|
|
+ return (LineAnnotation::TermStyle)polyann->getStartStyle();
|
|
+ }
|
|
+}
|
|
+
|
|
+void LineAnnotation::setLineStartStyle( LineAnnotation::TermStyle style )
|
|
+{
|
|
+ Q_D( LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->lineStartStyle = style;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ AnnotLine *lineann = static_cast<AnnotLine*>(d->pdfAnnot);
|
|
+ lineann->setStartEndStyle((AnnotLineEndingStyle)style, lineann->getEndStyle());
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ AnnotPolygon *polyann = static_cast<AnnotPolygon*>(d->pdfAnnot);
|
|
+ polyann->setStartEndStyle((AnnotLineEndingStyle)style, polyann->getEndStyle());
|
|
+ }
|
|
+}
|
|
+
|
|
+LineAnnotation::TermStyle LineAnnotation::lineEndStyle() const
|
|
+{
|
|
+ Q_D( const LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->lineEndStyle;
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ const AnnotLine * lineann = static_cast<const AnnotLine*>(d->pdfAnnot);
|
|
+ return (LineAnnotation::TermStyle)lineann->getEndStyle();
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ const AnnotPolygon * polyann = static_cast<const AnnotPolygon*>(d->pdfAnnot);
|
|
+ return (LineAnnotation::TermStyle)polyann->getEndStyle();
|
|
+ }
|
|
+}
|
|
+
|
|
+void LineAnnotation::setLineEndStyle( LineAnnotation::TermStyle style )
|
|
+{
|
|
+ Q_D( LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->lineEndStyle = style;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ AnnotLine *lineann = static_cast<AnnotLine*>(d->pdfAnnot);
|
|
+ lineann->setStartEndStyle(lineann->getStartStyle(), (AnnotLineEndingStyle)style);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ AnnotPolygon *polyann = static_cast<AnnotPolygon*>(d->pdfAnnot);
|
|
+ polyann->setStartEndStyle(polyann->getStartStyle(), (AnnotLineEndingStyle)style);
|
|
+ }
|
|
+}
|
|
+
|
|
+bool LineAnnotation::isLineClosed() const
|
|
+{
|
|
+ Q_D( const LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->lineClosed;
|
|
+
|
|
+ return d->pdfAnnot->getType() == Annot::typePolygon;
|
|
+}
|
|
+
|
|
+void LineAnnotation::setLineClosed( bool closed )
|
|
+{
|
|
+ Q_D( LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->lineClosed = closed;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (d->pdfAnnot->getType() != Annot::typeLine)
|
|
+ {
|
|
+ AnnotPolygon *polyann = static_cast<AnnotPolygon*>(d->pdfAnnot);
|
|
+
|
|
+ // Set new subtype and switch intent if necessary
|
|
+ if (closed)
|
|
+ {
|
|
+ polyann->setType(Annot::typePolygon);
|
|
+ if (polyann->getIntent() == AnnotPolygon::polylineDimension)
|
|
+ polyann->setIntent( AnnotPolygon::polygonDimension );
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ polyann->setType(Annot::typePolyLine);
|
|
+ if (polyann->getIntent() == AnnotPolygon::polygonDimension)
|
|
+ polyann->setIntent( AnnotPolygon::polylineDimension );
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+QColor LineAnnotation::lineInnerColor() const
|
|
+{
|
|
+ Q_D( const LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->lineInnerColor;
|
|
+
|
|
+ AnnotColor * c;
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ const AnnotLine * lineann = static_cast<const AnnotLine*>(d->pdfAnnot);
|
|
+ c = lineann->getInteriorColor();
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ const AnnotPolygon * polyann = static_cast<const AnnotPolygon*>(d->pdfAnnot);
|
|
+ c = polyann->getInteriorColor();
|
|
+ }
|
|
+
|
|
+ return convertAnnotColor(c);
|
|
+}
|
|
+
|
|
+void LineAnnotation::setLineInnerColor( const QColor &color )
|
|
+{
|
|
+ Q_D( LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->lineInnerColor = color;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ auto c = convertQColor(color);
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ AnnotLine *lineann = static_cast<AnnotLine*>(d->pdfAnnot);
|
|
+ lineann->setInteriorColor(std::move(c));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ AnnotPolygon *polyann = static_cast<AnnotPolygon*>(d->pdfAnnot);
|
|
+ polyann->setInteriorColor(std::move(c));
|
|
+ }
|
|
+}
|
|
+
|
|
+double LineAnnotation::lineLeadingForwardPoint() const
|
|
+{
|
|
+ Q_D( const LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->lineLeadingFwdPt;
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ const AnnotLine * lineann = static_cast<const AnnotLine*>(d->pdfAnnot);
|
|
+ return lineann->getLeaderLineLength();
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void LineAnnotation::setLineLeadingForwardPoint( double point )
|
|
+{
|
|
+ Q_D( LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->lineLeadingFwdPt = point;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ AnnotLine *lineann = static_cast<AnnotLine*>(d->pdfAnnot);
|
|
+ lineann->setLeaderLineLength(point);
|
|
+ }
|
|
+}
|
|
+
|
|
+double LineAnnotation::lineLeadingBackPoint() const
|
|
+{
|
|
+ Q_D( const LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->lineLeadingBackPt;
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ const AnnotLine * lineann = static_cast<const AnnotLine*>(d->pdfAnnot);
|
|
+ return lineann->getLeaderLineExtension();
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void LineAnnotation::setLineLeadingBackPoint( double point )
|
|
+{
|
|
+ Q_D( LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->lineLeadingBackPt = point;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ AnnotLine *lineann = static_cast<AnnotLine*>(d->pdfAnnot);
|
|
+ lineann->setLeaderLineExtension(point);
|
|
+ }
|
|
+}
|
|
+
|
|
+bool LineAnnotation::lineShowCaption() const
|
|
+{
|
|
+ Q_D( const LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->lineShowCaption;
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ const AnnotLine * lineann = static_cast<const AnnotLine*>(d->pdfAnnot);
|
|
+ return lineann->getCaption();
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+void LineAnnotation::setLineShowCaption( bool show )
|
|
+{
|
|
+ Q_D( LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->lineShowCaption = show;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ AnnotLine *lineann = static_cast<AnnotLine*>(d->pdfAnnot);
|
|
+ lineann->setCaption(show);
|
|
+ }
|
|
+}
|
|
+
|
|
+LineAnnotation::LineIntent LineAnnotation::lineIntent() const
|
|
+{
|
|
+ Q_D( const LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->lineIntent;
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ const AnnotLine * lineann = static_cast<const AnnotLine*>(d->pdfAnnot);
|
|
+ return (LineAnnotation::LineIntent)( lineann->getIntent() + 1 );
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ const AnnotPolygon * polyann = static_cast<const AnnotPolygon*>(d->pdfAnnot);
|
|
+ if ( polyann->getIntent() == AnnotPolygon::polygonCloud )
|
|
+ return LineAnnotation::PolygonCloud;
|
|
+ else // AnnotPolygon::polylineDimension, AnnotPolygon::polygonDimension
|
|
+ return LineAnnotation::Dimension;
|
|
+ }
|
|
+}
|
|
+
|
|
+void LineAnnotation::setLineIntent( LineAnnotation::LineIntent intent )
|
|
+{
|
|
+ Q_D( LineAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->lineIntent = intent;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ( intent == LineAnnotation::Unknown )
|
|
+ return; // Do not set (actually, it should clear the property)
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeLine)
|
|
+ {
|
|
+ AnnotLine * lineann = static_cast<AnnotLine*>(d->pdfAnnot);
|
|
+ lineann->setIntent((AnnotLine::AnnotLineIntent)( intent - 1 ));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ AnnotPolygon * polyann = static_cast<AnnotPolygon*>(d->pdfAnnot);
|
|
+ if ( intent == LineAnnotation::PolygonCloud)
|
|
+ polyann->setIntent( AnnotPolygon::polygonCloud );
|
|
+ else // LineAnnotation::Dimension
|
|
+ {
|
|
+ if ( d->pdfAnnot->getType() == Annot::typePolygon )
|
|
+ polyann->setIntent( AnnotPolygon::polygonDimension );
|
|
+ else // Annot::typePolyLine
|
|
+ polyann->setIntent( AnnotPolygon::polylineDimension );
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+/** GeomAnnotation [Annotation] */
|
|
+class GeomAnnotationPrivate : public AnnotationPrivate
|
|
+{
|
|
+ public:
|
|
+ GeomAnnotationPrivate();
|
|
+ Annotation * makeAlias();
|
|
+ Annot* createNativeAnnot(::Page *destPage, DocumentData *doc);
|
|
+
|
|
+ // data fields (note uses border for rendering style)
|
|
+ GeomAnnotation::GeomType geomType;
|
|
+ QColor geomInnerColor;
|
|
+};
|
|
+
|
|
+GeomAnnotationPrivate::GeomAnnotationPrivate()
|
|
+ : AnnotationPrivate(), geomType( GeomAnnotation::InscribedSquare )
|
|
+{
|
|
+}
|
|
+
|
|
+Annotation * GeomAnnotationPrivate::makeAlias()
|
|
+{
|
|
+ return new GeomAnnotation(*this);
|
|
+}
|
|
+
|
|
+Annot* GeomAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
|
|
+{
|
|
+ // Setters are defined in the public class
|
|
+ GeomAnnotation *q = static_cast<GeomAnnotation*>( makeAlias() );
|
|
+
|
|
+ // Set page and document
|
|
+ pdfPage = destPage;
|
|
+ parentDoc = doc;
|
|
+
|
|
+ Annot::AnnotSubtype type;
|
|
+ if (geomType == GeomAnnotation::InscribedSquare)
|
|
+ type = Annot::typeSquare;
|
|
+ else // GeomAnnotation::InscribedCircle
|
|
+ type = Annot::typeCircle;
|
|
+
|
|
+ // Set pdfAnnot
|
|
+ PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
|
|
+ pdfAnnot = new AnnotGeometry(destPage->getDoc(), &rect, type);
|
|
+
|
|
+ // Set properties
|
|
+ flushBaseAnnotationProperties();
|
|
+ q->setGeomInnerColor(geomInnerColor);
|
|
+
|
|
+ delete q;
|
|
+ return pdfAnnot;
|
|
+}
|
|
+
|
|
+GeomAnnotation::GeomAnnotation()
|
|
+ : Annotation( *new GeomAnnotationPrivate() )
|
|
+{}
|
|
+
|
|
+GeomAnnotation::GeomAnnotation(GeomAnnotationPrivate &dd)
|
|
+ : Annotation( dd )
|
|
+{}
|
|
+
|
|
+GeomAnnotation::GeomAnnotation( const QDomNode & node )
|
|
+ : Annotation( *new GeomAnnotationPrivate(), node )
|
|
+{
|
|
+ // loop through the whole children looking for a 'geom' element
|
|
+ QDomNode subNode = node.firstChild();
|
|
+ while( subNode.isElement() )
|
|
+ {
|
|
+ QDomElement e = subNode.toElement();
|
|
+ subNode = subNode.nextSibling();
|
|
+ if ( e.tagName() != "geom" )
|
|
+ continue;
|
|
+
|
|
+ // parse the attributes
|
|
+ if ( e.hasAttribute( "type" ) )
|
|
+ setGeomType((GeomAnnotation::GeomType)e.attribute( "type" ).toInt());
|
|
+ if ( e.hasAttribute( "color" ) )
|
|
+ setGeomInnerColor(QColor( e.attribute( "color" ) ));
|
|
+
|
|
+ // loading complete
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+GeomAnnotation::~GeomAnnotation()
|
|
+{
|
|
+}
|
|
+
|
|
+void GeomAnnotation::store( QDomNode & node, QDomDocument & document ) const
|
|
+{
|
|
+ // store base annotation properties
|
|
+ storeBaseAnnotationProperties( node, document );
|
|
+
|
|
+ // create [geom] element
|
|
+ QDomElement geomElement = document.createElement( "geom" );
|
|
+ node.appendChild( geomElement );
|
|
+
|
|
+ // append the optional attributes
|
|
+ if ( geomType() != InscribedSquare )
|
|
+ geomElement.setAttribute( "type", (int)geomType() );
|
|
+ if ( geomInnerColor().isValid() )
|
|
+ geomElement.setAttribute( "color", geomInnerColor().name() );
|
|
+}
|
|
+
|
|
+Annotation::SubType GeomAnnotation::subType() const
|
|
+{
|
|
+ return AGeom;
|
|
+}
|
|
+
|
|
+GeomAnnotation::GeomType GeomAnnotation::geomType() const
|
|
+{
|
|
+ Q_D( const GeomAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->geomType;
|
|
+
|
|
+ if (d->pdfAnnot->getType() == Annot::typeSquare)
|
|
+ return GeomAnnotation::InscribedSquare;
|
|
+ else // Annot::typeCircle
|
|
+ return GeomAnnotation::InscribedCircle;
|
|
+}
|
|
+
|
|
+void GeomAnnotation::setGeomType( GeomAnnotation::GeomType type )
|
|
+{
|
|
+ Q_D( GeomAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->geomType = type;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ AnnotGeometry * geomann = static_cast<AnnotGeometry*>(d->pdfAnnot);
|
|
+ if (type == GeomAnnotation::InscribedSquare)
|
|
+ geomann->setType(Annot::typeSquare);
|
|
+ else // GeomAnnotation::InscribedCircle
|
|
+ geomann->setType(Annot::typeCircle);
|
|
+}
|
|
+
|
|
+QColor GeomAnnotation::geomInnerColor() const
|
|
+{
|
|
+ Q_D( const GeomAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->geomInnerColor;
|
|
+
|
|
+ const AnnotGeometry * geomann = static_cast<const AnnotGeometry*>(d->pdfAnnot);
|
|
+ return convertAnnotColor( geomann->getInteriorColor() );
|
|
+}
|
|
+
|
|
+void GeomAnnotation::setGeomInnerColor( const QColor &color )
|
|
+{
|
|
+ Q_D( GeomAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->geomInnerColor = color;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ AnnotGeometry * geomann = static_cast<AnnotGeometry*>(d->pdfAnnot);
|
|
+ geomann->setInteriorColor(convertQColor( color ));
|
|
+}
|
|
+
|
|
+
|
|
+/** HighlightAnnotation [Annotation] */
|
|
+class HighlightAnnotationPrivate : public AnnotationPrivate
|
|
+{
|
|
+ public:
|
|
+ HighlightAnnotationPrivate();
|
|
+ Annotation * makeAlias();
|
|
+ Annot* createNativeAnnot(::Page *destPage, DocumentData *doc);
|
|
+
|
|
+ // data fields
|
|
+ HighlightAnnotation::HighlightType highlightType;
|
|
+ QList< HighlightAnnotation::Quad > highlightQuads; // not empty
|
|
+
|
|
+ // helpers
|
|
+ static Annot::AnnotSubtype toAnnotSubType( HighlightAnnotation::HighlightType type );
|
|
+ QList< HighlightAnnotation::Quad > fromQuadrilaterals(AnnotQuadrilaterals *quads) const;
|
|
+ AnnotQuadrilaterals * toQuadrilaterals(const QList< HighlightAnnotation::Quad > &quads) const;
|
|
+};
|
|
+
|
|
+HighlightAnnotationPrivate::HighlightAnnotationPrivate()
|
|
+ : AnnotationPrivate(), highlightType( HighlightAnnotation::Highlight )
|
|
+{
|
|
+}
|
|
+
|
|
+Annotation * HighlightAnnotationPrivate::makeAlias()
|
|
+{
|
|
+ return new HighlightAnnotation(*this);
|
|
+}
|
|
+
|
|
+Annot::AnnotSubtype HighlightAnnotationPrivate::toAnnotSubType( HighlightAnnotation::HighlightType type )
|
|
+{
|
|
+ switch (type)
|
|
+ {
|
|
+ default: // HighlightAnnotation::Highlight:
|
|
+ return Annot::typeHighlight;
|
|
+ case HighlightAnnotation::Underline:
|
|
+ return Annot::typeUnderline;
|
|
+ case HighlightAnnotation::Squiggly:
|
|
+ return Annot::typeSquiggly;
|
|
+ case HighlightAnnotation::StrikeOut:
|
|
+ return Annot::typeStrikeOut;
|
|
+ }
|
|
+}
|
|
+
|
|
+QList< HighlightAnnotation::Quad > HighlightAnnotationPrivate::fromQuadrilaterals(AnnotQuadrilaterals *hlquads) const
|
|
+{
|
|
+ QList< HighlightAnnotation::Quad > quads;
|
|
+
|
|
+ if ( !hlquads || !hlquads->getQuadrilateralsLength() )
|
|
+ return quads;
|
|
+ const int quadsCount = hlquads->getQuadrilateralsLength();
|
|
+
|
|
+ double MTX[6];
|
|
+ fillTransformationMTX(MTX);
|
|
+
|
|
+ quads.reserve(quadsCount);
|
|
+ for (int q = 0; q < quadsCount; ++q)
|
|
+ {
|
|
+ HighlightAnnotation::Quad quad;
|
|
+ XPDFReader::transform( MTX, hlquads->getX1( q ), hlquads->getY1( q ), quad.points[ 0 ] );
|
|
+ XPDFReader::transform( MTX, hlquads->getX2( q ), hlquads->getY2( q ), quad.points[ 1 ] );
|
|
+ XPDFReader::transform( MTX, hlquads->getX3( q ), hlquads->getY3( q ), quad.points[ 2 ] );
|
|
+ XPDFReader::transform( MTX, hlquads->getX4( q ), hlquads->getY4( q ), quad.points[ 3 ] );
|
|
+ // ### PDF1.6 specs says that point are in ccw order, but in fact
|
|
+ // points 3 and 4 are swapped in every PDF around!
|
|
+ QPointF tmpPoint = quad.points[ 2 ];
|
|
+ quad.points[ 2 ] = quad.points[ 3 ];
|
|
+ quad.points[ 3 ] = tmpPoint;
|
|
+ // initialize other properties and append quad
|
|
+ quad.capStart = true; // unlinked quads are always capped
|
|
+ quad.capEnd = true; // unlinked quads are always capped
|
|
+ quad.feather = 0.1; // default feather
|
|
+ quads.append( quad );
|
|
+ }
|
|
+
|
|
+ return quads;
|
|
+}
|
|
+
|
|
+AnnotQuadrilaterals * HighlightAnnotationPrivate::toQuadrilaterals(const QList< HighlightAnnotation::Quad > &quads) const
|
|
+{
|
|
+ const int count = quads.size();
|
|
+ auto ac = std::make_unique<AnnotQuadrilaterals::AnnotQuadrilateral[]>(count);
|
|
+
|
|
+ double MTX[6];
|
|
+ fillTransformationMTX(MTX);
|
|
+
|
|
+ int pos = 0;
|
|
+ foreach (const HighlightAnnotation::Quad &q, quads)
|
|
+ {
|
|
+ double x1, y1, x2, y2, x3, y3, x4, y4;
|
|
+ XPDFReader::invTransform( MTX, q.points[0], x1, y1 );
|
|
+ XPDFReader::invTransform( MTX, q.points[1], x2, y2 );
|
|
+ // Swap points 3 and 4 (see HighlightAnnotationPrivate::fromQuadrilaterals)
|
|
+ XPDFReader::invTransform( MTX, q.points[3], x3, y3 );
|
|
+ XPDFReader::invTransform( MTX, q.points[2], x4, y4 );
|
|
+ ac[pos++] = AnnotQuadrilaterals::AnnotQuadrilateral(x1, y1, x2, y2, x3, y3, x4, y4);
|
|
+ }
|
|
+
|
|
+ return new AnnotQuadrilaterals(std::move(ac), count);
|
|
+}
|
|
+
|
|
+Annot* HighlightAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
|
|
+{
|
|
+ // Setters are defined in the public class
|
|
+ HighlightAnnotation *q = static_cast<HighlightAnnotation*>( makeAlias() );
|
|
+
|
|
+ // Set page and document
|
|
+ pdfPage = destPage;
|
|
+ parentDoc = doc;
|
|
+
|
|
+ // Set pdfAnnot
|
|
+ PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
|
|
+ pdfAnnot = new AnnotTextMarkup(destPage->getDoc(), &rect, toAnnotSubType(highlightType));
|
|
+
|
|
+ // Set properties
|
|
+ flushBaseAnnotationProperties();
|
|
+ q->setHighlightQuads(highlightQuads);
|
|
+
|
|
+ highlightQuads.clear(); // Free up memory
|
|
+
|
|
+ delete q;
|
|
+
|
|
+ return pdfAnnot;
|
|
+}
|
|
+
|
|
+HighlightAnnotation::HighlightAnnotation()
|
|
+ : Annotation( *new HighlightAnnotationPrivate() )
|
|
+{}
|
|
+
|
|
+HighlightAnnotation::HighlightAnnotation(HighlightAnnotationPrivate &dd)
|
|
+ : Annotation( dd )
|
|
+{}
|
|
+
|
|
+HighlightAnnotation::HighlightAnnotation( const QDomNode & node )
|
|
+ : Annotation( *new HighlightAnnotationPrivate(), node )
|
|
+{
|
|
+ // loop through the whole children looking for a 'hl' element
|
|
+ QDomNode subNode = node.firstChild();
|
|
+ while( subNode.isElement() )
|
|
+ {
|
|
+ QDomElement e = subNode.toElement();
|
|
+ subNode = subNode.nextSibling();
|
|
+ if ( e.tagName() != "hl" )
|
|
+ continue;
|
|
+
|
|
+ // parse the attributes
|
|
+ if ( e.hasAttribute( "type" ) )
|
|
+ setHighlightType((HighlightAnnotation::HighlightType)e.attribute( "type" ).toInt());
|
|
+
|
|
+ // parse all 'quad' subnodes
|
|
+ QList<HighlightAnnotation::Quad> quads;
|
|
+ QDomNode quadNode = e.firstChild();
|
|
+ for ( ; quadNode.isElement(); quadNode = quadNode.nextSibling() )
|
|
+ {
|
|
+ QDomElement qe = quadNode.toElement();
|
|
+ if ( qe.tagName() != "quad" )
|
|
+ continue;
|
|
+
|
|
+ Quad q;
|
|
+ q.points[0].setX(qe.attribute( "ax", "0.0" ).toDouble());
|
|
+ q.points[0].setY(qe.attribute( "ay", "0.0" ).toDouble());
|
|
+ q.points[1].setX(qe.attribute( "bx", "0.0" ).toDouble());
|
|
+ q.points[1].setY(qe.attribute( "by", "0.0" ).toDouble());
|
|
+ q.points[2].setX(qe.attribute( "cx", "0.0" ).toDouble());
|
|
+ q.points[2].setY(qe.attribute( "cy", "0.0" ).toDouble());
|
|
+ q.points[3].setX(qe.attribute( "dx", "0.0" ).toDouble());
|
|
+ q.points[3].setY(qe.attribute( "dy", "0.0" ).toDouble());
|
|
+ q.capStart = qe.hasAttribute( "start" );
|
|
+ q.capEnd = qe.hasAttribute( "end" );
|
|
+ q.feather = qe.attribute( "feather", "0.1" ).toDouble();
|
|
+ quads.append( q );
|
|
+ }
|
|
+ setHighlightQuads(quads);
|
|
+
|
|
+ // loading complete
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+HighlightAnnotation::~HighlightAnnotation()
|
|
+{
|
|
+}
|
|
+
|
|
+void HighlightAnnotation::store( QDomNode & node, QDomDocument & document ) const
|
|
+{
|
|
+ // store base annotation properties
|
|
+ storeBaseAnnotationProperties( node, document );
|
|
+
|
|
+ // create [hl] element
|
|
+ QDomElement hlElement = document.createElement( "hl" );
|
|
+ node.appendChild( hlElement );
|
|
+
|
|
+ // append the optional attributes
|
|
+ if ( highlightType() != Highlight )
|
|
+ hlElement.setAttribute( "type", (int)highlightType() );
|
|
+
|
|
+ const QList<HighlightAnnotation::Quad> quads = highlightQuads();
|
|
+ if ( quads.count() < 1 )
|
|
+ return;
|
|
+ // append highlight quads, all children describe quads
|
|
+ QList< HighlightAnnotation::Quad >::const_iterator it = quads.begin(), end = quads.end();
|
|
+ for ( ; it != end; ++it )
|
|
+ {
|
|
+ QDomElement quadElement = document.createElement( "quad" );
|
|
+ hlElement.appendChild( quadElement );
|
|
+ const Quad & q = *it;
|
|
+ quadElement.setAttribute( "ax", QString::number( q.points[0].x() ) );
|
|
+ quadElement.setAttribute( "ay", QString::number( q.points[0].y() ) );
|
|
+ quadElement.setAttribute( "bx", QString::number( q.points[1].x() ) );
|
|
+ quadElement.setAttribute( "by", QString::number( q.points[1].y() ) );
|
|
+ quadElement.setAttribute( "cx", QString::number( q.points[2].x() ) );
|
|
+ quadElement.setAttribute( "cy", QString::number( q.points[2].y() ) );
|
|
+ quadElement.setAttribute( "dx", QString::number( q.points[3].x() ) );
|
|
+ quadElement.setAttribute( "dy", QString::number( q.points[3].y() ) );
|
|
+ if ( q.capStart )
|
|
+ quadElement.setAttribute( "start", 1 );
|
|
+ if ( q.capEnd )
|
|
+ quadElement.setAttribute( "end", 1 );
|
|
+ quadElement.setAttribute( "feather", QString::number( q.feather ) );
|
|
+ }
|
|
+}
|
|
+
|
|
+Annotation::SubType HighlightAnnotation::subType() const
|
|
+{
|
|
+ return AHighlight;
|
|
+}
|
|
+
|
|
+HighlightAnnotation::HighlightType HighlightAnnotation::highlightType() const
|
|
+{
|
|
+ Q_D( const HighlightAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->highlightType;
|
|
+
|
|
+ Annot::AnnotSubtype subType = d->pdfAnnot->getType();
|
|
+
|
|
+ if ( subType == Annot::typeHighlight )
|
|
+ return HighlightAnnotation::Highlight;
|
|
+ else if ( subType == Annot::typeUnderline )
|
|
+ return HighlightAnnotation::Underline;
|
|
+ else if ( subType == Annot::typeSquiggly )
|
|
+ return HighlightAnnotation::Squiggly;
|
|
+ else // Annot::typeStrikeOut
|
|
+ return HighlightAnnotation::StrikeOut;
|
|
+}
|
|
+
|
|
+void HighlightAnnotation::setHighlightType( HighlightAnnotation::HighlightType type )
|
|
+{
|
|
+ Q_D( HighlightAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->highlightType = type;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ AnnotTextMarkup * hlann = static_cast<AnnotTextMarkup*>(d->pdfAnnot);
|
|
+ hlann->setType(HighlightAnnotationPrivate::toAnnotSubType( type ));
|
|
+}
|
|
+
|
|
+QList< HighlightAnnotation::Quad > HighlightAnnotation::highlightQuads() const
|
|
+{
|
|
+ Q_D( const HighlightAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->highlightQuads;
|
|
+
|
|
+ const AnnotTextMarkup * hlann = static_cast<AnnotTextMarkup*>(d->pdfAnnot);
|
|
+ return d->fromQuadrilaterals( hlann->getQuadrilaterals() );
|
|
+}
|
|
+
|
|
+void HighlightAnnotation::setHighlightQuads( const QList< HighlightAnnotation::Quad > &quads )
|
|
+{
|
|
+ Q_D( HighlightAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->highlightQuads = quads;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ AnnotTextMarkup * hlann = static_cast<AnnotTextMarkup*>(d->pdfAnnot);
|
|
+ AnnotQuadrilaterals * quadrilaterals = d->toQuadrilaterals(quads);
|
|
+ hlann->setQuadrilaterals(quadrilaterals);
|
|
+ delete quadrilaterals;
|
|
+}
|
|
+
|
|
+
|
|
+/** StampAnnotation [Annotation] */
|
|
+class StampAnnotationPrivate : public AnnotationPrivate
|
|
+{
|
|
+ public:
|
|
+ StampAnnotationPrivate();
|
|
+ Annotation * makeAlias();
|
|
+ Annot* createNativeAnnot(::Page *destPage, DocumentData *doc);
|
|
+
|
|
+ // data fields
|
|
+ QString stampIconName;
|
|
+};
|
|
+
|
|
+StampAnnotationPrivate::StampAnnotationPrivate()
|
|
+ : AnnotationPrivate(), stampIconName( "Draft" )
|
|
+{
|
|
+}
|
|
+
|
|
+Annotation * StampAnnotationPrivate::makeAlias()
|
|
+{
|
|
+ return new StampAnnotation(*this);
|
|
+}
|
|
+
|
|
+Annot* StampAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
|
|
+{
|
|
+ StampAnnotation *q = static_cast<StampAnnotation*>( makeAlias() );
|
|
+
|
|
+ // Set page and document
|
|
+ pdfPage = destPage;
|
|
+ parentDoc = doc;
|
|
+
|
|
+ // Set pdfAnnot
|
|
+ PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
|
|
+ pdfAnnot = new AnnotStamp(destPage->getDoc(), &rect);
|
|
+
|
|
+ // Set properties
|
|
+ flushBaseAnnotationProperties();
|
|
+ q->setStampIconName(stampIconName);
|
|
+
|
|
+ delete q;
|
|
+
|
|
+ stampIconName.clear(); // Free up memory
|
|
+
|
|
+ return pdfAnnot;
|
|
+}
|
|
+
|
|
+StampAnnotation::StampAnnotation()
|
|
+ : Annotation( *new StampAnnotationPrivate() )
|
|
+{}
|
|
+
|
|
+StampAnnotation::StampAnnotation(StampAnnotationPrivate &dd)
|
|
+ : Annotation( dd )
|
|
+{}
|
|
+
|
|
+StampAnnotation::StampAnnotation( const QDomNode & node )
|
|
+ : Annotation( *new StampAnnotationPrivate(), node )
|
|
+{
|
|
+ // loop through the whole children looking for a 'stamp' element
|
|
+ QDomNode subNode = node.firstChild();
|
|
+ while( subNode.isElement() )
|
|
+ {
|
|
+ QDomElement e = subNode.toElement();
|
|
+ subNode = subNode.nextSibling();
|
|
+ if ( e.tagName() != "stamp" )
|
|
+ continue;
|
|
+
|
|
+ // parse the attributes
|
|
+ if ( e.hasAttribute( "icon" ) )
|
|
+ setStampIconName(e.attribute( "icon" ));
|
|
+
|
|
+ // loading complete
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+StampAnnotation::~StampAnnotation()
|
|
+{
|
|
+}
|
|
+
|
|
+void StampAnnotation::store( QDomNode & node, QDomDocument & document ) const
|
|
+{
|
|
+ // store base annotation properties
|
|
+ storeBaseAnnotationProperties( node, document );
|
|
+
|
|
+ // create [stamp] element
|
|
+ QDomElement stampElement = document.createElement( "stamp" );
|
|
+ node.appendChild( stampElement );
|
|
+
|
|
+ // append the optional attributes
|
|
+ if ( stampIconName() != "Draft" )
|
|
+ stampElement.setAttribute( "icon", stampIconName() );
|
|
+}
|
|
+
|
|
+Annotation::SubType StampAnnotation::subType() const
|
|
+{
|
|
+ return AStamp;
|
|
+}
|
|
+
|
|
+QString StampAnnotation::stampIconName() const
|
|
+{
|
|
+ Q_D( const StampAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->stampIconName;
|
|
+
|
|
+ const AnnotStamp * stampann = static_cast<const AnnotStamp*>(d->pdfAnnot);
|
|
+ return QString::fromLatin1( stampann->getIcon()->c_str() );
|
|
+}
|
|
+
|
|
+void StampAnnotation::setStampIconName( const QString &name )
|
|
+{
|
|
+ Q_D( StampAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->stampIconName = name;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ AnnotStamp * stampann = static_cast<AnnotStamp*>(d->pdfAnnot);
|
|
+ QByteArray encoded = name.toLatin1();
|
|
+ GooString s(encoded.constData());
|
|
+ stampann->setIcon(&s);
|
|
+}
|
|
+
|
|
+/** InkAnnotation [Annotation] */
|
|
+class InkAnnotationPrivate : public AnnotationPrivate
|
|
+{
|
|
+ public:
|
|
+ InkAnnotationPrivate();
|
|
+ Annotation * makeAlias();
|
|
+ Annot* createNativeAnnot(::Page *destPage, DocumentData *doc);
|
|
+
|
|
+ // data fields
|
|
+ QList< QLinkedList<QPointF> > inkPaths;
|
|
+
|
|
+ // helper
|
|
+ AnnotPath **toAnnotPaths(const QList< QLinkedList<QPointF> > &inkPaths);
|
|
+};
|
|
+
|
|
+InkAnnotationPrivate::InkAnnotationPrivate()
|
|
+ : AnnotationPrivate()
|
|
+{
|
|
+}
|
|
+
|
|
+Annotation * InkAnnotationPrivate::makeAlias()
|
|
+{
|
|
+ return new InkAnnotation(*this);
|
|
+}
|
|
+
|
|
+// Note: Caller is required to delete array elements and the array itself after use
|
|
+AnnotPath **InkAnnotationPrivate::toAnnotPaths(const QList< QLinkedList<QPointF> > &inkPaths)
|
|
+{
|
|
+ const int pathsNumber = inkPaths.size();
|
|
+ AnnotPath **res = new AnnotPath*[pathsNumber];
|
|
+ for (int i = 0; i < pathsNumber; ++i)
|
|
+ res[i] = toAnnotPath( inkPaths[i] );
|
|
+ return res;
|
|
+}
|
|
+
|
|
+Annot* InkAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
|
|
+{
|
|
+ // Setters are defined in the public class
|
|
+ InkAnnotation *q = static_cast<InkAnnotation*>( makeAlias() );
|
|
+
|
|
+ // Set page and document
|
|
+ pdfPage = destPage;
|
|
+ parentDoc = doc;
|
|
+
|
|
+ // Set pdfAnnot
|
|
+ PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
|
|
+ pdfAnnot = new AnnotInk(destPage->getDoc(), &rect);
|
|
+
|
|
+ // Set properties
|
|
+ flushBaseAnnotationProperties();
|
|
+ q->setInkPaths(inkPaths);
|
|
+
|
|
+ inkPaths.clear(); // Free up memory
|
|
+
|
|
+ delete q;
|
|
+
|
|
+ return pdfAnnot;
|
|
+}
|
|
+
|
|
+InkAnnotation::InkAnnotation()
|
|
+ : Annotation( *new InkAnnotationPrivate() )
|
|
+{}
|
|
+
|
|
+InkAnnotation::InkAnnotation(InkAnnotationPrivate &dd)
|
|
+ : Annotation( dd )
|
|
+{}
|
|
+
|
|
+InkAnnotation::InkAnnotation( const QDomNode & node )
|
|
+ : Annotation( *new InkAnnotationPrivate(), node )
|
|
+{
|
|
+ // loop through the whole children looking for a 'ink' element
|
|
+ QDomNode subNode = node.firstChild();
|
|
+ while( subNode.isElement() )
|
|
+ {
|
|
+ QDomElement e = subNode.toElement();
|
|
+ subNode = subNode.nextSibling();
|
|
+ if ( e.tagName() != "ink" )
|
|
+ continue;
|
|
+
|
|
+ // parse the 'path' subnodes
|
|
+ QList< QLinkedList<QPointF> > paths;
|
|
+ QDomNode pathNode = e.firstChild();
|
|
+ while ( pathNode.isElement() )
|
|
+ {
|
|
+ QDomElement pathElement = pathNode.toElement();
|
|
+ pathNode = pathNode.nextSibling();
|
|
+
|
|
+ if ( pathElement.tagName() != "path" )
|
|
+ continue;
|
|
+
|
|
+ // build each path parsing 'point' subnodes
|
|
+ QLinkedList<QPointF> path;
|
|
+ QDomNode pointNode = pathElement.firstChild();
|
|
+ while ( pointNode.isElement() )
|
|
+ {
|
|
+ QDomElement pointElement = pointNode.toElement();
|
|
+ pointNode = pointNode.nextSibling();
|
|
+
|
|
+ if ( pointElement.tagName() != "point" )
|
|
+ continue;
|
|
+
|
|
+ QPointF p(pointElement.attribute( "x", "0.0" ).toDouble(), pointElement.attribute( "y", "0.0" ).toDouble());
|
|
+ path.append( p );
|
|
+ }
|
|
+
|
|
+ // add the path to the path list if it contains at least 2 nodes
|
|
+ if ( path.count() >= 2 )
|
|
+ paths.append( path );
|
|
+ }
|
|
+ setInkPaths(paths);
|
|
+
|
|
+ // loading complete
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+InkAnnotation::~InkAnnotation()
|
|
+{
|
|
+}
|
|
+
|
|
+void InkAnnotation::store( QDomNode & node, QDomDocument & document ) const
|
|
+{
|
|
+ // store base annotation properties
|
|
+ storeBaseAnnotationProperties( node, document );
|
|
+
|
|
+ // create [ink] element
|
|
+ QDomElement inkElement = document.createElement( "ink" );
|
|
+ node.appendChild( inkElement );
|
|
+
|
|
+ // append the optional attributes
|
|
+ const QList< QLinkedList<QPointF> > paths = inkPaths();
|
|
+ if ( paths.count() < 1 )
|
|
+ return;
|
|
+ QList< QLinkedList<QPointF> >::const_iterator pIt = paths.begin(), pEnd = paths.end();
|
|
+ for ( ; pIt != pEnd; ++pIt )
|
|
+ {
|
|
+ QDomElement pathElement = document.createElement( "path" );
|
|
+ inkElement.appendChild( pathElement );
|
|
+ const QLinkedList<QPointF> & path = *pIt;
|
|
+ QLinkedList<QPointF>::const_iterator iIt = path.begin(), iEnd = path.end();
|
|
+ for ( ; iIt != iEnd; ++iIt )
|
|
+ {
|
|
+ const QPointF & point = *iIt;
|
|
+ QDomElement pointElement = document.createElement( "point" );
|
|
+ pathElement.appendChild( pointElement );
|
|
+ pointElement.setAttribute( "x", QString::number( point.x() ) );
|
|
+ pointElement.setAttribute( "y", QString::number( point.y() ) );
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+Annotation::SubType InkAnnotation::subType() const
|
|
+{
|
|
+ return AInk;
|
|
+}
|
|
+
|
|
+QList< QLinkedList<QPointF> > InkAnnotation::inkPaths() const
|
|
+{
|
|
+ Q_D( const InkAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->inkPaths;
|
|
+
|
|
+ const AnnotInk * inkann = static_cast<const AnnotInk *>(d->pdfAnnot);
|
|
+
|
|
+ const AnnotPath * const* paths = inkann->getInkList();
|
|
+ if ( !paths || !inkann->getInkListLength() )
|
|
+ return QList< QLinkedList<QPointF> >();
|
|
+
|
|
+ double MTX[6];
|
|
+ d->fillTransformationMTX(MTX);
|
|
+
|
|
+ const int pathsNumber = inkann->getInkListLength();
|
|
+ QList< QLinkedList<QPointF> > inkPaths;
|
|
+ inkPaths.reserve(pathsNumber);
|
|
+ for (int m = 0; m < pathsNumber; ++m)
|
|
+ {
|
|
+ // transform each path in a list of normalized points ..
|
|
+ QLinkedList<QPointF> localList;
|
|
+ const AnnotPath * path = paths[ m ];
|
|
+ const int pointsNumber = path ? path->getCoordsLength() : 0;
|
|
+ for (int n = 0; n < pointsNumber; ++n)
|
|
+ {
|
|
+ QPointF point;
|
|
+ XPDFReader::transform(MTX, path->getX(n), path->getY(n), point);
|
|
+ localList.append(point);
|
|
+ }
|
|
+ // ..and add it to the annotation
|
|
+ inkPaths.append( localList );
|
|
+ }
|
|
+ return inkPaths;
|
|
+}
|
|
+
|
|
+void InkAnnotation::setInkPaths( const QList< QLinkedList<QPointF> > &paths )
|
|
+{
|
|
+ Q_D( InkAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->inkPaths = paths;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ AnnotInk * inkann = static_cast<AnnotInk*>(d->pdfAnnot);
|
|
+ AnnotPath **annotpaths = d->toAnnotPaths(paths);
|
|
+ const int pathsNumber = paths.size();
|
|
+ inkann->setInkList(annotpaths, pathsNumber);
|
|
+
|
|
+ for (int i = 0; i < pathsNumber; ++i)
|
|
+ delete annotpaths[i];
|
|
+ delete[] annotpaths;
|
|
+}
|
|
+
|
|
+
|
|
+/** LinkAnnotation [Annotation] */
|
|
+class LinkAnnotationPrivate : public AnnotationPrivate
|
|
+{
|
|
+ public:
|
|
+ LinkAnnotationPrivate();
|
|
+ ~LinkAnnotationPrivate();
|
|
+ Annotation * makeAlias();
|
|
+ Annot* createNativeAnnot(::Page *destPage, DocumentData *doc);
|
|
+
|
|
+ // data fields
|
|
+ Link * linkDestination;
|
|
+ LinkAnnotation::HighlightMode linkHLMode;
|
|
+ QPointF linkRegion[4];
|
|
+};
|
|
+
|
|
+LinkAnnotationPrivate::LinkAnnotationPrivate()
|
|
+ : AnnotationPrivate(), linkDestination( nullptr ), linkHLMode( LinkAnnotation::Invert )
|
|
+{
|
|
+}
|
|
+
|
|
+LinkAnnotationPrivate::~LinkAnnotationPrivate()
|
|
+{
|
|
+ delete linkDestination;
|
|
+}
|
|
+
|
|
+Annotation * LinkAnnotationPrivate::makeAlias()
|
|
+{
|
|
+ return new LinkAnnotation(*this);
|
|
+}
|
|
+
|
|
+Annot* LinkAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
|
|
+{
|
|
+ return nullptr; // Not implemented
|
|
+}
|
|
+
|
|
+LinkAnnotation::LinkAnnotation()
|
|
+ : Annotation( *new LinkAnnotationPrivate() )
|
|
+{}
|
|
+
|
|
+LinkAnnotation::LinkAnnotation(LinkAnnotationPrivate &dd)
|
|
+ : Annotation( dd )
|
|
+{}
|
|
+
|
|
+LinkAnnotation::LinkAnnotation( const QDomNode & node )
|
|
+ : Annotation( *new LinkAnnotationPrivate(), node )
|
|
+{
|
|
+ // loop through the whole children looking for a 'link' element
|
|
+ QDomNode subNode = node.firstChild();
|
|
+ while( subNode.isElement() )
|
|
+ {
|
|
+ QDomElement e = subNode.toElement();
|
|
+ subNode = subNode.nextSibling();
|
|
+ if ( e.tagName() != "link" )
|
|
+ continue;
|
|
+
|
|
+ // parse the attributes
|
|
+ if ( e.hasAttribute( "hlmode" ) )
|
|
+ setLinkHighlightMode((LinkAnnotation::HighlightMode)e.attribute( "hlmode" ).toInt());
|
|
+
|
|
+ // parse all 'quad' subnodes
|
|
+ QDomNode quadNode = e.firstChild();
|
|
+ for ( ; quadNode.isElement(); quadNode = quadNode.nextSibling() )
|
|
+ {
|
|
+ QDomElement qe = quadNode.toElement();
|
|
+ if ( qe.tagName() == "quad" )
|
|
+ {
|
|
+ setLinkRegionPoint(0, QPointF(qe.attribute( "ax", "0.0" ).toDouble(),
|
|
+ qe.attribute( "ay", "0.0" ).toDouble()));
|
|
+ setLinkRegionPoint(1, QPointF(qe.attribute( "bx", "0.0" ).toDouble(),
|
|
+ qe.attribute( "by", "0.0" ).toDouble()));
|
|
+ setLinkRegionPoint(2, QPointF(qe.attribute( "cx", "0.0" ).toDouble(),
|
|
+ qe.attribute( "cy", "0.0" ).toDouble()));
|
|
+ setLinkRegionPoint(3, QPointF(qe.attribute( "dx", "0.0" ).toDouble(),
|
|
+ qe.attribute( "dy", "0.0" ).toDouble()));
|
|
+ }
|
|
+ else if ( qe.tagName() == "link" )
|
|
+ {
|
|
+ QString type = qe.attribute( "type" );
|
|
+ if ( type == "GoTo" )
|
|
+ {
|
|
+ Poppler::LinkGoto * go = new Poppler::LinkGoto( QRect(), qe.attribute( "filename" ), LinkDestination( qe.attribute( "destination" ) ) );
|
|
+ setLinkDestination(go);
|
|
+ }
|
|
+ else if ( type == "Exec" )
|
|
+ {
|
|
+ Poppler::LinkExecute * exec = new Poppler::LinkExecute( QRect(), qe.attribute( "filename" ), qe.attribute( "parameters" ) );
|
|
+ setLinkDestination(exec);
|
|
+ }
|
|
+ else if ( type == "Browse" )
|
|
+ {
|
|
+ Poppler::LinkBrowse * browse = new Poppler::LinkBrowse( QRect(), qe.attribute( "url" ) );
|
|
+ setLinkDestination(browse);
|
|
+ }
|
|
+ else if ( type == "Action" )
|
|
+ {
|
|
+ Poppler::LinkAction::ActionType act;
|
|
+ QString actString = qe.attribute( "action" );
|
|
+ bool found = true;
|
|
+ if ( actString == "PageFirst" )
|
|
+ act = Poppler::LinkAction::PageFirst;
|
|
+ else if ( actString == "PagePrev" )
|
|
+ act = Poppler::LinkAction::PagePrev;
|
|
+ else if ( actString == "PageNext" )
|
|
+ act = Poppler::LinkAction::PageNext;
|
|
+ else if ( actString == "PageLast" )
|
|
+ act = Poppler::LinkAction::PageLast;
|
|
+ else if ( actString == "HistoryBack" )
|
|
+ act = Poppler::LinkAction::HistoryBack;
|
|
+ else if ( actString == "HistoryForward" )
|
|
+ act = Poppler::LinkAction::HistoryForward;
|
|
+ else if ( actString == "Quit" )
|
|
+ act = Poppler::LinkAction::Quit;
|
|
+ else if ( actString == "Presentation" )
|
|
+ act = Poppler::LinkAction::Presentation;
|
|
+ else if ( actString == "EndPresentation" )
|
|
+ act = Poppler::LinkAction::EndPresentation;
|
|
+ else if ( actString == "Find" )
|
|
+ act = Poppler::LinkAction::Find;
|
|
+ else if ( actString == "GoToPage" )
|
|
+ act = Poppler::LinkAction::GoToPage;
|
|
+ else if ( actString == "Close" )
|
|
+ act = Poppler::LinkAction::Close;
|
|
+ else if ( actString == "Print" )
|
|
+ act = Poppler::LinkAction::Print;
|
|
+ else
|
|
+ found = false;
|
|
+ if (found)
|
|
+ {
|
|
+ Poppler::LinkAction * action = new Poppler::LinkAction( QRect(), act );
|
|
+ setLinkDestination(action);
|
|
+ }
|
|
+ }
|
|
+#if 0
|
|
+ else if ( type == "Movie" )
|
|
+ {
|
|
+ Poppler::LinkMovie * movie = new Poppler::LinkMovie( QRect() );
|
|
+ setLinkDestination(movie);
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // loading complete
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+LinkAnnotation::~LinkAnnotation()
|
|
+{
|
|
+}
|
|
+
|
|
+void LinkAnnotation::store( QDomNode & node, QDomDocument & document ) const
|
|
+{
|
|
+ // store base annotation properties
|
|
+ storeBaseAnnotationProperties( node, document );
|
|
+
|
|
+ // create [hl] element
|
|
+ QDomElement linkElement = document.createElement( "link" );
|
|
+ node.appendChild( linkElement );
|
|
+
|
|
+ // append the optional attributes
|
|
+ if ( linkHighlightMode() != Invert )
|
|
+ linkElement.setAttribute( "hlmode", (int)linkHighlightMode() );
|
|
+
|
|
+ // saving region
|
|
+ QDomElement quadElement = document.createElement( "quad" );
|
|
+ linkElement.appendChild( quadElement );
|
|
+ quadElement.setAttribute( "ax", QString::number( linkRegionPoint(0).x() ) );
|
|
+ quadElement.setAttribute( "ay", QString::number( linkRegionPoint(0).y() ) );
|
|
+ quadElement.setAttribute( "bx", QString::number( linkRegionPoint(1).x() ) );
|
|
+ quadElement.setAttribute( "by", QString::number( linkRegionPoint(1).y() ) );
|
|
+ quadElement.setAttribute( "cx", QString::number( linkRegionPoint(2).x() ) );
|
|
+ quadElement.setAttribute( "cy", QString::number( linkRegionPoint(2).y() ) );
|
|
+ quadElement.setAttribute( "dx", QString::number( linkRegionPoint(3).x() ) );
|
|
+ quadElement.setAttribute( "dy", QString::number( linkRegionPoint(3).y() ) );
|
|
+
|
|
+ // saving link
|
|
+ QDomElement hyperlinkElement = document.createElement( "link" );
|
|
+ linkElement.appendChild( hyperlinkElement );
|
|
+ if ( linkDestination() )
|
|
+ {
|
|
+ switch( linkDestination()->linkType() )
|
|
+ {
|
|
+ case Poppler::Link::Goto:
|
|
+ {
|
|
+ Poppler::LinkGoto * go = static_cast< Poppler::LinkGoto * >( linkDestination() );
|
|
+ hyperlinkElement.setAttribute( "type", "GoTo" );
|
|
+ hyperlinkElement.setAttribute( "filename", go->fileName() );
|
|
+ hyperlinkElement.setAttribute( "destionation", go->destination().toString() ); // TODO Remove for poppler 0.28
|
|
+ hyperlinkElement.setAttribute( "destination", go->destination().toString() );
|
|
+ break;
|
|
+ }
|
|
+ case Poppler::Link::Execute:
|
|
+ {
|
|
+ Poppler::LinkExecute * exec = static_cast< Poppler::LinkExecute * >( linkDestination() );
|
|
+ hyperlinkElement.setAttribute( "type", "Exec" );
|
|
+ hyperlinkElement.setAttribute( "filename", exec->fileName() );
|
|
+ hyperlinkElement.setAttribute( "parameters", exec->parameters() );
|
|
+ break;
|
|
+ }
|
|
+ case Poppler::Link::Browse:
|
|
+ {
|
|
+ Poppler::LinkBrowse * browse = static_cast< Poppler::LinkBrowse * >( linkDestination() );
|
|
+ hyperlinkElement.setAttribute( "type", "Browse" );
|
|
+ hyperlinkElement.setAttribute( "url", browse->url() );
|
|
+ break;
|
|
+ }
|
|
+ case Poppler::Link::Action:
|
|
+ {
|
|
+ Poppler::LinkAction * action = static_cast< Poppler::LinkAction * >( linkDestination() );
|
|
+ hyperlinkElement.setAttribute( "type", "Action" );
|
|
+ switch ( action->actionType() )
|
|
+ {
|
|
+ case Poppler::LinkAction::PageFirst:
|
|
+ hyperlinkElement.setAttribute( "action", "PageFirst" );
|
|
+ break;
|
|
+ case Poppler::LinkAction::PagePrev:
|
|
+ hyperlinkElement.setAttribute( "action", "PagePrev" );
|
|
+ break;
|
|
+ case Poppler::LinkAction::PageNext:
|
|
+ hyperlinkElement.setAttribute( "action", "PageNext" );
|
|
+ break;
|
|
+ case Poppler::LinkAction::PageLast:
|
|
+ hyperlinkElement.setAttribute( "action", "PageLast" );
|
|
+ break;
|
|
+ case Poppler::LinkAction::HistoryBack:
|
|
+ hyperlinkElement.setAttribute( "action", "HistoryBack" );
|
|
+ break;
|
|
+ case Poppler::LinkAction::HistoryForward:
|
|
+ hyperlinkElement.setAttribute( "action", "HistoryForward" );
|
|
+ break;
|
|
+ case Poppler::LinkAction::Quit:
|
|
+ hyperlinkElement.setAttribute( "action", "Quit" );
|
|
+ break;
|
|
+ case Poppler::LinkAction::Presentation:
|
|
+ hyperlinkElement.setAttribute( "action", "Presentation" );
|
|
+ break;
|
|
+ case Poppler::LinkAction::EndPresentation:
|
|
+ hyperlinkElement.setAttribute( "action", "EndPresentation" );
|
|
+ break;
|
|
+ case Poppler::LinkAction::Find:
|
|
+ hyperlinkElement.setAttribute( "action", "Find" );
|
|
+ break;
|
|
+ case Poppler::LinkAction::GoToPage:
|
|
+ hyperlinkElement.setAttribute( "action", "GoToPage" );
|
|
+ break;
|
|
+ case Poppler::LinkAction::Close:
|
|
+ hyperlinkElement.setAttribute( "action", "Close" );
|
|
+ break;
|
|
+ case Poppler::LinkAction::Print:
|
|
+ hyperlinkElement.setAttribute( "action", "Print" );
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ case Poppler::Link::Movie:
|
|
+ {
|
|
+ hyperlinkElement.setAttribute( "type", "Movie" );
|
|
+ break;
|
|
+ }
|
|
+ case Poppler::Link::Rendition:
|
|
+ {
|
|
+ hyperlinkElement.setAttribute( "type", "Rendition" );
|
|
+ break;
|
|
+ }
|
|
+ case Poppler::Link::Sound:
|
|
+ {
|
|
+ // FIXME: implement me
|
|
+ break;
|
|
+ }
|
|
+ case Poppler::Link::None:
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+Annotation::SubType LinkAnnotation::subType() const
|
|
+{
|
|
+ return ALink;
|
|
+}
|
|
+
|
|
+Link* LinkAnnotation::linkDestination() const
|
|
+{
|
|
+ Q_D( const LinkAnnotation );
|
|
+ return d->linkDestination;
|
|
+}
|
|
+
|
|
+void LinkAnnotation::setLinkDestination( Link *link )
|
|
+{
|
|
+ Q_D( LinkAnnotation );
|
|
+ delete d->linkDestination;
|
|
+ d->linkDestination = link;
|
|
+}
|
|
+
|
|
+LinkAnnotation::HighlightMode LinkAnnotation::linkHighlightMode() const
|
|
+{
|
|
+ Q_D( const LinkAnnotation );
|
|
+ return d->linkHLMode;
|
|
+}
|
|
+
|
|
+void LinkAnnotation::setLinkHighlightMode( LinkAnnotation::HighlightMode mode )
|
|
+{
|
|
+ Q_D( LinkAnnotation );
|
|
+ d->linkHLMode = mode;
|
|
+}
|
|
+
|
|
+QPointF LinkAnnotation::linkRegionPoint( int id ) const
|
|
+{
|
|
+ if ( id < 0 || id >= 4 )
|
|
+ return QPointF();
|
|
+
|
|
+ Q_D( const LinkAnnotation );
|
|
+ return d->linkRegion[id];
|
|
+}
|
|
+
|
|
+void LinkAnnotation::setLinkRegionPoint( int id, const QPointF &point )
|
|
+{
|
|
+ if ( id < 0 || id >= 4 )
|
|
+ return;
|
|
+
|
|
+ Q_D( LinkAnnotation );
|
|
+ d->linkRegion[id] = point;
|
|
+}
|
|
+
|
|
+/** CaretAnnotation [Annotation] */
|
|
+class CaretAnnotationPrivate : public AnnotationPrivate
|
|
+{
|
|
+ public:
|
|
+ CaretAnnotationPrivate();
|
|
+ Annotation * makeAlias();
|
|
+ Annot* createNativeAnnot(::Page *destPage, DocumentData *doc);
|
|
+
|
|
+ // data fields
|
|
+ CaretAnnotation::CaretSymbol symbol;
|
|
+};
|
|
+
|
|
+static QString caretSymbolToString( CaretAnnotation::CaretSymbol symbol )
|
|
+{
|
|
+ switch ( symbol )
|
|
+ {
|
|
+ case CaretAnnotation::None:
|
|
+ return QString::fromLatin1( "None" );
|
|
+ case CaretAnnotation::P:
|
|
+ return QString::fromLatin1( "P" );
|
|
+ }
|
|
+ return QString();
|
|
+}
|
|
+
|
|
+static CaretAnnotation::CaretSymbol caretSymbolFromString( const QString &symbol )
|
|
+{
|
|
+ if ( symbol == QLatin1String( "None" ) )
|
|
+ return CaretAnnotation::None;
|
|
+ else if ( symbol == QLatin1String( "P" ) )
|
|
+ return CaretAnnotation::P;
|
|
+ return CaretAnnotation::None;
|
|
+}
|
|
+
|
|
+CaretAnnotationPrivate::CaretAnnotationPrivate()
|
|
+ : AnnotationPrivate(), symbol( CaretAnnotation::None )
|
|
+{
|
|
+}
|
|
+
|
|
+Annotation * CaretAnnotationPrivate::makeAlias()
|
|
+{
|
|
+ return new CaretAnnotation(*this);
|
|
+}
|
|
+
|
|
+Annot* CaretAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
|
|
+{
|
|
+ // Setters are defined in the public class
|
|
+ CaretAnnotation *q = static_cast<CaretAnnotation*>( makeAlias() );
|
|
+
|
|
+ // Set page and document
|
|
+ pdfPage = destPage;
|
|
+ parentDoc = doc;
|
|
+
|
|
+ // Set pdfAnnot
|
|
+ PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
|
|
+ pdfAnnot = new AnnotCaret(destPage->getDoc(), &rect);
|
|
+
|
|
+ // Set properties
|
|
+ flushBaseAnnotationProperties();
|
|
+ q->setCaretSymbol(symbol);
|
|
+
|
|
+ delete q;
|
|
+ return pdfAnnot;
|
|
+}
|
|
+
|
|
+CaretAnnotation::CaretAnnotation()
|
|
+ : Annotation( *new CaretAnnotationPrivate() )
|
|
+{
|
|
+}
|
|
+
|
|
+CaretAnnotation::CaretAnnotation(CaretAnnotationPrivate &dd)
|
|
+ : Annotation( dd )
|
|
+{
|
|
+}
|
|
+
|
|
+CaretAnnotation::CaretAnnotation( const QDomNode & node )
|
|
+ : Annotation( *new CaretAnnotationPrivate(), node )
|
|
+{
|
|
+ // loop through the whole children looking for a 'caret' element
|
|
+ QDomNode subNode = node.firstChild();
|
|
+ while( subNode.isElement() )
|
|
+ {
|
|
+ QDomElement e = subNode.toElement();
|
|
+ subNode = subNode.nextSibling();
|
|
+ if ( e.tagName() != "caret" )
|
|
+ continue;
|
|
+
|
|
+ // parse the attributes
|
|
+ if ( e.hasAttribute( "symbol" ) )
|
|
+ setCaretSymbol(caretSymbolFromString( e.attribute( "symbol" ) ));
|
|
+
|
|
+ // loading complete
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+CaretAnnotation::~CaretAnnotation()
|
|
+{
|
|
+}
|
|
+
|
|
+void CaretAnnotation::store( QDomNode & node, QDomDocument & document ) const
|
|
+{
|
|
+ // store base annotation properties
|
|
+ storeBaseAnnotationProperties( node, document );
|
|
+
|
|
+ // create [caret] element
|
|
+ QDomElement caretElement = document.createElement( "caret" );
|
|
+ node.appendChild( caretElement );
|
|
+
|
|
+ // append the optional attributes
|
|
+ if ( caretSymbol() != CaretAnnotation::None )
|
|
+ caretElement.setAttribute( "symbol", caretSymbolToString( caretSymbol() ) );
|
|
+}
|
|
+
|
|
+Annotation::SubType CaretAnnotation::subType() const
|
|
+{
|
|
+ return ACaret;
|
|
+}
|
|
+
|
|
+CaretAnnotation::CaretSymbol CaretAnnotation::caretSymbol() const
|
|
+{
|
|
+ Q_D( const CaretAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ return d->symbol;
|
|
+
|
|
+ const AnnotCaret * caretann = static_cast<const AnnotCaret *>(d->pdfAnnot);
|
|
+ return (CaretAnnotation::CaretSymbol)caretann->getSymbol();
|
|
+}
|
|
+
|
|
+void CaretAnnotation::setCaretSymbol( CaretAnnotation::CaretSymbol symbol )
|
|
+{
|
|
+ Q_D( CaretAnnotation );
|
|
+
|
|
+ if (!d->pdfAnnot)
|
|
+ {
|
|
+ d->symbol = symbol;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ AnnotCaret * caretann = static_cast<AnnotCaret *>(d->pdfAnnot);
|
|
+ caretann->setSymbol((AnnotCaret::AnnotCaretSymbol)symbol);
|
|
+}
|
|
+
|
|
+/** FileAttachmentAnnotation [Annotation] */
|
|
+class FileAttachmentAnnotationPrivate : public AnnotationPrivate
|
|
+{
|
|
+ public:
|
|
+ FileAttachmentAnnotationPrivate();
|
|
+ ~FileAttachmentAnnotationPrivate();
|
|
+ Annotation * makeAlias();
|
|
+ Annot* createNativeAnnot(::Page *destPage, DocumentData *doc);
|
|
+
|
|
+ // data fields
|
|
+ QString icon;
|
|
+ EmbeddedFile *embfile;
|
|
+};
|
|
+
|
|
+FileAttachmentAnnotationPrivate::FileAttachmentAnnotationPrivate()
|
|
+ : AnnotationPrivate(), icon( "PushPin" ), embfile( nullptr )
|
|
+{
|
|
+}
|
|
+
|
|
+FileAttachmentAnnotationPrivate::~FileAttachmentAnnotationPrivate()
|
|
+{
|
|
+ delete embfile;
|
|
+}
|
|
+
|
|
+Annotation * FileAttachmentAnnotationPrivate::makeAlias()
|
|
+{
|
|
+ return new FileAttachmentAnnotation(*this);
|
|
+}
|
|
+
|
|
+Annot* FileAttachmentAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
|
|
+{
|
|
+ return nullptr; // Not implemented
|
|
+}
|
|
+
|
|
+FileAttachmentAnnotation::FileAttachmentAnnotation()
|
|
+ : Annotation( *new FileAttachmentAnnotationPrivate() )
|
|
+{
|
|
+}
|
|
+
|
|
+FileAttachmentAnnotation::FileAttachmentAnnotation(FileAttachmentAnnotationPrivate &dd)
|
|
+ : Annotation( dd )
|
|
+{
|
|
+}
|
|
+
|
|
+FileAttachmentAnnotation::FileAttachmentAnnotation( const QDomNode & node )
|
|
+ : Annotation( *new FileAttachmentAnnotationPrivate(), node )
|
|
+{
|
|
+ // loop through the whole children looking for a 'fileattachment' element
|
|
+ QDomNode subNode = node.firstChild();
|
|
+ while( subNode.isElement() )
|
|
+ {
|
|
+ QDomElement e = subNode.toElement();
|
|
+ subNode = subNode.nextSibling();
|
|
+ if ( e.tagName() != "fileattachment" )
|
|
+ continue;
|
|
+
|
|
+ // loading complete
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+FileAttachmentAnnotation::~FileAttachmentAnnotation()
|
|
+{
|
|
+}
|
|
+
|
|
+void FileAttachmentAnnotation::store( QDomNode & node, QDomDocument & document ) const
|
|
+{
|
|
+ // store base annotation properties
|
|
+ storeBaseAnnotationProperties( node, document );
|
|
+
|
|
+ // create [fileattachment] element
|
|
+ QDomElement fileAttachmentElement = document.createElement( "fileattachment" );
|
|
+ node.appendChild( fileAttachmentElement );
|
|
+}
|
|
+
|
|
+Annotation::SubType FileAttachmentAnnotation::subType() const
|
|
+{
|
|
+ return AFileAttachment;
|
|
+}
|
|
+
|
|
+QString FileAttachmentAnnotation::fileIconName() const
|
|
+{
|
|
+ Q_D( const FileAttachmentAnnotation );
|
|
+ return d->icon;
|
|
+}
|
|
+
|
|
+void FileAttachmentAnnotation::setFileIconName( const QString &icon )
|
|
+{
|
|
+ Q_D( FileAttachmentAnnotation );
|
|
+ d->icon = icon;
|
|
+}
|
|
+
|
|
+EmbeddedFile* FileAttachmentAnnotation::embeddedFile() const
|
|
+{
|
|
+ Q_D( const FileAttachmentAnnotation );
|
|
+ return d->embfile;
|
|
+}
|
|
+
|
|
+void FileAttachmentAnnotation::setEmbeddedFile( EmbeddedFile *ef )
|
|
+{
|
|
+ Q_D( FileAttachmentAnnotation );
|
|
+ d->embfile = ef;
|
|
+}
|
|
+
|
|
+/** SoundAnnotation [Annotation] */
|
|
+class SoundAnnotationPrivate : public AnnotationPrivate
|
|
+{
|
|
+ public:
|
|
+ SoundAnnotationPrivate();
|
|
+ ~SoundAnnotationPrivate();
|
|
+ Annotation * makeAlias();
|
|
+ Annot* createNativeAnnot(::Page *destPage, DocumentData *doc);
|
|
+
|
|
+ // data fields
|
|
+ QString icon;
|
|
+ SoundObject *sound;
|
|
+};
|
|
+
|
|
+SoundAnnotationPrivate::SoundAnnotationPrivate()
|
|
+ : AnnotationPrivate(), icon( "Speaker" ), sound( nullptr )
|
|
+{
|
|
+}
|
|
+
|
|
+SoundAnnotationPrivate::~SoundAnnotationPrivate()
|
|
+{
|
|
+ delete sound;
|
|
+}
|
|
+
|
|
+Annotation * SoundAnnotationPrivate::makeAlias()
|
|
+{
|
|
+ return new SoundAnnotation(*this);
|
|
+}
|
|
+
|
|
+Annot* SoundAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
|
|
+{
|
|
+ return nullptr; // Not implemented
|
|
+}
|
|
+
|
|
+SoundAnnotation::SoundAnnotation()
|
|
+ : Annotation( *new SoundAnnotationPrivate() )
|
|
+{
|
|
+}
|
|
+
|
|
+SoundAnnotation::SoundAnnotation(SoundAnnotationPrivate &dd)
|
|
+ : Annotation( dd )
|
|
+{
|
|
+}
|
|
+
|
|
+SoundAnnotation::SoundAnnotation( const QDomNode & node )
|
|
+ : Annotation( *new SoundAnnotationPrivate(), node )
|
|
+{
|
|
+ // loop through the whole children looking for a 'sound' element
|
|
+ QDomNode subNode = node.firstChild();
|
|
+ while( subNode.isElement() )
|
|
+ {
|
|
+ QDomElement e = subNode.toElement();
|
|
+ subNode = subNode.nextSibling();
|
|
+ if ( e.tagName() != "sound" )
|
|
+ continue;
|
|
+
|
|
+ // loading complete
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+SoundAnnotation::~SoundAnnotation()
|
|
+{
|
|
+}
|
|
+
|
|
+void SoundAnnotation::store( QDomNode & node, QDomDocument & document ) const
|
|
+{
|
|
+ // store base annotation properties
|
|
+ storeBaseAnnotationProperties( node, document );
|
|
+
|
|
+ // create [sound] element
|
|
+ QDomElement soundElement = document.createElement( "sound" );
|
|
+ node.appendChild( soundElement );
|
|
+}
|
|
+
|
|
+Annotation::SubType SoundAnnotation::subType() const
|
|
+{
|
|
+ return ASound;
|
|
+}
|
|
+
|
|
+QString SoundAnnotation::soundIconName() const
|
|
+{
|
|
+ Q_D( const SoundAnnotation );
|
|
+ return d->icon;
|
|
+}
|
|
+
|
|
+void SoundAnnotation::setSoundIconName( const QString &icon )
|
|
+{
|
|
+ Q_D( SoundAnnotation );
|
|
+ d->icon = icon;
|
|
+}
|
|
+
|
|
+SoundObject* SoundAnnotation::sound() const
|
|
+{
|
|
+ Q_D( const SoundAnnotation );
|
|
+ return d->sound;
|
|
+}
|
|
+
|
|
+void SoundAnnotation::setSound( SoundObject *s )
|
|
+{
|
|
+ Q_D( SoundAnnotation );
|
|
+ d->sound = s;
|
|
+}
|
|
+
|
|
+/** MovieAnnotation [Annotation] */
|
|
+class MovieAnnotationPrivate : public AnnotationPrivate
|
|
+{
|
|
+ public:
|
|
+ MovieAnnotationPrivate();
|
|
+ ~MovieAnnotationPrivate();
|
|
+ Annotation * makeAlias();
|
|
+ Annot* createNativeAnnot(::Page *destPage, DocumentData *doc);
|
|
+
|
|
+ // data fields
|
|
+ MovieObject *movie;
|
|
+ QString title;
|
|
+};
|
|
+
|
|
+MovieAnnotationPrivate::MovieAnnotationPrivate()
|
|
+ : AnnotationPrivate(), movie( nullptr )
|
|
+{
|
|
+}
|
|
+
|
|
+MovieAnnotationPrivate::~MovieAnnotationPrivate()
|
|
+{
|
|
+ delete movie;
|
|
+}
|
|
+
|
|
+Annotation * MovieAnnotationPrivate::makeAlias()
|
|
+{
|
|
+ return new MovieAnnotation(*this);
|
|
+}
|
|
+
|
|
+Annot* MovieAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
|
|
+{
|
|
+ return nullptr; // Not implemented
|
|
+}
|
|
+
|
|
+MovieAnnotation::MovieAnnotation()
|
|
+ : Annotation( *new MovieAnnotationPrivate() )
|
|
+{
|
|
+}
|
|
+
|
|
+MovieAnnotation::MovieAnnotation(MovieAnnotationPrivate &dd)
|
|
+ : Annotation( dd )
|
|
+{
|
|
+}
|
|
+
|
|
+MovieAnnotation::MovieAnnotation( const QDomNode & node )
|
|
+ : Annotation( *new MovieAnnotationPrivate(), node )
|
|
+{
|
|
+ // loop through the whole children looking for a 'movie' element
|
|
+ QDomNode subNode = node.firstChild();
|
|
+ while( subNode.isElement() )
|
|
+ {
|
|
+ QDomElement e = subNode.toElement();
|
|
+ subNode = subNode.nextSibling();
|
|
+ if ( e.tagName() != "movie" )
|
|
+ continue;
|
|
+
|
|
+ // loading complete
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+MovieAnnotation::~MovieAnnotation()
|
|
+{
|
|
+}
|
|
+
|
|
+void MovieAnnotation::store( QDomNode & node, QDomDocument & document ) const
|
|
+{
|
|
+ // store base annotation properties
|
|
+ storeBaseAnnotationProperties( node, document );
|
|
+
|
|
+ // create [movie] element
|
|
+ QDomElement movieElement = document.createElement( "movie" );
|
|
+ node.appendChild( movieElement );
|
|
+}
|
|
+
|
|
+Annotation::SubType MovieAnnotation::subType() const
|
|
+{
|
|
+ return AMovie;
|
|
+}
|
|
+
|
|
+MovieObject* MovieAnnotation::movie() const
|
|
+{
|
|
+ Q_D( const MovieAnnotation );
|
|
+ return d->movie;
|
|
+}
|
|
+
|
|
+void MovieAnnotation::setMovie( MovieObject *movie )
|
|
+{
|
|
+ Q_D( MovieAnnotation );
|
|
+ d->movie = movie;
|
|
+}
|
|
+
|
|
+QString MovieAnnotation::movieTitle() const
|
|
+{
|
|
+ Q_D( const MovieAnnotation );
|
|
+ return d->title;
|
|
+}
|
|
+
|
|
+void MovieAnnotation::setMovieTitle( const QString &title )
|
|
+{
|
|
+ Q_D( MovieAnnotation );
|
|
+ d->title = title;
|
|
+}
|
|
+
|
|
+/** ScreenAnnotation [Annotation] */
|
|
+class ScreenAnnotationPrivate : public AnnotationPrivate
|
|
+{
|
|
+ public:
|
|
+ ScreenAnnotationPrivate();
|
|
+ ~ScreenAnnotationPrivate();
|
|
+ Annotation * makeAlias();
|
|
+ Annot* createNativeAnnot(::Page *destPage, DocumentData *doc);
|
|
+
|
|
+ // data fields
|
|
+ LinkRendition *action;
|
|
+ QString title;
|
|
+};
|
|
+
|
|
+ScreenAnnotationPrivate::ScreenAnnotationPrivate()
|
|
+ : AnnotationPrivate(), action( nullptr )
|
|
+{
|
|
+}
|
|
+
|
|
+ScreenAnnotationPrivate::~ScreenAnnotationPrivate()
|
|
+{
|
|
+ delete action;
|
|
+}
|
|
+
|
|
+ScreenAnnotation::ScreenAnnotation(ScreenAnnotationPrivate &dd)
|
|
+ : Annotation( dd )
|
|
+{}
|
|
+
|
|
+Annotation * ScreenAnnotationPrivate::makeAlias()
|
|
+{
|
|
+ return new ScreenAnnotation(*this);
|
|
+}
|
|
+
|
|
+Annot* ScreenAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
|
|
+{
|
|
+ return nullptr; // Not implemented
|
|
+}
|
|
+
|
|
+ScreenAnnotation::ScreenAnnotation()
|
|
+ : Annotation( *new ScreenAnnotationPrivate() )
|
|
+{
|
|
+}
|
|
+
|
|
+ScreenAnnotation::~ScreenAnnotation()
|
|
+{
|
|
+}
|
|
+
|
|
+void ScreenAnnotation::store( QDomNode & node, QDomDocument & document ) const
|
|
+{
|
|
+ // store base annotation properties
|
|
+ storeBaseAnnotationProperties( node, document );
|
|
+
|
|
+ // create [screen] element
|
|
+ QDomElement screenElement = document.createElement( "screen" );
|
|
+ node.appendChild( screenElement );
|
|
+}
|
|
+
|
|
+Annotation::SubType ScreenAnnotation::subType() const
|
|
+{
|
|
+ return AScreen;
|
|
+}
|
|
+
|
|
+LinkRendition* ScreenAnnotation::action() const
|
|
+{
|
|
+ Q_D( const ScreenAnnotation );
|
|
+ return d->action;
|
|
+}
|
|
+
|
|
+void ScreenAnnotation::setAction( LinkRendition *action )
|
|
+{
|
|
+ Q_D( ScreenAnnotation );
|
|
+ d->action = action;
|
|
+}
|
|
+
|
|
+QString ScreenAnnotation::screenTitle() const
|
|
+{
|
|
+ Q_D( const ScreenAnnotation );
|
|
+ return d->title;
|
|
+}
|
|
+
|
|
+void ScreenAnnotation::setScreenTitle( const QString &title )
|
|
+{
|
|
+ Q_D( ScreenAnnotation );
|
|
+ d->title = title;
|
|
+}
|
|
+
|
|
+Link* ScreenAnnotation::additionalAction( AdditionalActionType type ) const
|
|
+{
|
|
+ Q_D( const ScreenAnnotation );
|
|
+ return d->additionalAction( type );
|
|
+}
|
|
+
|
|
+/** WidgetAnnotation [Annotation] */
|
|
+class WidgetAnnotationPrivate : public AnnotationPrivate
|
|
+{
|
|
+ public:
|
|
+ Annotation * makeAlias();
|
|
+ Annot* createNativeAnnot(::Page *destPage, DocumentData *doc);
|
|
+};
|
|
+
|
|
+Annotation * WidgetAnnotationPrivate::makeAlias()
|
|
+{
|
|
+ return new WidgetAnnotation(*this);
|
|
+}
|
|
+
|
|
+Annot* WidgetAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
|
|
+{
|
|
+ return nullptr; // Not implemented
|
|
+}
|
|
+
|
|
+WidgetAnnotation::WidgetAnnotation(WidgetAnnotationPrivate &dd)
|
|
+ : Annotation( dd )
|
|
+{}
|
|
+
|
|
+WidgetAnnotation::WidgetAnnotation()
|
|
+ : Annotation( *new WidgetAnnotationPrivate() )
|
|
+{
|
|
+}
|
|
+
|
|
+WidgetAnnotation::~WidgetAnnotation()
|
|
+{
|
|
+}
|
|
+
|
|
+void WidgetAnnotation::store( QDomNode & node, QDomDocument & document ) const
|
|
+{
|
|
+ // store base annotation properties
|
|
+ storeBaseAnnotationProperties( node, document );
|
|
+
|
|
+ // create [widget] element
|
|
+ QDomElement widgetElement = document.createElement( "widget" );
|
|
+ node.appendChild( widgetElement );
|
|
+}
|
|
+
|
|
+Annotation::SubType WidgetAnnotation::subType() const
|
|
+{
|
|
+ return AWidget;
|
|
+}
|
|
+
|
|
+Link* WidgetAnnotation::additionalAction( AdditionalActionType type ) const
|
|
+{
|
|
+ Q_D( const WidgetAnnotation );
|
|
+ return d->additionalAction( type );
|
|
+}
|
|
+
|
|
+/** RichMediaAnnotation [Annotation] */
|
|
+class RichMediaAnnotation::Params::Private
|
|
+{
|
|
+ public:
|
|
+ Private() {}
|
|
+
|
|
+ QString flashVars;
|
|
+};
|
|
+
|
|
+RichMediaAnnotation::Params::Params()
|
|
+ : d( new Private )
|
|
+{
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Params::~Params()
|
|
+{
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::Params::setFlashVars( const QString &flashVars )
|
|
+{
|
|
+ d->flashVars = flashVars;
|
|
+}
|
|
+
|
|
+QString RichMediaAnnotation::Params::flashVars() const
|
|
+{
|
|
+ return d->flashVars;
|
|
+}
|
|
+
|
|
+
|
|
+class RichMediaAnnotation::Instance::Private
|
|
+{
|
|
+ public:
|
|
+ Private()
|
|
+ : params( nullptr )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ ~Private()
|
|
+ {
|
|
+ delete params;
|
|
+ }
|
|
+
|
|
+ RichMediaAnnotation::Instance::Type type;
|
|
+ RichMediaAnnotation::Params *params;
|
|
+};
|
|
+
|
|
+RichMediaAnnotation::Instance::Instance()
|
|
+ : d( new Private )
|
|
+{
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Instance::~Instance()
|
|
+{
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::Instance::setType( Type type )
|
|
+{
|
|
+ d->type = type;
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Instance::Type RichMediaAnnotation::Instance::type() const
|
|
+{
|
|
+ return d->type;
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::Instance::setParams( RichMediaAnnotation::Params *params )
|
|
+{
|
|
+ delete d->params;
|
|
+ d->params = params;
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Params* RichMediaAnnotation::Instance::params() const
|
|
+{
|
|
+ return d->params;
|
|
+}
|
|
+
|
|
+
|
|
+class RichMediaAnnotation::Configuration::Private
|
|
+{
|
|
+ public:
|
|
+ Private() {}
|
|
+ ~Private()
|
|
+ {
|
|
+ qDeleteAll( instances );
|
|
+ instances.clear();
|
|
+ }
|
|
+
|
|
+ RichMediaAnnotation::Configuration::Type type;
|
|
+ QString name;
|
|
+ QList< RichMediaAnnotation::Instance* > instances;
|
|
+};
|
|
+
|
|
+RichMediaAnnotation::Configuration::Configuration()
|
|
+ : d( new Private )
|
|
+{
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Configuration::~Configuration()
|
|
+{
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::Configuration::setType( Type type )
|
|
+{
|
|
+ d->type = type;
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Configuration::Type RichMediaAnnotation::Configuration::type() const
|
|
+{
|
|
+ return d->type;
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::Configuration::setName( const QString &name )
|
|
+{
|
|
+ d->name = name;
|
|
+}
|
|
+
|
|
+QString RichMediaAnnotation::Configuration::name() const
|
|
+{
|
|
+ return d->name;
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::Configuration::setInstances( const QList< RichMediaAnnotation::Instance* > &instances )
|
|
+{
|
|
+ qDeleteAll( d->instances );
|
|
+ d->instances.clear();
|
|
+
|
|
+ d->instances = instances;
|
|
+}
|
|
+
|
|
+QList< RichMediaAnnotation::Instance* > RichMediaAnnotation::Configuration::instances() const
|
|
+{
|
|
+ return d->instances;
|
|
+}
|
|
+
|
|
+
|
|
+class RichMediaAnnotation::Asset::Private
|
|
+{
|
|
+ public:
|
|
+ Private()
|
|
+ : embeddedFile( nullptr )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ ~Private()
|
|
+ {
|
|
+ delete embeddedFile;
|
|
+ }
|
|
+
|
|
+ QString name;
|
|
+ EmbeddedFile *embeddedFile;
|
|
+};
|
|
+
|
|
+RichMediaAnnotation::Asset::Asset()
|
|
+ : d( new Private )
|
|
+{
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Asset::~Asset()
|
|
+{
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::Asset::setName( const QString &name )
|
|
+{
|
|
+ d->name = name;
|
|
+}
|
|
+
|
|
+QString RichMediaAnnotation::Asset::name() const
|
|
+{
|
|
+ return d->name;
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::Asset::setEmbeddedFile( EmbeddedFile * embeddedFile )
|
|
+{
|
|
+ delete d->embeddedFile;
|
|
+ d->embeddedFile = embeddedFile;
|
|
+}
|
|
+
|
|
+EmbeddedFile* RichMediaAnnotation::Asset::embeddedFile() const
|
|
+{
|
|
+ return d->embeddedFile;
|
|
+}
|
|
+
|
|
+
|
|
+class RichMediaAnnotation::Content::Private
|
|
+{
|
|
+ public:
|
|
+ Private() {}
|
|
+ ~Private()
|
|
+ {
|
|
+ qDeleteAll( configurations );
|
|
+ configurations.clear();
|
|
+
|
|
+ qDeleteAll( assets );
|
|
+ assets.clear();
|
|
+ }
|
|
+
|
|
+ QList< RichMediaAnnotation::Configuration* > configurations;
|
|
+ QList< RichMediaAnnotation::Asset* > assets;
|
|
+};
|
|
+
|
|
+RichMediaAnnotation::Content::Content()
|
|
+ : d( new Private )
|
|
+{
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Content::~Content()
|
|
+{
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::Content::setConfigurations( const QList< RichMediaAnnotation::Configuration* > &configurations )
|
|
+{
|
|
+ qDeleteAll( d->configurations );
|
|
+ d->configurations.clear();
|
|
+
|
|
+ d->configurations = configurations;
|
|
+}
|
|
+
|
|
+QList< RichMediaAnnotation::Configuration* > RichMediaAnnotation::Content::configurations() const
|
|
+{
|
|
+ return d->configurations;
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::Content::setAssets( const QList< RichMediaAnnotation::Asset* > &assets )
|
|
+{
|
|
+ qDeleteAll( d->assets );
|
|
+ d->assets.clear();
|
|
+
|
|
+ d->assets = assets;
|
|
+}
|
|
+
|
|
+QList< RichMediaAnnotation::Asset* > RichMediaAnnotation::Content::assets() const
|
|
+{
|
|
+ return d->assets;
|
|
+}
|
|
+
|
|
+
|
|
+class RichMediaAnnotation::Activation::Private
|
|
+{
|
|
+ public:
|
|
+ Private()
|
|
+ : condition( RichMediaAnnotation::Activation::UserAction )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ RichMediaAnnotation::Activation::Condition condition;
|
|
+};
|
|
+
|
|
+RichMediaAnnotation::Activation::Activation()
|
|
+ : d( new Private )
|
|
+{
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Activation::~Activation()
|
|
+{
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::Activation::setCondition( Condition condition )
|
|
+{
|
|
+ d->condition = condition;
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Activation::Condition RichMediaAnnotation::Activation::condition() const
|
|
+{
|
|
+ return d->condition;
|
|
+}
|
|
+
|
|
+
|
|
+class RichMediaAnnotation::Deactivation::Private : public QSharedData
|
|
+{
|
|
+ public:
|
|
+ Private()
|
|
+ : condition( RichMediaAnnotation::Deactivation::UserAction )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ RichMediaAnnotation::Deactivation::Condition condition;
|
|
+};
|
|
+
|
|
+RichMediaAnnotation::Deactivation::Deactivation()
|
|
+ : d( new Private )
|
|
+{
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Deactivation::~Deactivation()
|
|
+{
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::Deactivation::setCondition( Condition condition )
|
|
+{
|
|
+ d->condition = condition;
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Deactivation::Condition RichMediaAnnotation::Deactivation::condition() const
|
|
+{
|
|
+ return d->condition;
|
|
+}
|
|
+
|
|
+
|
|
+class RichMediaAnnotation::Settings::Private : public QSharedData
|
|
+{
|
|
+ public:
|
|
+ Private()
|
|
+ : activation( nullptr ), deactivation( nullptr )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ RichMediaAnnotation::Activation *activation;
|
|
+ RichMediaAnnotation::Deactivation *deactivation;
|
|
+};
|
|
+
|
|
+RichMediaAnnotation::Settings::Settings()
|
|
+ : d( new Private )
|
|
+{
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Settings::~Settings()
|
|
+{
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::Settings::setActivation( RichMediaAnnotation::Activation *activation )
|
|
+{
|
|
+ delete d->activation;
|
|
+ d->activation = activation;
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Activation* RichMediaAnnotation::Settings::activation() const
|
|
+{
|
|
+ return d->activation;
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::Settings::setDeactivation( RichMediaAnnotation::Deactivation *deactivation )
|
|
+{
|
|
+ delete d->deactivation;
|
|
+ d->deactivation = deactivation;
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Deactivation* RichMediaAnnotation::Settings::deactivation() const
|
|
+{
|
|
+ return d->deactivation;
|
|
+}
|
|
+
|
|
+
|
|
+class RichMediaAnnotationPrivate : public AnnotationPrivate
|
|
+{
|
|
+ public:
|
|
+ RichMediaAnnotationPrivate()
|
|
+ : settings( nullptr ), content( nullptr )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ ~RichMediaAnnotationPrivate()
|
|
+ {
|
|
+ delete settings;
|
|
+ delete content;
|
|
+ }
|
|
+
|
|
+ Annotation * makeAlias()
|
|
+ {
|
|
+ return new RichMediaAnnotation( *this );
|
|
+ }
|
|
+
|
|
+ Annot* createNativeAnnot( ::Page *destPage, DocumentData *doc )
|
|
+ {
|
|
+ Q_UNUSED( destPage );
|
|
+ Q_UNUSED( doc );
|
|
+
|
|
+ return nullptr;
|
|
+ }
|
|
+
|
|
+ RichMediaAnnotation::Settings *settings;
|
|
+ RichMediaAnnotation::Content *content;
|
|
+};
|
|
+
|
|
+RichMediaAnnotation::RichMediaAnnotation()
|
|
+ : Annotation( *new RichMediaAnnotationPrivate() )
|
|
+{
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::RichMediaAnnotation( RichMediaAnnotationPrivate &dd )
|
|
+ : Annotation( dd )
|
|
+{
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::RichMediaAnnotation( const QDomNode & node )
|
|
+ : Annotation( *new RichMediaAnnotationPrivate(), node )
|
|
+{
|
|
+ // loop through the whole children looking for a 'richMedia' element
|
|
+ QDomNode subNode = node.firstChild();
|
|
+ while( subNode.isElement() )
|
|
+ {
|
|
+ QDomElement e = subNode.toElement();
|
|
+ subNode = subNode.nextSibling();
|
|
+ if ( e.tagName() != "richMedia" )
|
|
+ continue;
|
|
+
|
|
+ // loading complete
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::~RichMediaAnnotation()
|
|
+{
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::store( QDomNode & node, QDomDocument & document ) const
|
|
+{
|
|
+ // store base annotation properties
|
|
+ storeBaseAnnotationProperties( node, document );
|
|
+
|
|
+ // create [richMedia] element
|
|
+ QDomElement richMediaElement = document.createElement( "richMedia" );
|
|
+ node.appendChild( richMediaElement );
|
|
+}
|
|
+
|
|
+Annotation::SubType RichMediaAnnotation::subType() const
|
|
+{
|
|
+ return ARichMedia;
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::setSettings( RichMediaAnnotation::Settings *settings )
|
|
+{
|
|
+ Q_D( RichMediaAnnotation );
|
|
+
|
|
+ delete d->settings;
|
|
+ d->settings = settings;
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Settings* RichMediaAnnotation::settings() const
|
|
+{
|
|
+ Q_D( const RichMediaAnnotation );
|
|
+
|
|
+ return d->settings;
|
|
+}
|
|
+
|
|
+void RichMediaAnnotation::setContent( RichMediaAnnotation::Content *content )
|
|
+{
|
|
+ Q_D( RichMediaAnnotation );
|
|
+
|
|
+ delete d->content;
|
|
+ d->content = content;
|
|
+}
|
|
+
|
|
+RichMediaAnnotation::Content* RichMediaAnnotation::content() const
|
|
+{
|
|
+ Q_D( const RichMediaAnnotation );
|
|
+
|
|
+ return d->content;
|
|
+}
|
|
+
|
|
+//BEGIN utility annotation functions
|
|
+QColor convertAnnotColor( const AnnotColor *color )
|
|
+{
|
|
+ if ( !color )
|
|
+ return QColor();
|
|
+
|
|
+ QColor newcolor;
|
|
+ const double *color_data = color->getValues();
|
|
+ switch ( color->getSpace() )
|
|
+ {
|
|
+ case AnnotColor::colorTransparent: // = 0,
|
|
+ newcolor = Qt::transparent;
|
|
+ break;
|
|
+ case AnnotColor::colorGray: // = 1,
|
|
+ newcolor.setRgbF( color_data[0], color_data[0], color_data[0] );
|
|
+ break;
|
|
+ case AnnotColor::colorRGB: // = 3,
|
|
+ newcolor.setRgbF( color_data[0], color_data[1], color_data[2] );
|
|
+ break;
|
|
+ case AnnotColor::colorCMYK: // = 4
|
|
+ newcolor.setCmykF( color_data[0], color_data[1], color_data[2], color_data[3] );
|
|
+ break;
|
|
+ }
|
|
+ return newcolor;
|
|
+}
|
|
+
|
|
+std::unique_ptr<AnnotColor> convertQColor( const QColor &c )
|
|
+{
|
|
+ if ( c.alpha() == 0 )
|
|
+ return {}; // Transparent
|
|
+
|
|
+ switch ( c.spec() )
|
|
+ {
|
|
+ case QColor::Rgb:
|
|
+ case QColor::Hsl:
|
|
+ case QColor::Hsv:
|
|
+ return std::make_unique<AnnotColor>( c.redF(), c.greenF(), c.blueF() );
|
|
+ case QColor::Cmyk:
|
|
+ return std::make_unique<AnnotColor>( c.cyanF(), c.magentaF(), c.yellowF(), c.blackF() );
|
|
+ case QColor::Invalid:
|
|
+ default:
|
|
+ return {};
|
|
+ }
|
|
+}
|
|
+//END utility annotation functions
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-annotation.h b/qt4/src/poppler-annotation.h
|
|
new file mode 100644
|
|
index 00000000..ac77c421
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-annotation.h
|
|
@@ -0,0 +1,1379 @@
|
|
+/* poppler-annotation.h: qt interface to poppler
|
|
+ * Copyright (C) 2006-2008, 2012 Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2006, 2008 Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2007, Brad Hards <bradh@frogmouth.net>
|
|
+ * Copyright (C) 2010, Philip Lorenz <lorenzph+freedesktop@gmail.com>
|
|
+ * Copyright (C) 2012, 2015, Tobias Koenig <tobias.koenig@kdab.com>
|
|
+ * Copyright (C) 2012, Guillermo A. Amaral B. <gamaral@kde.org>
|
|
+ * Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
|
|
+ * Adapting code from
|
|
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef _POPPLER_ANNOTATION_H_
|
|
+#define _POPPLER_ANNOTATION_H_
|
|
+
|
|
+#include <QtCore/QDateTime>
|
|
+#include <QtCore/QSharedDataPointer>
|
|
+#include <QtCore/QLinkedList>
|
|
+#include <QtCore/QList>
|
|
+#include <QtCore/QPointF>
|
|
+#include <QtCore/QRectF>
|
|
+#include <QtCore/QVector>
|
|
+#include <QtGui/QColor>
|
|
+#include <QtGui/QFont>
|
|
+#include <QtXml/QDomDocument>
|
|
+#include "poppler-export.h"
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+class Annotation;
|
|
+class AnnotationPrivate;
|
|
+class TextAnnotationPrivate;
|
|
+class LineAnnotationPrivate;
|
|
+class GeomAnnotationPrivate;
|
|
+class HighlightAnnotationPrivate;
|
|
+class StampAnnotationPrivate;
|
|
+class InkAnnotationPrivate;
|
|
+class LinkAnnotationPrivate;
|
|
+class CaretAnnotationPrivate;
|
|
+class FileAttachmentAnnotationPrivate;
|
|
+class SoundAnnotationPrivate;
|
|
+class MovieAnnotationPrivate;
|
|
+class ScreenAnnotationPrivate;
|
|
+class WidgetAnnotationPrivate;
|
|
+class RichMediaAnnotationPrivate;
|
|
+class EmbeddedFile;
|
|
+class Link;
|
|
+class SoundObject;
|
|
+class MovieObject;
|
|
+class LinkRendition;
|
|
+class Page;
|
|
+
|
|
+/**
|
|
+ * \short Helper class for (recursive) Annotation retrieval/storage.
|
|
+ *
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT AnnotationUtils
|
|
+{
|
|
+ public:
|
|
+ /**
|
|
+ * Restore an Annotation (with revisions if needed) from the DOM
|
|
+ * element \p annElement.
|
|
+ * \returns a pointer to the complete Annotation or 0 if element is
|
|
+ * invalid.
|
|
+ */
|
|
+ static Annotation * createAnnotation( const QDomElement & annElement );
|
|
+
|
|
+ /**
|
|
+ * Save the Annotation \p ann as a child of \p annElement taking
|
|
+ * care of saving all revisions if \p ann has any.
|
|
+ */
|
|
+ static void storeAnnotation( const Annotation * ann,
|
|
+ QDomElement & annElement, QDomDocument & document );
|
|
+
|
|
+ /**
|
|
+ * Returns an element called \p name from the direct children of
|
|
+ * \p parentNode or a null element if not found.
|
|
+ */
|
|
+ static QDomElement findChildElement( const QDomNode & parentNode,
|
|
+ const QString & name );
|
|
+};
|
|
+
|
|
+
|
|
+/**
|
|
+ * \short Annotation class holding properties shared by all annotations.
|
|
+ *
|
|
+ * An Annotation is an object (text note, highlight, sound, popup window, ..)
|
|
+ * contained by a Page in the document.
|
|
+ *
|
|
+ * \warning Different Annotation objects might point to the same annotation.
|
|
+ *
|
|
+ * \section annotCreation How to add annotations
|
|
+ *
|
|
+ * Create an Annotation object of the desired subclass (for example
|
|
+ * TextAnnotation) and set its properties:
|
|
+ * @code
|
|
+ * Poppler::TextAnnotation* myann = new Poppler::TextAnnotation(Poppler::TextAnnotation::InPlace);
|
|
+ * myann->setBoundary(QRectF(0.1, 0.1, 0.2, 0.2)); // normalized coordinates: (0,0) is top-left, (1,1) is bottom-right
|
|
+ * myann->setContents("Hello, world!");
|
|
+ * @endcode
|
|
+ * \note Always set a boundary rectangle, or nothing will be shown!
|
|
+ *
|
|
+ * Obtain a pointer to the Page where you want to add the annotation (refer to
|
|
+ * \ref req for instructions) and add the annotation:
|
|
+ * @code
|
|
+ * Poppler::Page* mypage = ...;
|
|
+ * mypage->addAnnotation(myann);
|
|
+ * @endcode
|
|
+ *
|
|
+ * You can keep on editing the annotation after it has been added to the page:
|
|
+ * @code
|
|
+ * myann->setContents("World, hello!"); // Let's change text...
|
|
+ * myann->setAuthor("Your name here"); // ...and set an author too
|
|
+ * @endcode
|
|
+ *
|
|
+ * When you're done with editing the annotation, you must destroy the Annotation
|
|
+ * object:
|
|
+ * @code
|
|
+ * delete myann;
|
|
+ * @endcode
|
|
+ *
|
|
+ * Use the PDFConverter class to save the modified document.
|
|
+ *
|
|
+ * \section annotFixedRotation FixedRotation flag specifics
|
|
+ *
|
|
+ * According to the PDF specification, annotations whose
|
|
+ * Annotation::FixedRotation flag is set must always be shown in their original
|
|
+ * orientation, no matter what the current rendering rotation or the page's
|
|
+ * Page::orientation() values are. In comparison with regular annotations, such
|
|
+ * annotations should therefore be transformed by an extra rotation at rendering
|
|
+ * time to "undo" such context-related rotations, which is equal to
|
|
+ * <code>-(rendering_rotation + page_orientation)</code>. The rotation pivot
|
|
+ * is the top-left corner of the boundary rectangle.
|
|
+ *
|
|
+ * In practice, %Poppler's \ref Page::renderToImage only "unrotates" the
|
|
+ * page orientation, and does <b>not</b> unrotate the rendering rotation.
|
|
+ * This ensures consistent renderings at different Page::Rotation values:
|
|
+ * annotations are always positioned as if they were being positioned at the
|
|
+ * default page orientation.
|
|
+ *
|
|
+ * Just like regular annotations, %Poppler Qt4 exposes normalized coordinates
|
|
+ * relative to the page's default orientation. However, behind the scenes, the
|
|
+ * coordinate system is different and %Poppler transparently transforms each
|
|
+ * shape. If you never call either Annotation::setFlags or
|
|
+ * Annotation::setBoundary, you don't need to worry about this; but if you do
|
|
+ * call them, then you need to adhere to the following rules:
|
|
+ * - Whenever you toggle the Annotation::FixedRotation flag, you <b>must</b>
|
|
+ * set again the boundary rectangle first, and then you <b>must</b> set
|
|
+ * again any other geometry-related property.
|
|
+ * - Whenever you modify the boundary rectangle of an annotation whose
|
|
+ * Annotation::FixedRotation flag is set, you <b>must</b> set again any other
|
|
+ * geometry-related property.
|
|
+ *
|
|
+ * These two rules are necessary to make %Poppler's transparent coordinate
|
|
+ * conversion work properly.
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT Annotation
|
|
+{
|
|
+ friend class AnnotationUtils;
|
|
+ friend class LinkMovie;
|
|
+ friend class LinkRendition;
|
|
+
|
|
+ public:
|
|
+ // enum definitions
|
|
+ /**
|
|
+ * Annotation subclasses
|
|
+ *
|
|
+ * \sa subType()
|
|
+ */
|
|
+ // WARNING!!! oKular uses that very same values so if you change them notify the author!
|
|
+ enum SubType
|
|
+ {
|
|
+ AText = 1, ///< TextAnnotation
|
|
+ ALine = 2, ///< LineAnnotation
|
|
+ AGeom = 3, ///< GeomAnnotation
|
|
+ AHighlight = 4, ///< HighlightAnnotation
|
|
+ AStamp = 5, ///< StampAnnotation
|
|
+ AInk = 6, ///< InkAnnotation
|
|
+ ALink = 7, ///< LinkAnnotation
|
|
+ ACaret = 8, ///< CaretAnnotation
|
|
+ AFileAttachment = 9, ///< FileAttachmentAnnotation
|
|
+ ASound = 10, ///< SoundAnnotation
|
|
+ AMovie = 11, ///< MovieAnnotation
|
|
+ AScreen = 12, ///< ScreenAnnotation \since 0.20
|
|
+ AWidget = 13, ///< WidgetAnnotation \since 0.22
|
|
+ ARichMedia = 14, ///< RichMediaAnnotation \since 0.36
|
|
+ A_BASE = 0
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ * Annotation flags
|
|
+ *
|
|
+ * They can be OR'd together (e.g. Annotation::FixedRotation | Annotation::DenyPrint).
|
|
+ *
|
|
+ * \sa flags(), setFlags(int)
|
|
+ */
|
|
+ // NOTE: Only flags that are known to work are documented
|
|
+ enum Flag
|
|
+ {
|
|
+ Hidden = 1, ///< Do not display or print the annotation
|
|
+ FixedSize = 2,
|
|
+ FixedRotation = 4, ///< Do not rotate the annotation according to page orientation and rendering rotation \warning Extra care is needed with this flag: see \ref annotFixedRotation
|
|
+ DenyPrint = 8, ///< Do not print the annotation
|
|
+ DenyWrite = 16,
|
|
+ DenyDelete = 32,
|
|
+ ToggleHidingOnMouse = 64,
|
|
+ External = 128
|
|
+ };
|
|
+
|
|
+ enum LineStyle { Solid = 1, Dashed = 2, Beveled = 4, Inset = 8, Underline = 16 };
|
|
+ enum LineEffect { NoEffect = 1, Cloudy = 2};
|
|
+ enum RevScope { Root = 0 /** \since 0.20 */, Reply = 1, Group = 2, Delete = 4 };
|
|
+ enum RevType { None = 1, Marked = 2, Unmarked = 4, Accepted = 8, Rejected = 16, Cancelled = 32, Completed = 64 };
|
|
+
|
|
+ /**
|
|
+ * Returns the author of the annotation.
|
|
+ */
|
|
+ QString author() const;
|
|
+ /**
|
|
+ * Sets a new author for the annotation.
|
|
+ */
|
|
+ void setAuthor( const QString &author );
|
|
+
|
|
+ QString contents() const;
|
|
+ void setContents( const QString &contents );
|
|
+
|
|
+ /**
|
|
+ * Returns the unique name (ID) of the annotation.
|
|
+ */
|
|
+ QString uniqueName() const;
|
|
+ /**
|
|
+ * Sets a new unique name for the annotation.
|
|
+ *
|
|
+ * \note no check of the new uniqueName is done
|
|
+ */
|
|
+ void setUniqueName( const QString &uniqueName );
|
|
+
|
|
+ QDateTime modificationDate() const;
|
|
+ void setModificationDate( const QDateTime &date );
|
|
+
|
|
+ QDateTime creationDate() const;
|
|
+ void setCreationDate( const QDateTime &date );
|
|
+
|
|
+ /**
|
|
+ * Returns this annotation's flags
|
|
+ *
|
|
+ * \sa Flag, setFlags(int)
|
|
+ */
|
|
+ int flags() const;
|
|
+ /**
|
|
+ * Sets this annotation's flags
|
|
+ *
|
|
+ * \sa Flag, flags(), \ref annotFixedRotation
|
|
+ */
|
|
+ void setFlags( int flags );
|
|
+
|
|
+ /**
|
|
+ * Returns this annotation's boundary rectangle in normalized coordinates
|
|
+ *
|
|
+ * \sa setBoundary(const QRectF&)
|
|
+ */
|
|
+ QRectF boundary() const;
|
|
+ /**
|
|
+ * Sets this annotation's boundary rectangle
|
|
+ *
|
|
+ * The boundary rectangle is the smallest rectangle that contains the
|
|
+ * annotation.
|
|
+ *
|
|
+ * \warning This property is mandatory: you must always set this.
|
|
+ *
|
|
+ * \sa boundary(), \ref annotFixedRotation
|
|
+ */
|
|
+ void setBoundary( const QRectF &boundary );
|
|
+
|
|
+ /**
|
|
+ * \short Container class for Annotation style information
|
|
+ *
|
|
+ * \since 0.20
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT Style
|
|
+ {
|
|
+ public:
|
|
+ Style();
|
|
+ Style( const Style &other );
|
|
+ Style& operator=( const Style &other );
|
|
+ ~Style();
|
|
+
|
|
+ // appearance properties
|
|
+ QColor color() const; // black
|
|
+ void setColor(const QColor &color);
|
|
+ double opacity() const; // 1.0
|
|
+ void setOpacity(double opacity);
|
|
+
|
|
+ // pen properties
|
|
+ double width() const; // 1.0
|
|
+ void setWidth(double width);
|
|
+ LineStyle lineStyle() const; // LineStyle::Solid
|
|
+ void setLineStyle(LineStyle style);
|
|
+ double xCorners() const; // 0.0
|
|
+ void setXCorners(double radius);
|
|
+ double yCorners() const; // 0.0
|
|
+ void setYCorners(double radius);
|
|
+ const QVector<double>& dashArray() const; // [ 3 ]
|
|
+ void setDashArray(const QVector<double> &array);
|
|
+
|
|
+ // pen effects
|
|
+ LineEffect lineEffect() const; // LineEffect::NoEffect
|
|
+ void setLineEffect(LineEffect effect);
|
|
+ double effectIntensity() const; // 1.0
|
|
+ void setEffectIntensity(double intens);
|
|
+
|
|
+ private:
|
|
+ class Private;
|
|
+ QSharedDataPointer<Private> d;
|
|
+ };
|
|
+
|
|
+ /// \since 0.20
|
|
+ Style style() const;
|
|
+ /// \since 0.20
|
|
+ void setStyle( const Style& style );
|
|
+
|
|
+ /**
|
|
+ * \short Container class for Annotation pop-up window information
|
|
+ *
|
|
+ * \since 0.20
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT Popup
|
|
+ {
|
|
+ public:
|
|
+ Popup();
|
|
+ Popup( const Popup &other );
|
|
+ Popup& operator=( const Popup &other );
|
|
+ ~Popup();
|
|
+
|
|
+ // window state (Hidden, FixedRotation, Deny* flags allowed)
|
|
+ int flags() const; // -1 (never initialized) -> 0 (if inited and shown)
|
|
+ void setFlags( int flags );
|
|
+
|
|
+ // geometric properties
|
|
+ QRectF geometry() const; // no default
|
|
+ void setGeometry( const QRectF &geom );
|
|
+
|
|
+ // window contens/override properties
|
|
+ QString title() const; // '' text in the titlebar (overrides author)
|
|
+ void setTitle( const QString &title );
|
|
+ QString summary() const; // '' short description (displayed if not empty)
|
|
+ void setSummary( const QString &summary );
|
|
+ QString text() const; // '' text for the window (overrides annot->contents)
|
|
+ void setText( const QString &text );
|
|
+
|
|
+ private:
|
|
+ class Private;
|
|
+ QSharedDataPointer<Private> d;
|
|
+ };
|
|
+
|
|
+ /// \since 0.20
|
|
+ Popup popup() const;
|
|
+ /// \warning Currently does nothing \since 0.20
|
|
+ void setPopup( const Popup& popup );
|
|
+
|
|
+ /// \cond PRIVATE
|
|
+ // This field is deprecated and not used any more. Use popup
|
|
+ Q_DECL_DEPRECATED struct { int width, height; } window; // Always set to zero
|
|
+ /// \endcond
|
|
+
|
|
+ /// \since 0.20
|
|
+ RevScope revisionScope() const; // Root
|
|
+
|
|
+ /// \since 0.20
|
|
+ RevType revisionType() const; // None
|
|
+
|
|
+ /**
|
|
+ * Returns the revisions of this annotation
|
|
+ *
|
|
+ * \note The caller owns the returned annotations and they should
|
|
+ * be deleted when no longer required.
|
|
+ *
|
|
+ * \since 0.20
|
|
+ */
|
|
+ QList<Annotation*> revisions() const;
|
|
+
|
|
+ /**
|
|
+ * The type of the annotation.
|
|
+ */
|
|
+ virtual SubType subType() const = 0;
|
|
+
|
|
+ /**
|
|
+ * Destructor.
|
|
+ */
|
|
+ virtual ~Annotation();
|
|
+
|
|
+ /**
|
|
+ * Describes the flags from an annotations 'AA' dictionary.
|
|
+ *
|
|
+ * This flag is used by the additionalAction() method for ScreenAnnotation
|
|
+ * and WidgetAnnotation.
|
|
+ *
|
|
+ * \since 0.22
|
|
+ */
|
|
+ enum AdditionalActionType
|
|
+ {
|
|
+ CursorEnteringAction, ///< Performed when the cursor enters the annotation's active area
|
|
+ CursorLeavingAction, ///< Performed when the cursor exists the annotation's active area
|
|
+ MousePressedAction, ///< Performed when the mouse button is pressed inside the annotation's active area
|
|
+ MouseReleasedAction, ///< Performed when the mouse button is released inside the annotation's active area
|
|
+ FocusInAction, ///< Performed when the annotation receives the input focus
|
|
+ FocusOutAction, ///< Performed when the annotation loses the input focus
|
|
+ PageOpeningAction, ///< Performed when the page containing the annotation is opened
|
|
+ PageClosingAction, ///< Performed when the page containing the annotation is closed
|
|
+ PageVisibleAction, ///< Performed when the page containing the annotation becomes visible
|
|
+ PageInvisibleAction ///< Performed when the page containing the annotation becomes invisible
|
|
+ };
|
|
+
|
|
+ protected:
|
|
+ /// \cond PRIVATE
|
|
+ Annotation( AnnotationPrivate &dd );
|
|
+ Annotation( AnnotationPrivate &dd, const QDomNode &description );
|
|
+ void storeBaseAnnotationProperties( QDomNode & parentNode, QDomDocument & document ) const;
|
|
+ Q_DECLARE_PRIVATE( Annotation )
|
|
+ QExplicitlySharedDataPointer<AnnotationPrivate> d_ptr;
|
|
+ /// \endcond
|
|
+
|
|
+ private:
|
|
+ virtual void store( QDomNode & parentNode, QDomDocument & document ) const = 0;
|
|
+ Q_DISABLE_COPY( Annotation )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \short Annotation containing text.
|
|
+ *
|
|
+ * A text annotation is an object showing some text directly on the page, or
|
|
+ * linked to the contents using an icon shown on a page.
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT TextAnnotation : public Annotation
|
|
+{
|
|
+ friend class AnnotationUtils;
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ // local enums
|
|
+ enum TextType { Linked, InPlace };
|
|
+ enum InplaceIntent { Unknown, Callout, TypeWriter };
|
|
+
|
|
+ TextAnnotation( TextType type );
|
|
+ ~TextAnnotation();
|
|
+ SubType subType() const override;
|
|
+
|
|
+ /**
|
|
+ The type of text annotation represented by this object
|
|
+ */
|
|
+ TextType textType() const;
|
|
+
|
|
+ /**
|
|
+ The name of the icon for this text annotation.
|
|
+
|
|
+ Standard names for text annotation icons are:
|
|
+ - Comment
|
|
+ - Help
|
|
+ - Insert
|
|
+ - Key
|
|
+ - NewParagraph
|
|
+ - Note (this is the default icon to use)
|
|
+ - Paragraph
|
|
+ */
|
|
+ QString textIcon() const;
|
|
+
|
|
+ /**
|
|
+ Set the name of the icon to use for this text annotation.
|
|
+
|
|
+ \sa textIcon for the list of standard names
|
|
+ */
|
|
+ void setTextIcon( const QString &icon );
|
|
+
|
|
+ QFont textFont() const;
|
|
+ void setTextFont( const QFont &font );
|
|
+ /// \since 0.69
|
|
+ QColor textColor() const;
|
|
+ /// \since 0.69
|
|
+ void setTextColor( const QColor &color );
|
|
+
|
|
+ int inplaceAlign() const;
|
|
+ void setInplaceAlign( int align );
|
|
+
|
|
+ /**
|
|
+ Synonym for contents()
|
|
+
|
|
+ \deprecated Use contents() instead
|
|
+ */
|
|
+ QString inplaceText() const;
|
|
+ /**
|
|
+ Synonym for setContents()
|
|
+
|
|
+ \deprecated Use setContents() instead
|
|
+ */
|
|
+ void setInplaceText( const QString &text );
|
|
+
|
|
+ QPointF calloutPoint( int id ) const;
|
|
+ /// \since 0.20
|
|
+ QVector<QPointF> calloutPoints() const;
|
|
+ /// \since 0.20
|
|
+ void setCalloutPoints( const QVector<QPointF> &points );
|
|
+
|
|
+ InplaceIntent inplaceIntent() const;
|
|
+ void setInplaceIntent( InplaceIntent intent );
|
|
+
|
|
+ private:
|
|
+ TextAnnotation( const QDomNode &node );
|
|
+ TextAnnotation( TextAnnotationPrivate &dd );
|
|
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const;
|
|
+ void setTextType( TextType type );
|
|
+ Q_DECLARE_PRIVATE( TextAnnotation )
|
|
+ Q_DISABLE_COPY( TextAnnotation )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \short Polygon/polyline annotation.
|
|
+ *
|
|
+ * This annotation represents a polygon (or polyline) to be drawn on a page.
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT LineAnnotation : public Annotation
|
|
+{
|
|
+ friend class AnnotationUtils;
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ // local enums
|
|
+ /// \since 0.20
|
|
+ enum LineType { StraightLine, Polyline };
|
|
+ enum TermStyle { Square, Circle, Diamond, OpenArrow, ClosedArrow, None,
|
|
+ Butt, ROpenArrow, RClosedArrow, Slash };
|
|
+ enum LineIntent { Unknown, Arrow, Dimension, PolygonCloud };
|
|
+
|
|
+ /// \since 0.20
|
|
+ LineAnnotation( LineType type );
|
|
+ ~LineAnnotation();
|
|
+ SubType subType() const override;
|
|
+
|
|
+ /// \since 0.20
|
|
+ LineType lineType() const;
|
|
+
|
|
+ QLinkedList<QPointF> linePoints() const;
|
|
+ void setLinePoints( const QLinkedList<QPointF> &points );
|
|
+
|
|
+ TermStyle lineStartStyle() const;
|
|
+ void setLineStartStyle( TermStyle style );
|
|
+
|
|
+ TermStyle lineEndStyle() const;
|
|
+ void setLineEndStyle( TermStyle style );
|
|
+
|
|
+ bool isLineClosed() const;
|
|
+ void setLineClosed( bool closed );
|
|
+
|
|
+ QColor lineInnerColor() const;
|
|
+ void setLineInnerColor( const QColor &color );
|
|
+
|
|
+ double lineLeadingForwardPoint() const;
|
|
+ void setLineLeadingForwardPoint( double point );
|
|
+
|
|
+ double lineLeadingBackPoint() const;
|
|
+ void setLineLeadingBackPoint( double point );
|
|
+
|
|
+ bool lineShowCaption() const;
|
|
+ void setLineShowCaption( bool show );
|
|
+
|
|
+ LineIntent lineIntent() const;
|
|
+ void setLineIntent( LineIntent intent );
|
|
+
|
|
+ private:
|
|
+ LineAnnotation( const QDomNode &node );
|
|
+ LineAnnotation( LineAnnotationPrivate &dd );
|
|
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const;
|
|
+ void setLineType( LineType type );
|
|
+ Q_DECLARE_PRIVATE( LineAnnotation )
|
|
+ Q_DISABLE_COPY( LineAnnotation )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \short Geometric annotation.
|
|
+ *
|
|
+ * The geometric annotation represents a geometric figure, like a rectangle or
|
|
+ * an ellipse.
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT GeomAnnotation : public Annotation
|
|
+{
|
|
+ friend class AnnotationUtils;
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ GeomAnnotation();
|
|
+ virtual ~GeomAnnotation();
|
|
+ virtual SubType subType() const;
|
|
+
|
|
+ // common enums
|
|
+ enum GeomType { InscribedSquare, InscribedCircle };
|
|
+
|
|
+ GeomType geomType() const;
|
|
+ void setGeomType( GeomType style );
|
|
+
|
|
+ QColor geomInnerColor() const;
|
|
+ void setGeomInnerColor( const QColor &color );
|
|
+
|
|
+ private:
|
|
+ GeomAnnotation( const QDomNode &node );
|
|
+ GeomAnnotation( GeomAnnotationPrivate &dd );
|
|
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const;
|
|
+ Q_DECLARE_PRIVATE( GeomAnnotation )
|
|
+ Q_DISABLE_COPY( GeomAnnotation )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \short Text highlight annotation.
|
|
+ *
|
|
+ * The higlight annotation represents some areas of text being "highlighted".
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT HighlightAnnotation : public Annotation
|
|
+{
|
|
+ friend class AnnotationUtils;
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ HighlightAnnotation();
|
|
+ virtual ~HighlightAnnotation();
|
|
+ virtual SubType subType() const;
|
|
+
|
|
+ /**
|
|
+ The type of highlight
|
|
+ */
|
|
+ enum HighlightType { Highlight, ///< highlighter pen style annotation
|
|
+ Squiggly, ///< jagged or squiggly underline
|
|
+ Underline, ///< straight line underline
|
|
+ StrikeOut ///< straight line through-line
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ Structure corresponding to a QuadPoints array. This matches a
|
|
+ quadrilateral that describes the area around a word (or set of
|
|
+ words) that are to be highlighted.
|
|
+ */
|
|
+ struct Quad
|
|
+ {
|
|
+ QPointF points[4]; // 8 valid coords
|
|
+ bool capStart; // false (vtx 1-4) [K]
|
|
+ bool capEnd; // false (vtx 2-3) [K]
|
|
+ double feather; // 0.1 (in range 0..1) [K]
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ The type (style) of highlighting to use for this area
|
|
+ or these areas.
|
|
+ */
|
|
+ HighlightType highlightType() const;
|
|
+
|
|
+ /**
|
|
+ Set the type of highlighting to use for the given area
|
|
+ or areas.
|
|
+ */
|
|
+ void setHighlightType( HighlightType type );
|
|
+
|
|
+ /**
|
|
+ The list of areas to highlight.
|
|
+ */
|
|
+ QList< Quad > highlightQuads() const;
|
|
+
|
|
+ /**
|
|
+ Set the areas to highlight.
|
|
+ */
|
|
+ void setHighlightQuads( const QList< Quad > &quads );
|
|
+
|
|
+ private:
|
|
+ HighlightAnnotation( const QDomNode &node );
|
|
+ HighlightAnnotation( HighlightAnnotationPrivate &dd );
|
|
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const;
|
|
+ Q_DECLARE_PRIVATE( HighlightAnnotation )
|
|
+ Q_DISABLE_COPY( HighlightAnnotation )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \short Stamp annotation.
|
|
+ *
|
|
+ * A simple annotation drawing a stamp on a page.
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT StampAnnotation : public Annotation
|
|
+{
|
|
+ friend class AnnotationUtils;
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ StampAnnotation();
|
|
+ virtual ~StampAnnotation();
|
|
+ virtual SubType subType() const;
|
|
+
|
|
+ /**
|
|
+ The name of the icon for this stamp annotation.
|
|
+
|
|
+ Standard names for stamp annotation icons are:
|
|
+ - Approved
|
|
+ - AsIs
|
|
+ - Confidential
|
|
+ - Departmental
|
|
+ - Draft (this is the default icon type)
|
|
+ - Experimental
|
|
+ - Expired
|
|
+ - Final
|
|
+ - ForComment
|
|
+ - ForPublicRelease
|
|
+ - NotApproved
|
|
+ - NotForPublicRelease
|
|
+ - Sold
|
|
+ - TopSecret
|
|
+ */
|
|
+ QString stampIconName() const;
|
|
+
|
|
+ /**
|
|
+ Set the icon type for this stamp annotation.
|
|
+
|
|
+ \sa stampIconName for the list of standard icon names
|
|
+ */
|
|
+ void setStampIconName( const QString &name );
|
|
+
|
|
+ private:
|
|
+ StampAnnotation( const QDomNode &node );
|
|
+ StampAnnotation( StampAnnotationPrivate &dd );
|
|
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const;
|
|
+ Q_DECLARE_PRIVATE( StampAnnotation )
|
|
+ Q_DISABLE_COPY( StampAnnotation )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \short Ink Annotation.
|
|
+ *
|
|
+ * Annotation representing an ink path on a page.
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT InkAnnotation : public Annotation
|
|
+{
|
|
+ friend class AnnotationUtils;
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ InkAnnotation();
|
|
+ virtual ~InkAnnotation();
|
|
+ virtual SubType subType() const;
|
|
+
|
|
+ QList< QLinkedList<QPointF> > inkPaths() const;
|
|
+ void setInkPaths( const QList< QLinkedList<QPointF> > &paths );
|
|
+
|
|
+ private:
|
|
+ InkAnnotation( const QDomNode &node );
|
|
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const;
|
|
+ InkAnnotation(InkAnnotationPrivate &dd);
|
|
+ Q_DECLARE_PRIVATE( InkAnnotation )
|
|
+ Q_DISABLE_COPY( InkAnnotation )
|
|
+};
|
|
+
|
|
+class POPPLER_QT4_EXPORT LinkAnnotation : public Annotation
|
|
+{
|
|
+ friend class AnnotationUtils;
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ virtual ~LinkAnnotation();
|
|
+ virtual SubType subType() const;
|
|
+
|
|
+ // local enums
|
|
+ enum HighlightMode { None, Invert, Outline, Push };
|
|
+
|
|
+ /** \since 0.20 */
|
|
+ Link* linkDestination() const;
|
|
+ void setLinkDestination( Link *link );
|
|
+
|
|
+ HighlightMode linkHighlightMode() const;
|
|
+ void setLinkHighlightMode( HighlightMode mode );
|
|
+
|
|
+ QPointF linkRegionPoint( int id ) const;
|
|
+ void setLinkRegionPoint( int id, const QPointF &point );
|
|
+
|
|
+ private:
|
|
+ LinkAnnotation();
|
|
+ LinkAnnotation( const QDomNode &node );
|
|
+ LinkAnnotation( LinkAnnotationPrivate &dd );
|
|
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const;
|
|
+ Q_DECLARE_PRIVATE( LinkAnnotation )
|
|
+ Q_DISABLE_COPY( LinkAnnotation )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \short Caret annotation.
|
|
+ *
|
|
+ * The caret annotation represents a symbol to indicate the presence of text.
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT CaretAnnotation : public Annotation
|
|
+{
|
|
+ friend class AnnotationUtils;
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ CaretAnnotation();
|
|
+ virtual ~CaretAnnotation();
|
|
+ virtual SubType subType() const;
|
|
+
|
|
+ /**
|
|
+ * The symbols for the caret annotation.
|
|
+ */
|
|
+ enum CaretSymbol { None, P };
|
|
+
|
|
+ CaretSymbol caretSymbol() const;
|
|
+ void setCaretSymbol( CaretSymbol symbol );
|
|
+
|
|
+ private:
|
|
+ CaretAnnotation( const QDomNode &node );
|
|
+ CaretAnnotation( CaretAnnotationPrivate &dd );
|
|
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const;
|
|
+ Q_DECLARE_PRIVATE( CaretAnnotation )
|
|
+ Q_DISABLE_COPY( CaretAnnotation )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \short File attachment annotation.
|
|
+ *
|
|
+ * The file attachment annotation represents a file embedded in the document.
|
|
+ *
|
|
+ * \since 0.10
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT FileAttachmentAnnotation : public Annotation
|
|
+{
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ virtual ~FileAttachmentAnnotation();
|
|
+ virtual SubType subType() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the name of the icon of this annotation.
|
|
+ */
|
|
+ QString fileIconName() const;
|
|
+ /**
|
|
+ * Sets a new name for the icon of this annotation.
|
|
+ */
|
|
+ void setFileIconName( const QString &icon );
|
|
+
|
|
+ /**
|
|
+ * Returns the EmbeddedFile of this annotation.
|
|
+ */
|
|
+ EmbeddedFile* embeddedFile() const;
|
|
+ /**
|
|
+ * Sets a new EmbeddedFile for this annotation.
|
|
+ *
|
|
+ * \note FileAttachmentAnnotation takes ownership of the object
|
|
+ */
|
|
+ void setEmbeddedFile( EmbeddedFile *ef );
|
|
+
|
|
+ private:
|
|
+ FileAttachmentAnnotation();
|
|
+ FileAttachmentAnnotation( const QDomNode &node );
|
|
+ FileAttachmentAnnotation( FileAttachmentAnnotationPrivate &dd );
|
|
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const;
|
|
+ Q_DECLARE_PRIVATE( FileAttachmentAnnotation )
|
|
+ Q_DISABLE_COPY( FileAttachmentAnnotation )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \short Sound annotation.
|
|
+ *
|
|
+ * The sound annotation represents a sound to be played when activated.
|
|
+ *
|
|
+ * \since 0.10
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT SoundAnnotation : public Annotation
|
|
+{
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ virtual ~SoundAnnotation();
|
|
+ virtual SubType subType() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the name of the icon of this annotation.
|
|
+ */
|
|
+ QString soundIconName() const;
|
|
+ /**
|
|
+ * Sets a new name for the icon of this annotation.
|
|
+ */
|
|
+ void setSoundIconName( const QString &icon );
|
|
+
|
|
+ /**
|
|
+ * Returns the SoundObject of this annotation.
|
|
+ */
|
|
+ SoundObject* sound() const;
|
|
+ /**
|
|
+ * Sets a new SoundObject for this annotation.
|
|
+ *
|
|
+ * \note SoundAnnotation takes ownership of the object
|
|
+ */
|
|
+ void setSound( SoundObject *ef );
|
|
+
|
|
+ private:
|
|
+ SoundAnnotation();
|
|
+ SoundAnnotation( const QDomNode &node );
|
|
+ SoundAnnotation( SoundAnnotationPrivate &dd );
|
|
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const;
|
|
+ Q_DECLARE_PRIVATE( SoundAnnotation )
|
|
+ Q_DISABLE_COPY( SoundAnnotation )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \short Movie annotation.
|
|
+ *
|
|
+ * The movie annotation represents a movie to be played when activated.
|
|
+ *
|
|
+ * \since 0.10
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT MovieAnnotation : public Annotation
|
|
+{
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ virtual ~MovieAnnotation();
|
|
+ virtual SubType subType() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the MovieObject of this annotation.
|
|
+ */
|
|
+ MovieObject* movie() const;
|
|
+ /**
|
|
+ * Sets a new MovieObject for this annotation.
|
|
+ *
|
|
+ * \note MovieAnnotation takes ownership of the object
|
|
+ */
|
|
+ void setMovie( MovieObject *movie );
|
|
+
|
|
+ /**
|
|
+ * Returns the title of the movie of this annotation.
|
|
+ */
|
|
+ QString movieTitle() const;
|
|
+ /**
|
|
+ * Sets a new title for the movie of this annotation.
|
|
+ */
|
|
+ void setMovieTitle( const QString &title );
|
|
+
|
|
+ private:
|
|
+ MovieAnnotation();
|
|
+ MovieAnnotation( const QDomNode &node );
|
|
+ MovieAnnotation( MovieAnnotationPrivate &dd );
|
|
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const;
|
|
+ Q_DECLARE_PRIVATE( MovieAnnotation )
|
|
+ Q_DISABLE_COPY( MovieAnnotation )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \short Screen annotation.
|
|
+ *
|
|
+ * The screen annotation represents a screen to be played when activated.
|
|
+ *
|
|
+ * \since 0.20
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT ScreenAnnotation : public Annotation
|
|
+{
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ virtual ~ScreenAnnotation();
|
|
+
|
|
+ virtual SubType subType() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the LinkRendition of this annotation.
|
|
+ */
|
|
+ LinkRendition* action() const;
|
|
+
|
|
+ /**
|
|
+ * Sets a new LinkRendition for this annotation.
|
|
+ *
|
|
+ * \note ScreenAnnotation takes ownership of the object
|
|
+ */
|
|
+ void setAction( LinkRendition *action );
|
|
+
|
|
+ /**
|
|
+ * Returns the title of the screen of this annotation.
|
|
+ */
|
|
+ QString screenTitle() const;
|
|
+
|
|
+ /**
|
|
+ * Sets a new title for the screen of this annotation.
|
|
+ */
|
|
+ void setScreenTitle( const QString &title );
|
|
+
|
|
+ /**
|
|
+ * Returns the additional action of the given @p type fo the annotation or
|
|
+ * @c 0 if no action has been defined.
|
|
+ *
|
|
+ * \since 0.22
|
|
+ */
|
|
+ Link* additionalAction( AdditionalActionType type ) const;
|
|
+
|
|
+ private:
|
|
+ ScreenAnnotation();
|
|
+ ScreenAnnotation( ScreenAnnotationPrivate &dd );
|
|
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const; // stub
|
|
+ Q_DECLARE_PRIVATE( ScreenAnnotation )
|
|
+ Q_DISABLE_COPY( ScreenAnnotation )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \short Widget annotation.
|
|
+ *
|
|
+ * The widget annotation represents a widget (form field) on a page.
|
|
+ *
|
|
+ * \note This class is just provided for consistency of the annotation API,
|
|
+ * use the FormField classes to get all the form-related information.
|
|
+ *
|
|
+ * \since 0.22
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT WidgetAnnotation : public Annotation
|
|
+{
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ virtual ~WidgetAnnotation();
|
|
+
|
|
+ virtual SubType subType() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the additional action of the given @p type fo the annotation or
|
|
+ * @c 0 if no action has been defined.
|
|
+ *
|
|
+ * \since 0.22
|
|
+ */
|
|
+ Link* additionalAction( AdditionalActionType type ) const;
|
|
+
|
|
+ private:
|
|
+ WidgetAnnotation();
|
|
+ WidgetAnnotation( WidgetAnnotationPrivate &dd );
|
|
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const; // stub
|
|
+ Q_DECLARE_PRIVATE( WidgetAnnotation )
|
|
+ Q_DISABLE_COPY( WidgetAnnotation )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \short RichMedia annotation.
|
|
+ *
|
|
+ * The RichMedia annotation represents a video or sound on a page.
|
|
+ *
|
|
+ * \since 0.36
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT RichMediaAnnotation : public Annotation
|
|
+{
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ virtual ~RichMediaAnnotation();
|
|
+
|
|
+ virtual SubType subType() const;
|
|
+
|
|
+ /**
|
|
+ * The params object of a RichMediaAnnotation::Instance object.
|
|
+ *
|
|
+ * The params object provides media specific parameters, to play
|
|
+ * back the media inside the PDF viewer.
|
|
+ *
|
|
+ * At the moment only parameters for flash player are supported.
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT Params
|
|
+ {
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ Params();
|
|
+ ~Params();
|
|
+
|
|
+ /**
|
|
+ * Returns the parameters for the flash player.
|
|
+ */
|
|
+ QString flashVars() const;
|
|
+
|
|
+ private:
|
|
+ void setFlashVars( const QString &flashVars );
|
|
+
|
|
+ class Private;
|
|
+ QScopedPointer<Private> d;
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ * The instance object of a RichMediaAnnotation::Configuration object.
|
|
+ *
|
|
+ * The instance object represents one media object, that should be shown
|
|
+ * on the page. It has a media type and a Params object, to define the
|
|
+ * media specific parameters.
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT Instance
|
|
+ {
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ /**
|
|
+ * Describes the media type of the instance.
|
|
+ */
|
|
+ enum Type
|
|
+ {
|
|
+ Type3D, ///< A 3D media file.
|
|
+ TypeFlash, ///< A Flash media file.
|
|
+ TypeSound, ///< A sound media file.
|
|
+ TypeVideo ///< A video media file.
|
|
+ };
|
|
+
|
|
+ Instance();
|
|
+ ~Instance();
|
|
+
|
|
+ /**
|
|
+ * Returns the media type of the instance.
|
|
+ */
|
|
+ Type type() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the params object of the instance or @c 0 if it doesn't exist.
|
|
+ */
|
|
+ RichMediaAnnotation::Params* params() const;
|
|
+
|
|
+ private:
|
|
+ void setType( Type type );
|
|
+ void setParams( RichMediaAnnotation::Params *params );
|
|
+
|
|
+ class Private;
|
|
+ QScopedPointer<Private> d;
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ * The configuration object of a RichMediaAnnotation::Content object.
|
|
+ *
|
|
+ * The configuration object provides access to the various Instance objects
|
|
+ * of the rich media annotation.
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT Configuration
|
|
+ {
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ /**
|
|
+ * Describes the media type of the configuration.
|
|
+ */
|
|
+ enum Type
|
|
+ {
|
|
+ Type3D, ///< A 3D media file.
|
|
+ TypeFlash, ///< A Flash media file.
|
|
+ TypeSound, ///< A sound media file.
|
|
+ TypeVideo ///< A video media file.
|
|
+ };
|
|
+
|
|
+ Configuration();
|
|
+ ~Configuration();
|
|
+
|
|
+ /**
|
|
+ * Returns the media type of the configuration.
|
|
+ */
|
|
+ Type type() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the name of the configuration.
|
|
+ */
|
|
+ QString name() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the list of Instance objects of the configuration.
|
|
+ */
|
|
+ QList< RichMediaAnnotation::Instance* > instances() const;
|
|
+
|
|
+ private:
|
|
+ void setType( Type type );
|
|
+ void setName( const QString &name );
|
|
+ void setInstances( const QList< RichMediaAnnotation::Instance* > &instances );
|
|
+
|
|
+ class Private;
|
|
+ QScopedPointer<Private> d;
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ * The asset object of a RichMediaAnnotation::Content object.
|
|
+ *
|
|
+ * The asset object provides a mapping between identifier name, as
|
|
+ * used in the flash vars string of RichMediaAnnotation::Params, and the
|
|
+ * associated file spec object.
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT Asset
|
|
+ {
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ Asset();
|
|
+ ~Asset();
|
|
+
|
|
+ /**
|
|
+ * Returns the identifier name of the asset.
|
|
+ */
|
|
+ QString name() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the embedded file the asset points to.
|
|
+ */
|
|
+ EmbeddedFile* embeddedFile() const;
|
|
+
|
|
+ private:
|
|
+ void setName( const QString &name );
|
|
+ void setEmbeddedFile( EmbeddedFile *embeddedFile );
|
|
+
|
|
+ class Private;
|
|
+ QScopedPointer<Private> d;
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ * The content object of a RichMediaAnnotation.
|
|
+ *
|
|
+ * The content object provides access to the list of configurations
|
|
+ * and assets of the rich media annotation.
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT Content
|
|
+ {
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ Content();
|
|
+ ~Content();
|
|
+
|
|
+ /**
|
|
+ * Returns the list of configuration objects of the content object.
|
|
+ */
|
|
+ QList< RichMediaAnnotation::Configuration* > configurations() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the list of asset objects of the content object.
|
|
+ */
|
|
+ QList< RichMediaAnnotation::Asset* > assets() const;
|
|
+
|
|
+ private:
|
|
+ void setConfigurations( const QList< RichMediaAnnotation::Configuration* > &configurations );
|
|
+ void setAssets( const QList< RichMediaAnnotation::Asset* > &assets );
|
|
+
|
|
+ class Private;
|
|
+ QScopedPointer<Private> d;
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ * The activation object of the RichMediaAnnotation::Settings object.
|
|
+ *
|
|
+ * The activation object is a wrapper around the settings for the activation
|
|
+ * state. At the moment it provides only the activation condition.
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT Activation
|
|
+ {
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ /**
|
|
+ * Describes the condition for activating the rich media.
|
|
+ */
|
|
+ enum Condition {
|
|
+ PageOpened, ///< Activate when page is opened.
|
|
+ PageVisible, ///< Activate when page becomes visible.
|
|
+ UserAction ///< Activate when user interacts with the annotation.
|
|
+ };
|
|
+
|
|
+ Activation();
|
|
+ ~Activation();
|
|
+
|
|
+ /**
|
|
+ * Returns the activation condition.
|
|
+ */
|
|
+ Condition condition() const;
|
|
+
|
|
+ private:
|
|
+ void setCondition( Condition condition );
|
|
+
|
|
+ class Private;
|
|
+ QScopedPointer<Private> d;
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ * The deactivation object of the RichMediaAnnotation::Settings object.
|
|
+ *
|
|
+ * The deactivation object is a wrapper around the settings for the deactivation
|
|
+ * state. At the moment it provides only the deactivation condition.
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT Deactivation
|
|
+ {
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ /**
|
|
+ * Describes the condition for deactivating the rich media.
|
|
+ */
|
|
+ enum Condition {
|
|
+ PageClosed, ///< Deactivate when page is closed.
|
|
+ PageInvisible, ///< Deactivate when page becomes invisible.
|
|
+ UserAction ///< Deactivate when user interacts with the annotation.
|
|
+ };
|
|
+
|
|
+ Deactivation();
|
|
+ ~Deactivation();
|
|
+
|
|
+ /**
|
|
+ * Returns the deactivation condition.
|
|
+ */
|
|
+ Condition condition() const;
|
|
+
|
|
+ private:
|
|
+ void setCondition( Condition condition );
|
|
+
|
|
+ class Private;
|
|
+ QScopedPointer<Private> d;
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ * The settings object of a RichMediaAnnotation.
|
|
+ *
|
|
+ * The settings object provides access to the configuration objects
|
|
+ * for annotation activation and deactivation.
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT Settings
|
|
+ {
|
|
+ friend class AnnotationPrivate;
|
|
+
|
|
+ public:
|
|
+ Settings();
|
|
+ ~Settings();
|
|
+
|
|
+ /**
|
|
+ * Returns the Activation object of the settings object or @c 0 if it doesn't exist.
|
|
+ */
|
|
+ RichMediaAnnotation::Activation* activation() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the Deactivation object of the settings object or @c 0 if it doesn't exist.
|
|
+ */
|
|
+ RichMediaAnnotation::Deactivation* deactivation() const;
|
|
+
|
|
+ private:
|
|
+ void setActivation( RichMediaAnnotation::Activation *activation );
|
|
+ void setDeactivation( RichMediaAnnotation::Deactivation *deactivation );
|
|
+
|
|
+ class Private;
|
|
+ QScopedPointer<Private> d;
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ * Returns the Settings object of the rich media annotation or @c 0 if it doesn't exist.
|
|
+ */
|
|
+ RichMediaAnnotation::Settings* settings() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the Content object of the rich media annotation or @c 0 if it doesn't exist.
|
|
+ */
|
|
+ RichMediaAnnotation::Content* content() const;
|
|
+
|
|
+ private:
|
|
+ void setSettings( RichMediaAnnotation::Settings *settings );
|
|
+ void setContent( RichMediaAnnotation::Content *content );
|
|
+
|
|
+ RichMediaAnnotation();
|
|
+ RichMediaAnnotation( const QDomNode &node );
|
|
+ RichMediaAnnotation( RichMediaAnnotationPrivate &dd );
|
|
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const;
|
|
+ Q_DECLARE_PRIVATE( RichMediaAnnotation )
|
|
+ Q_DISABLE_COPY( RichMediaAnnotation )
|
|
+};
|
|
+
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-base-converter.cc b/qt4/src/poppler-base-converter.cc
|
|
new file mode 100644
|
|
index 00000000..11ff17ca
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-base-converter.cc
|
|
@@ -0,0 +1,105 @@
|
|
+/* poppler-base-converter.cc: qt interface to poppler
|
|
+ * Copyright (C) 2007, 2009, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-qt4.h"
|
|
+
|
|
+#include "poppler-converter-private.h"
|
|
+
|
|
+#include <QtCore/QFile>
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+BaseConverterPrivate::BaseConverterPrivate()
|
|
+ : document(0), iodev(0), ownIodev(true)
|
|
+{
|
|
+}
|
|
+
|
|
+BaseConverterPrivate::~BaseConverterPrivate()
|
|
+{
|
|
+}
|
|
+
|
|
+QIODevice* BaseConverterPrivate::openDevice()
|
|
+{
|
|
+ if (!iodev)
|
|
+ {
|
|
+ Q_ASSERT(!outputFileName.isEmpty());
|
|
+ QFile *f = new QFile(outputFileName);
|
|
+ iodev = f;
|
|
+ ownIodev = true;
|
|
+ }
|
|
+ Q_ASSERT(iodev);
|
|
+ if (!iodev->isOpen())
|
|
+ {
|
|
+ if (!iodev->open(QIODevice::WriteOnly))
|
|
+ {
|
|
+ if (ownIodev)
|
|
+ {
|
|
+ delete iodev;
|
|
+ iodev = 0;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return iodev;
|
|
+}
|
|
+
|
|
+void BaseConverterPrivate::closeDevice()
|
|
+{
|
|
+ if (ownIodev)
|
|
+ {
|
|
+ iodev->close();
|
|
+ delete iodev;
|
|
+ iodev = 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+BaseConverter::BaseConverter(BaseConverterPrivate &dd)
|
|
+ : d_ptr(&dd)
|
|
+{
|
|
+}
|
|
+
|
|
+BaseConverter::~BaseConverter()
|
|
+{
|
|
+ delete d_ptr;
|
|
+}
|
|
+
|
|
+void BaseConverter::setOutputFileName(const QString &outputFileName)
|
|
+{
|
|
+ Q_D(BaseConverter);
|
|
+ d->outputFileName = outputFileName;
|
|
+}
|
|
+
|
|
+void BaseConverter::setOutputDevice(QIODevice *device)
|
|
+{
|
|
+ Q_D(BaseConverter);
|
|
+ d->iodev = device;
|
|
+ d->ownIodev = false;
|
|
+}
|
|
+
|
|
+BaseConverter::Error BaseConverter::lastError() const
|
|
+{
|
|
+ Q_D(const BaseConverter);
|
|
+ return d->lastError;
|
|
+}
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-converter-private.h b/qt4/src/poppler-converter-private.h
|
|
new file mode 100644
|
|
index 00000000..dc3e9437
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-converter-private.h
|
|
@@ -0,0 +1,49 @@
|
|
+/* poppler-converter-private.h: Qt4 interface to poppler
|
|
+ * Copyright (C) 2007, 2009, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef POPPLER_QT4_CONVERTER_PRIVATE_H
|
|
+#define POPPLER_QT4_CONVERTER_PRIVATE_H
|
|
+
|
|
+#include <QtCore/QString>
|
|
+
|
|
+class QIODevice;
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+class DocumentData;
|
|
+
|
|
+class BaseConverterPrivate
|
|
+{
|
|
+ public:
|
|
+ BaseConverterPrivate();
|
|
+ virtual ~BaseConverterPrivate();
|
|
+
|
|
+ QIODevice* openDevice();
|
|
+ void closeDevice();
|
|
+
|
|
+ DocumentData *document;
|
|
+ QString outputFileName;
|
|
+ QIODevice *iodev;
|
|
+ bool ownIodev : 1;
|
|
+ BaseConverter::Error lastError;
|
|
+};
|
|
+
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-document.cc b/qt4/src/poppler-document.cc
|
|
new file mode 100644
|
|
index 00000000..d6e2fbf7
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-document.cc
|
|
@@ -0,0 +1,850 @@
|
|
+/* poppler-document.cc: qt interface to poppler
|
|
+ * Copyright (C) 2005, Net Integration Technologies, Inc.
|
|
+ * Copyright (C) 2005, 2008, Brad Hards <bradh@frogmouth.net>
|
|
+ * Copyright (C) 2005-2010, 2012, 2013, 2015-2017, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2006-2010, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2010, 2011 Hib Eris <hib@hiberis.nl>
|
|
+ * Copyright (C) 2012 Koji Otani <sho@bbr.jp>
|
|
+ * Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
|
|
+ * Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
|
|
+ * Copyright (C) 2014 Adam Reichold <adamreichold@myopera.com>
|
|
+ * Copyright (C) 2015 William Bader <williambader@hotmail.com>
|
|
+ * Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com>
|
|
+ * Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-qt4.h"
|
|
+
|
|
+#include <config.h>
|
|
+#include <ErrorCodes.h>
|
|
+#include <GlobalParams.h>
|
|
+#include <Outline.h>
|
|
+#include <PDFDoc.h>
|
|
+#include <Stream.h>
|
|
+#include <Catalog.h>
|
|
+#include <ViewerPreferences.h>
|
|
+#include <DateInfo.h>
|
|
+#include <GfxState.h>
|
|
+
|
|
+#include <QtCore/QDebug>
|
|
+#include <QtCore/QFile>
|
|
+#include <QtCore/QByteArray>
|
|
+
|
|
+#include "poppler-private.h"
|
|
+#include "poppler-page-private.h"
|
|
+
|
|
+#if defined(USE_CMS)
|
|
+#if defined(USE_LCMS1)
|
|
+#include <lcms.h>
|
|
+#else
|
|
+#include <lcms2.h>
|
|
+#endif
|
|
+#endif
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+ int DocumentData::count = 0;
|
|
+
|
|
+ Document *Document::load(const QString &filePath, const QByteArray &ownerPassword,
|
|
+ const QByteArray &userPassword)
|
|
+ {
|
|
+ DocumentData *doc = new DocumentData(filePath,
|
|
+ new GooString(ownerPassword.data()),
|
|
+ new GooString(userPassword.data()));
|
|
+ return DocumentData::checkDocument(doc);
|
|
+ }
|
|
+
|
|
+ Document *Document::loadFromData(const QByteArray &fileContents,
|
|
+ const QByteArray &ownerPassword,
|
|
+ const QByteArray &userPassword)
|
|
+ {
|
|
+ // create stream
|
|
+ DocumentData *doc = new DocumentData(fileContents,
|
|
+ new GooString(ownerPassword.data()),
|
|
+ new GooString(userPassword.data()));
|
|
+ return DocumentData::checkDocument(doc);
|
|
+ }
|
|
+
|
|
+ Document *DocumentData::checkDocument(DocumentData *doc)
|
|
+ {
|
|
+ Document *pdoc;
|
|
+ if (doc->doc->isOk() || doc->doc->getErrorCode() == errEncrypted) {
|
|
+ pdoc = new Document(doc);
|
|
+ if (doc->doc->getErrorCode() == errEncrypted)
|
|
+ pdoc->m_doc->locked = true;
|
|
+ else
|
|
+ {
|
|
+ pdoc->m_doc->locked = false;
|
|
+ pdoc->m_doc->fillMembers();
|
|
+ }
|
|
+ return pdoc;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ delete doc;
|
|
+ }
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ Document::Document(DocumentData *dataA)
|
|
+ {
|
|
+ m_doc = dataA;
|
|
+ }
|
|
+
|
|
+ Document::~Document()
|
|
+ {
|
|
+ delete m_doc;
|
|
+ }
|
|
+
|
|
+ Page *Document::page(int index) const
|
|
+ {
|
|
+ Page *page = new Page(m_doc, index);
|
|
+ if (page->m_page->page == NULL) {
|
|
+ delete page;
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return page;
|
|
+ }
|
|
+
|
|
+ bool Document::isLocked() const
|
|
+ {
|
|
+ return m_doc->locked;
|
|
+ }
|
|
+
|
|
+ bool Document::unlock(const QByteArray &ownerPassword,
|
|
+ const QByteArray &userPassword)
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ /* racier then it needs to be */
|
|
+ DocumentData *doc2;
|
|
+ if (!m_doc->fileContents.isEmpty())
|
|
+ {
|
|
+ doc2 = new DocumentData(m_doc->fileContents,
|
|
+ new GooString(ownerPassword.data()),
|
|
+ new GooString(userPassword.data()));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ doc2 = new DocumentData(m_doc->m_filePath,
|
|
+ new GooString(ownerPassword.data()),
|
|
+ new GooString(userPassword.data()));
|
|
+ }
|
|
+ if (!doc2->doc->isOk()) {
|
|
+ delete doc2;
|
|
+ } else {
|
|
+ delete m_doc;
|
|
+ m_doc = doc2;
|
|
+ m_doc->locked = false;
|
|
+ m_doc->fillMembers();
|
|
+ }
|
|
+ }
|
|
+ return m_doc->locked;
|
|
+ }
|
|
+
|
|
+ Document::PageMode Document::pageMode() const
|
|
+ {
|
|
+ switch (m_doc->doc->getCatalog()->getPageMode()) {
|
|
+ case Catalog::pageModeNone:
|
|
+ return UseNone;
|
|
+ case Catalog::pageModeOutlines:
|
|
+ return UseOutlines;
|
|
+ case Catalog::pageModeThumbs:
|
|
+ return UseThumbs;
|
|
+ case Catalog::pageModeFullScreen:
|
|
+ return FullScreen;
|
|
+ case Catalog::pageModeOC:
|
|
+ return UseOC;
|
|
+ case Catalog::pageModeAttach:
|
|
+ return UseAttach;
|
|
+ default:
|
|
+ return UseNone;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ Document::PageLayout Document::pageLayout() const
|
|
+ {
|
|
+ switch (m_doc->doc->getCatalog()->getPageLayout()) {
|
|
+ case Catalog::pageLayoutNone:
|
|
+ return NoLayout;
|
|
+ case Catalog::pageLayoutSinglePage:
|
|
+ return SinglePage;
|
|
+ case Catalog::pageLayoutOneColumn:
|
|
+ return OneColumn;
|
|
+ case Catalog::pageLayoutTwoColumnLeft:
|
|
+ return TwoColumnLeft;
|
|
+ case Catalog::pageLayoutTwoColumnRight:
|
|
+ return TwoColumnRight;
|
|
+ case Catalog::pageLayoutTwoPageLeft:
|
|
+ return TwoPageLeft;
|
|
+ case Catalog::pageLayoutTwoPageRight:
|
|
+ return TwoPageRight;
|
|
+ default:
|
|
+ return NoLayout;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ Qt::LayoutDirection Document::textDirection() const
|
|
+ {
|
|
+ if (!m_doc->doc->getCatalog()->getViewerPreferences())
|
|
+ return Qt::LayoutDirectionAuto;
|
|
+
|
|
+ switch (m_doc->doc->getCatalog()->getViewerPreferences()->getDirection()) {
|
|
+ case ViewerPreferences::directionL2R:
|
|
+ return Qt::LeftToRight;
|
|
+ case ViewerPreferences::directionR2L:
|
|
+ return Qt::RightToLeft;
|
|
+ default:
|
|
+ return Qt::LayoutDirectionAuto;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ int Document::numPages() const
|
|
+ {
|
|
+ return m_doc->doc->getNumPages();
|
|
+ }
|
|
+
|
|
+ QList<FontInfo> Document::fonts() const
|
|
+ {
|
|
+ QList<FontInfo> ourList;
|
|
+ FontIterator it( 0, m_doc );
|
|
+ while ( it.hasNext() )
|
|
+ {
|
|
+ ourList += it.next();
|
|
+ }
|
|
+ return ourList;
|
|
+ }
|
|
+
|
|
+ QList<EmbeddedFile*> Document::embeddedFiles() const
|
|
+ {
|
|
+ return m_doc->m_embeddedFiles;
|
|
+ }
|
|
+
|
|
+ bool Document::scanForFonts( int numPages, QList<FontInfo> *fontList ) const
|
|
+ {
|
|
+ if ( !m_doc->m_fontInfoIterator )
|
|
+ return false;
|
|
+ if ( !m_doc->m_fontInfoIterator->hasNext() )
|
|
+ return false;
|
|
+ while ( m_doc->m_fontInfoIterator->hasNext() && numPages )
|
|
+ {
|
|
+ (*fontList) += m_doc->m_fontInfoIterator->next();
|
|
+ --numPages;
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ FontIterator* Document::newFontIterator( int startPage ) const
|
|
+ {
|
|
+ return new FontIterator( startPage, m_doc );
|
|
+ }
|
|
+
|
|
+ QByteArray Document::fontData(const FontInfo &fi) const
|
|
+ {
|
|
+ QByteArray result;
|
|
+ if (fi.isEmbedded())
|
|
+ {
|
|
+ XRef *xref = m_doc->doc->getXRef()->copy();
|
|
+
|
|
+ Object refObj(fi.m_data->embRef);
|
|
+ Object strObj = refObj.fetch(xref);
|
|
+ if (strObj.isStream())
|
|
+ {
|
|
+ int c;
|
|
+ strObj.streamReset();
|
|
+ while ((c = strObj.streamGetChar()) != EOF)
|
|
+ {
|
|
+ result.append((char)c);
|
|
+ }
|
|
+ strObj.streamClose();
|
|
+ }
|
|
+ delete xref;
|
|
+ }
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ QString Document::info( const QString & type ) const
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return QString();
|
|
+ }
|
|
+
|
|
+ QScopedPointer<GooString> goo(m_doc->doc->getDocInfoStringEntry(type.toLatin1().constData()));
|
|
+ return UnicodeParsedString(goo.data());
|
|
+ }
|
|
+
|
|
+ bool Document::setInfo( const QString & key, const QString & val )
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ GooString *goo = QStringToUnicodeGooString(val);
|
|
+ m_doc->doc->setDocInfoStringEntry(key.toLatin1().constData(), goo);
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ QString Document::title() const
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return QString();
|
|
+ }
|
|
+
|
|
+ QScopedPointer<GooString> goo(m_doc->doc->getDocInfoTitle());
|
|
+ return UnicodeParsedString(goo.data());
|
|
+ }
|
|
+
|
|
+ bool Document::setTitle( const QString & val )
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ m_doc->doc->setDocInfoTitle(QStringToUnicodeGooString(val));
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ QString Document::author() const
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return QString();
|
|
+ }
|
|
+
|
|
+ QScopedPointer<GooString> goo(m_doc->doc->getDocInfoAuthor());
|
|
+ return UnicodeParsedString(goo.data());
|
|
+ }
|
|
+
|
|
+ bool Document::setAuthor( const QString & val )
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ m_doc->doc->setDocInfoAuthor(QStringToUnicodeGooString(val));
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ QString Document::subject() const
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return QString();
|
|
+ }
|
|
+
|
|
+ QScopedPointer<GooString> goo(m_doc->doc->getDocInfoSubject());
|
|
+ return UnicodeParsedString(goo.data());
|
|
+ }
|
|
+
|
|
+ bool Document::setSubject( const QString & val )
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ m_doc->doc->setDocInfoSubject(QStringToUnicodeGooString(val));
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ QString Document::keywords() const
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return QString();
|
|
+ }
|
|
+
|
|
+ QScopedPointer<GooString> goo(m_doc->doc->getDocInfoKeywords());
|
|
+ return UnicodeParsedString(goo.data());
|
|
+ }
|
|
+
|
|
+ bool Document::setKeywords( const QString & val )
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ m_doc->doc->setDocInfoKeywords(QStringToUnicodeGooString(val));
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ QString Document::creator() const
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return QString();
|
|
+ }
|
|
+
|
|
+ QScopedPointer<GooString> goo(m_doc->doc->getDocInfoCreator());
|
|
+ return UnicodeParsedString(goo.data());
|
|
+ }
|
|
+
|
|
+ bool Document::setCreator( const QString & val )
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ m_doc->doc->setDocInfoCreator(QStringToUnicodeGooString(val));
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ QString Document::producer() const
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return QString();
|
|
+ }
|
|
+
|
|
+ QScopedPointer<GooString> goo(m_doc->doc->getDocInfoProducer());
|
|
+ return UnicodeParsedString(goo.data());
|
|
+ }
|
|
+
|
|
+ bool Document::setProducer( const QString & val )
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ m_doc->doc->setDocInfoProducer(QStringToUnicodeGooString(val));
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ bool Document::removeInfo()
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ m_doc->doc->removeDocInfo();
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ QStringList Document::infoKeys() const
|
|
+ {
|
|
+ QStringList keys;
|
|
+
|
|
+ if ( m_doc->locked )
|
|
+ return QStringList();
|
|
+
|
|
+ QScopedPointer<XRef> xref(m_doc->doc->getXRef()->copy());
|
|
+ if (!xref)
|
|
+ return QStringList();
|
|
+ Object info = xref->getDocInfo();
|
|
+ if ( !info.isDict() )
|
|
+ return QStringList();
|
|
+
|
|
+ Dict *infoDict = info.getDict();
|
|
+ // somehow iterate over keys in infoDict
|
|
+ keys.reserve( infoDict->getLength() );
|
|
+ for( int i=0; i < infoDict->getLength(); ++i ) {
|
|
+ keys.append( QString::fromAscii(infoDict->getKey(i)) );
|
|
+ }
|
|
+
|
|
+ return keys;
|
|
+ }
|
|
+
|
|
+ QDateTime Document::date( const QString & type ) const
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return QDateTime();
|
|
+ }
|
|
+
|
|
+ QScopedPointer<GooString> goo(m_doc->doc->getDocInfoStringEntry(type.toLatin1().constData()));
|
|
+ QString str = UnicodeParsedString(goo.data());
|
|
+ return Poppler::convertDate(str.toLatin1().data());
|
|
+ }
|
|
+
|
|
+ bool Document::setDate( const QString & key, const QDateTime & val )
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ m_doc->doc->setDocInfoStringEntry(key.toLatin1().constData(), QDateTimeToUnicodeGooString(val));
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ QDateTime Document::creationDate() const
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return QDateTime();
|
|
+ }
|
|
+
|
|
+ QScopedPointer<GooString> goo(m_doc->doc->getDocInfoCreatDate());
|
|
+ QString str = UnicodeParsedString(goo.data());
|
|
+ return Poppler::convertDate(str.toLatin1().data());
|
|
+ }
|
|
+
|
|
+ bool Document::setCreationDate( const QDateTime & val )
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ m_doc->doc->setDocInfoCreatDate(QDateTimeToUnicodeGooString(val));
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ QDateTime Document::modificationDate() const
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return QDateTime();
|
|
+ }
|
|
+
|
|
+ QScopedPointer<GooString> goo(m_doc->doc->getDocInfoModDate());
|
|
+ QString str = UnicodeParsedString(goo.data());
|
|
+ return Poppler::convertDate(str.toLatin1().data());
|
|
+ }
|
|
+
|
|
+ bool Document::setModificationDate( const QDateTime & val )
|
|
+ {
|
|
+ if (m_doc->locked) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ m_doc->doc->setDocInfoModDate(QDateTimeToUnicodeGooString(val));
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ bool Document::isEncrypted() const
|
|
+ {
|
|
+ return m_doc->doc->isEncrypted();
|
|
+ }
|
|
+
|
|
+ bool Document::isLinearized() const
|
|
+ {
|
|
+ return m_doc->doc->isLinearized();
|
|
+ }
|
|
+
|
|
+ bool Document::okToPrint() const
|
|
+ {
|
|
+ return m_doc->doc->okToPrint();
|
|
+ }
|
|
+
|
|
+ bool Document::okToPrintHighRes() const
|
|
+ {
|
|
+ return m_doc->doc->okToPrintHighRes();
|
|
+ }
|
|
+
|
|
+ bool Document::okToChange() const
|
|
+ {
|
|
+ return m_doc->doc->okToChange();
|
|
+ }
|
|
+
|
|
+ bool Document::okToCopy() const
|
|
+ {
|
|
+ return m_doc->doc->okToCopy();
|
|
+ }
|
|
+
|
|
+ bool Document::okToAddNotes() const
|
|
+ {
|
|
+ return m_doc->doc->okToAddNotes();
|
|
+ }
|
|
+
|
|
+ bool Document::okToFillForm() const
|
|
+ {
|
|
+ return m_doc->doc->okToFillForm();
|
|
+ }
|
|
+
|
|
+ bool Document::okToCreateFormFields() const
|
|
+ {
|
|
+ return ( okToFillForm() && okToChange() );
|
|
+ }
|
|
+
|
|
+ bool Document::okToExtractForAccessibility() const
|
|
+ {
|
|
+ return m_doc->doc->okToAccessibility();
|
|
+ }
|
|
+
|
|
+ bool Document::okToAssemble() const
|
|
+ {
|
|
+ return m_doc->doc->okToAssemble();
|
|
+ }
|
|
+
|
|
+ double Document::pdfVersion() const
|
|
+ {
|
|
+ return m_doc->doc->getPDFMajorVersion () + m_doc->doc->getPDFMinorVersion() / 10.0;
|
|
+ }
|
|
+
|
|
+ void Document::getPdfVersion(int *major, int *minor) const
|
|
+ {
|
|
+ if (major)
|
|
+ *major = m_doc->doc->getPDFMajorVersion();
|
|
+ if (minor)
|
|
+ *minor = m_doc->doc->getPDFMinorVersion();
|
|
+ }
|
|
+
|
|
+ Page *Document::page(const QString &label) const
|
|
+ {
|
|
+ GooString label_g(label.toAscii().data());
|
|
+ int index;
|
|
+
|
|
+ if (!m_doc->doc->getCatalog()->labelToIndex (&label_g, &index))
|
|
+ return NULL;
|
|
+
|
|
+ return page(index);
|
|
+ }
|
|
+
|
|
+ bool Document::hasEmbeddedFiles() const
|
|
+ {
|
|
+ return (!(0 == m_doc->doc->getCatalog()->numEmbeddedFiles()));
|
|
+ }
|
|
+
|
|
+ QDomDocument *Document::toc() const
|
|
+ {
|
|
+ Outline * outline = m_doc->doc->getOutline();
|
|
+ if ( !outline )
|
|
+ return NULL;
|
|
+
|
|
+ const std::vector<::OutlineItem*> * items = outline->getItems();
|
|
+ if ( !items || items->size() < 1 )
|
|
+ return NULL;
|
|
+
|
|
+ QDomDocument *toc = new QDomDocument();
|
|
+ if ( items->size() > 0 )
|
|
+ m_doc->addTocChildren( toc, toc, items );
|
|
+
|
|
+ return toc;
|
|
+ }
|
|
+
|
|
+ LinkDestination *Document::linkDestination( const QString &name )
|
|
+ {
|
|
+ GooString * namedDest = QStringToGooString( name );
|
|
+ LinkDestinationData ldd(NULL, namedDest, m_doc, false);
|
|
+ LinkDestination *ld = new LinkDestination(ldd);
|
|
+ delete namedDest;
|
|
+ return ld;
|
|
+ }
|
|
+
|
|
+ void Document::setPaperColor(const QColor &color)
|
|
+ {
|
|
+ m_doc->setPaperColor(color);
|
|
+ }
|
|
+
|
|
+ void Document::setColorDisplayProfile(void* outputProfileA)
|
|
+ {
|
|
+#if defined(USE_CMS)
|
|
+ GfxColorSpace::setDisplayProfile((cmsHPROFILE)outputProfileA);
|
|
+#else
|
|
+ Q_UNUSED(outputProfileA);
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ void Document::setColorDisplayProfileName(const QString &name)
|
|
+ {
|
|
+#if defined(USE_CMS)
|
|
+ GooString *profileName = QStringToGooString( name );
|
|
+ GfxColorSpace::setDisplayProfileName(profileName);
|
|
+ delete profileName;
|
|
+#else
|
|
+ Q_UNUSED(name);
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ void* Document::colorRgbProfile() const
|
|
+ {
|
|
+#if defined(USE_CMS)
|
|
+ return (void*)GfxColorSpace::getRGBProfile();
|
|
+#else
|
|
+ return NULL;
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ void* Document::colorDisplayProfile() const
|
|
+ {
|
|
+#if defined(USE_CMS)
|
|
+ return (void*)GfxColorSpace::getDisplayProfile();
|
|
+#else
|
|
+ return NULL;
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ QColor Document::paperColor() const
|
|
+ {
|
|
+ return m_doc->paperColor;
|
|
+ }
|
|
+
|
|
+ void Document::setRenderBackend( Document::RenderBackend backend )
|
|
+ {
|
|
+ // no need to delete the outputdev as for the moment we always create a splash one
|
|
+ // as the arthur one does not allow "precaching" due to it's signature
|
|
+ // delete m_doc->m_outputDev;
|
|
+ // m_doc->m_outputDev = NULL;
|
|
+ m_doc->m_backend = backend;
|
|
+ }
|
|
+
|
|
+ Document::RenderBackend Document::renderBackend() const
|
|
+ {
|
|
+ return m_doc->m_backend;
|
|
+ }
|
|
+
|
|
+ QSet<Document::RenderBackend> Document::availableRenderBackends()
|
|
+ {
|
|
+ QSet<Document::RenderBackend> ret;
|
|
+#if defined(HAVE_SPLASH)
|
|
+ ret << Document::SplashBackend;
|
|
+#endif
|
|
+ ret << Document::ArthurBackend;
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ void Document::setRenderHint( Document::RenderHint hint, bool on )
|
|
+ {
|
|
+ const bool touchesOverprinting = hint & Document::OverprintPreview;
|
|
+
|
|
+ int hintForOperation = hint;
|
|
+ if (touchesOverprinting && !isOverprintPreviewAvailable())
|
|
+ hintForOperation = hintForOperation & ~(int)Document::OverprintPreview;
|
|
+
|
|
+ if ( on )
|
|
+ m_doc->m_hints |= hintForOperation;
|
|
+ else
|
|
+ m_doc->m_hints &= ~hintForOperation;
|
|
+
|
|
+ }
|
|
+
|
|
+ Document::RenderHints Document::renderHints() const
|
|
+ {
|
|
+ return Document::RenderHints( m_doc->m_hints );
|
|
+ }
|
|
+
|
|
+ PSConverter *Document::psConverter() const
|
|
+ {
|
|
+ return new PSConverter(m_doc);
|
|
+ }
|
|
+
|
|
+ PDFConverter *Document::pdfConverter() const
|
|
+ {
|
|
+ return new PDFConverter(m_doc);
|
|
+ }
|
|
+
|
|
+ QString Document::metadata() const
|
|
+ {
|
|
+ QString result;
|
|
+ Catalog *catalog = m_doc->doc->getCatalog();
|
|
+ if (catalog && catalog->isOk())
|
|
+ {
|
|
+ GooString *s = catalog->readMetadata();
|
|
+ if (s) result = UnicodeParsedString(s);
|
|
+ delete s;
|
|
+ }
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ bool Document::hasOptionalContent() const
|
|
+ {
|
|
+ return ( m_doc->doc->getOptContentConfig() && m_doc->doc->getOptContentConfig()->hasOCGs() );
|
|
+ }
|
|
+
|
|
+ OptContentModel *Document::optionalContentModel()
|
|
+ {
|
|
+ if (m_doc->m_optContentModel.isNull()) {
|
|
+ m_doc->m_optContentModel = new OptContentModel(m_doc->doc->getOptContentConfig(), 0);
|
|
+ }
|
|
+ return (OptContentModel *)m_doc->m_optContentModel;
|
|
+ }
|
|
+
|
|
+ QStringList Document::scripts() const
|
|
+ {
|
|
+ Catalog *catalog = m_doc->doc->getCatalog();
|
|
+ const int numScripts = catalog->numJS();
|
|
+ QStringList scripts;
|
|
+ for (int i = 0; i < numScripts; ++i) {
|
|
+ GooString *s = catalog->getJS(i);
|
|
+ if (s) {
|
|
+ scripts.append(UnicodeParsedString(s));
|
|
+ delete s;
|
|
+ }
|
|
+ }
|
|
+ return scripts;
|
|
+ }
|
|
+
|
|
+ bool Document::getPdfId(QByteArray *permanentId, QByteArray *updateId) const
|
|
+ {
|
|
+ GooString gooPermanentId;
|
|
+ GooString gooUpdateId;
|
|
+
|
|
+ if (!m_doc->doc->getID(permanentId ? &gooPermanentId : 0, updateId ? &gooUpdateId : 0))
|
|
+ return false;
|
|
+
|
|
+ if (permanentId)
|
|
+ *permanentId = gooPermanentId.c_str();
|
|
+ if (updateId)
|
|
+ *updateId = gooUpdateId.c_str();
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ Document::FormType Document::formType() const
|
|
+ {
|
|
+ switch ( m_doc->doc->getCatalog()->getFormType() )
|
|
+ {
|
|
+ case Catalog::NoForm:
|
|
+ return Document::NoForm;
|
|
+ case Catalog::AcroForm:
|
|
+ return Document::AcroForm;
|
|
+ case Catalog::XfaForm:
|
|
+ return Document::XfaForm;
|
|
+ }
|
|
+
|
|
+ return Document::NoForm; // make gcc happy
|
|
+ }
|
|
+
|
|
+ QDateTime convertDate( char *dateString )
|
|
+ {
|
|
+ int year, mon, day, hour, min, sec, tzHours, tzMins;
|
|
+ char tz;
|
|
+
|
|
+ if ( parseDateString( dateString, &year, &mon, &day, &hour, &min, &sec, &tz, &tzHours, &tzMins ) )
|
|
+ {
|
|
+ QDate d( year, mon, day );
|
|
+ QTime t( hour, min, sec );
|
|
+ if ( d.isValid() && t.isValid() ) {
|
|
+ QDateTime dt( d, t, Qt::UTC );
|
|
+ if ( tz ) {
|
|
+ // then we have some form of timezone
|
|
+ if ( 'Z' == tz ) {
|
|
+ // We are already at UTC
|
|
+ } else if ( '+' == tz ) {
|
|
+ // local time is ahead of UTC
|
|
+ dt = dt.addSecs(-1*((tzHours*60)+tzMins)*60);
|
|
+ } else if ( '-' == tz ) {
|
|
+ // local time is behind UTC
|
|
+ dt = dt.addSecs(((tzHours*60)+tzMins)*60);
|
|
+ } else {
|
|
+ qWarning("unexpected tz val");
|
|
+ }
|
|
+ }
|
|
+ return dt;
|
|
+ }
|
|
+ }
|
|
+ return QDateTime();
|
|
+ }
|
|
+
|
|
+ bool isCmsAvailable()
|
|
+ {
|
|
+#if defined(USE_CMS)
|
|
+ return true;
|
|
+#else
|
|
+ return false;
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ bool isOverprintPreviewAvailable() {
|
|
+#ifdef SPLASH_CMYK
|
|
+ return true;
|
|
+#else
|
|
+ return false;
|
|
+#endif
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-embeddedfile-private.h b/qt4/src/poppler-embeddedfile-private.h
|
|
new file mode 100644
|
|
index 00000000..83549dad
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-embeddedfile-private.h
|
|
@@ -0,0 +1,42 @@
|
|
+/* poppler-embeddedfile-private.h: Qt4 interface to poppler
|
|
+ * Copyright (C) 2005, 2008, 2009, 2012, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2005, Brad Hards <bradh@frogmouth.net>
|
|
+ * Copyright (C) 2008, 2011, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef POPPLER_EMBEDDEDFILE_PRIVATE_H
|
|
+#define POPPLER_EMBEDDEDFILE_PRIVATE_H
|
|
+
|
|
+class FileSpec;
|
|
+
|
|
+namespace Poppler
|
|
+{
|
|
+
|
|
+class EmbeddedFileData
|
|
+{
|
|
+public:
|
|
+ EmbeddedFileData(FileSpec *fs);
|
|
+ ~EmbeddedFileData();
|
|
+
|
|
+ EmbFile *embFile() const;
|
|
+
|
|
+ FileSpec *filespec;
|
|
+};
|
|
+
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-embeddedfile.cc b/qt4/src/poppler-embeddedfile.cc
|
|
new file mode 100644
|
|
index 00000000..f70573ac
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-embeddedfile.cc
|
|
@@ -0,0 +1,135 @@
|
|
+/* poppler-document.cc: qt interface to poppler
|
|
+ * Copyright (C) 2005, 2008, 2009, 2012, 2013, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2005, Brad Hards <bradh@frogmouth.net>
|
|
+ * Copyright (C) 2008, 2011, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-qt4.h"
|
|
+
|
|
+#include <QtCore/QString>
|
|
+#include <QtCore/QDateTime>
|
|
+
|
|
+#include "Object.h"
|
|
+#include "Stream.h"
|
|
+#include "Catalog.h"
|
|
+#include "FileSpec.h"
|
|
+
|
|
+#include "poppler-private.h"
|
|
+#include "poppler-embeddedfile-private.h"
|
|
+
|
|
+namespace Poppler
|
|
+{
|
|
+
|
|
+EmbeddedFileData::EmbeddedFileData(FileSpec *fs)
|
|
+ : filespec(fs)
|
|
+{
|
|
+}
|
|
+
|
|
+EmbeddedFileData::~EmbeddedFileData()
|
|
+{
|
|
+ delete filespec;
|
|
+}
|
|
+
|
|
+EmbFile *EmbeddedFileData::embFile() const
|
|
+{
|
|
+ return filespec->isOk() ? filespec->getEmbeddedFile() : NULL;
|
|
+}
|
|
+
|
|
+
|
|
+EmbeddedFile::EmbeddedFile(EmbFile *embfile)
|
|
+ : m_embeddedFile(0)
|
|
+{
|
|
+ assert(!"You must not use this private constructor!");
|
|
+}
|
|
+
|
|
+EmbeddedFile::EmbeddedFile(EmbeddedFileData &dd)
|
|
+ : m_embeddedFile(&dd)
|
|
+{
|
|
+}
|
|
+
|
|
+EmbeddedFile::~EmbeddedFile()
|
|
+{
|
|
+ delete m_embeddedFile;
|
|
+}
|
|
+
|
|
+QString EmbeddedFile::name() const
|
|
+{
|
|
+ GooString *goo = m_embeddedFile->filespec->getFileName();
|
|
+ return goo ? UnicodeParsedString(goo) : QString();
|
|
+}
|
|
+
|
|
+QString EmbeddedFile::description() const
|
|
+{
|
|
+ GooString *goo = m_embeddedFile->filespec->getDescription();
|
|
+ return goo ? UnicodeParsedString(goo) : QString();
|
|
+}
|
|
+
|
|
+int EmbeddedFile::size() const
|
|
+{
|
|
+ return m_embeddedFile->embFile() ? m_embeddedFile->embFile()->size() : -1;
|
|
+}
|
|
+
|
|
+QDateTime EmbeddedFile::modDate() const
|
|
+{
|
|
+ GooString *goo = m_embeddedFile->embFile() ? m_embeddedFile->embFile()->modDate() : NULL;
|
|
+ return goo ? convertDate(goo->c_str()) : QDateTime();
|
|
+}
|
|
+
|
|
+QDateTime EmbeddedFile::createDate() const
|
|
+{
|
|
+ GooString *goo = m_embeddedFile->embFile() ? m_embeddedFile->embFile()->createDate() : NULL;
|
|
+ return goo ? convertDate(goo->c_str()) : QDateTime();
|
|
+}
|
|
+
|
|
+QByteArray EmbeddedFile::checksum() const
|
|
+{
|
|
+ GooString *goo = m_embeddedFile->embFile() ? m_embeddedFile->embFile()->checksum() : NULL;
|
|
+ return goo ? QByteArray::fromRawData(goo->c_str(), goo->getLength()) : QByteArray();
|
|
+}
|
|
+
|
|
+QString EmbeddedFile::mimeType() const
|
|
+{
|
|
+ GooString *goo = m_embeddedFile->embFile() ? m_embeddedFile->embFile()->mimeType() : NULL;
|
|
+ return goo ? QString(goo->c_str()) : QString();
|
|
+}
|
|
+
|
|
+QByteArray EmbeddedFile::data()
|
|
+{
|
|
+ if (!isValid())
|
|
+ return QByteArray();
|
|
+ Stream *stream = m_embeddedFile->embFile() ? m_embeddedFile->embFile()->stream() : NULL;
|
|
+ if (!stream)
|
|
+ return QByteArray();
|
|
+
|
|
+ stream->reset();
|
|
+ int dataLen = 0;
|
|
+ QByteArray fileArray;
|
|
+ int i;
|
|
+ while ( (i = stream->getChar()) != EOF) {
|
|
+ fileArray[dataLen] = (char)i;
|
|
+ ++dataLen;
|
|
+ }
|
|
+ fileArray.resize(dataLen);
|
|
+ return fileArray;
|
|
+}
|
|
+
|
|
+bool EmbeddedFile::isValid() const
|
|
+{
|
|
+ return m_embeddedFile->filespec->isOk();
|
|
+}
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-export.h b/qt4/src/poppler-export.h
|
|
new file mode 100644
|
|
index 00000000..2e2f6ff8
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-export.h
|
|
@@ -0,0 +1,20 @@
|
|
+/*
|
|
+* This file is used to set the poppler_qt4_EXPORT macros right.
|
|
+* This is needed for setting the visibility on windows, it will have no effect on other platforms.
|
|
+*/
|
|
+#if defined(_WIN32)
|
|
+# define _POPPLER_QT4_LIB_EXPORT __declspec(dllexport)
|
|
+# define _POPPLER_QT4_LIB_IMPORT __declspec(dllimport)
|
|
+#elif defined(__GNUC__)
|
|
+# define _POPPLER_QT4_LIB_EXPORT __attribute__((visibility("default")))
|
|
+# define _POPPLER_QT4_LIB_IMPORT
|
|
+#else
|
|
+# define _POPPLER_QT4_LIB_EXPORT
|
|
+# define _POPPLER_QT4_LIB_IMPORT
|
|
+#endif
|
|
+
|
|
+#ifdef poppler_qt4_EXPORTS
|
|
+# define POPPLER_QT4_EXPORT _POPPLER_QT4_LIB_EXPORT
|
|
+#else
|
|
+# define POPPLER_QT4_EXPORT _POPPLER_QT4_LIB_IMPORT
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-fontinfo.cc b/qt4/src/poppler-fontinfo.cc
|
|
new file mode 100644
|
|
index 00000000..5bb9e3a8
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-fontinfo.cc
|
|
@@ -0,0 +1,150 @@
|
|
+/* poppler-qt.h: qt interface to poppler
|
|
+ * Copyright (C) 2005, Net Integration Technologies, Inc.
|
|
+ * Copyright (C) 2005, Tobias Koening <tokoe@kde.org>
|
|
+ * Copyright (C) 2005, Brad Hards <bradh@frogmouth.net>
|
|
+ * Copyright (C) 2005-2008, 2015, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2008, 2009, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-qt4.h"
|
|
+#include "poppler-private.h"
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+FontInfo::FontInfo()
|
|
+{
|
|
+ m_data = new FontInfoData();
|
|
+}
|
|
+
|
|
+FontInfo::FontInfo( const FontInfoData &fid )
|
|
+{
|
|
+ m_data = new FontInfoData(fid);
|
|
+}
|
|
+
|
|
+FontInfo::FontInfo( const FontInfo &fi )
|
|
+{
|
|
+ m_data = new FontInfoData(*fi.m_data);
|
|
+}
|
|
+
|
|
+FontInfo::~FontInfo()
|
|
+{
|
|
+ delete m_data;
|
|
+}
|
|
+
|
|
+QString FontInfo::name() const
|
|
+{
|
|
+ return m_data->fontName;
|
|
+}
|
|
+
|
|
+QString FontInfo::file() const
|
|
+{
|
|
+ return m_data->fontFile;
|
|
+}
|
|
+
|
|
+bool FontInfo::isEmbedded() const
|
|
+{
|
|
+ return m_data->isEmbedded;
|
|
+}
|
|
+
|
|
+bool FontInfo::isSubset() const
|
|
+{
|
|
+ return m_data->isSubset;
|
|
+}
|
|
+
|
|
+FontInfo::Type FontInfo::type() const
|
|
+{
|
|
+ return m_data->type;
|
|
+}
|
|
+
|
|
+QString FontInfo::typeName() const
|
|
+{
|
|
+ switch (type()) {
|
|
+ case unknown:
|
|
+ return QObject::tr("unknown");
|
|
+ case Type1:
|
|
+ return QObject::tr("Type 1");
|
|
+ case Type1C:
|
|
+ return QObject::tr("Type 1C");
|
|
+ case Type3:
|
|
+ return QObject::tr("Type 3");
|
|
+ case TrueType:
|
|
+ return QObject::tr("TrueType");
|
|
+ case CIDType0:
|
|
+ return QObject::tr("CID Type 0");
|
|
+ case CIDType0C:
|
|
+ return QObject::tr("CID Type 0C");
|
|
+ case CIDTrueType:
|
|
+ return QObject::tr("CID TrueType");
|
|
+ case Type1COT:
|
|
+ return QObject::tr("Type 1C (OpenType)");
|
|
+ case TrueTypeOT:
|
|
+ return QObject::tr("TrueType (OpenType)");
|
|
+ case CIDType0COT:
|
|
+ return QObject::tr("CID Type 0C (OpenType)");
|
|
+ case CIDTrueTypeOT:
|
|
+ return QObject::tr("CID TrueType (OpenType)");
|
|
+ }
|
|
+ return QObject::tr("Bug: unexpected font type. Notify poppler mailing list!");
|
|
+}
|
|
+
|
|
+FontInfo& FontInfo::operator=( const FontInfo &fi )
|
|
+{
|
|
+ if (this == &fi)
|
|
+ return *this;
|
|
+
|
|
+ *m_data = *fi.m_data;
|
|
+ return *this;
|
|
+}
|
|
+
|
|
+
|
|
+FontIterator::FontIterator( int startPage, DocumentData *dd )
|
|
+ : d( new FontIteratorData( startPage, dd ) )
|
|
+{
|
|
+}
|
|
+
|
|
+FontIterator::~FontIterator()
|
|
+{
|
|
+ delete d;
|
|
+}
|
|
+
|
|
+QList<FontInfo> FontIterator::next()
|
|
+{
|
|
+ ++d->currentPage;
|
|
+
|
|
+ QList<FontInfo> fonts;
|
|
+ const std::vector<::FontInfo*> items = d->fontInfoScanner.scan( 1 );
|
|
+ fonts.reserve( items.size() );
|
|
+ for ( ::FontInfo* entry : items ) {
|
|
+ fonts.append( FontInfo( FontInfoData( entry ) ) );
|
|
+ delete entry;
|
|
+ }
|
|
+
|
|
+
|
|
+ return fonts;
|
|
+}
|
|
+
|
|
+bool FontIterator::hasNext() const
|
|
+{
|
|
+ return ( d->currentPage + 1 ) < d->totalPages;
|
|
+}
|
|
+
|
|
+int FontIterator::currentPage() const
|
|
+{
|
|
+ return d->currentPage;
|
|
+}
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-form.cc b/qt4/src/poppler-form.cc
|
|
new file mode 100644
|
|
index 00000000..57cde574
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-form.cc
|
|
@@ -0,0 +1,416 @@
|
|
+/* poppler-form.h: qt4 interface to poppler
|
|
+ * Copyright (C) 2007-2008, 2011, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2008, 2011, 2012, 2015, 2017, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2011 Carlos Garcia Campos <carlosgc@gnome.org>
|
|
+ * Copyright (C) 2012, Adam Reichold <adamreichold@myopera.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-qt4.h"
|
|
+
|
|
+#include <QtCore/QSizeF>
|
|
+
|
|
+#include <Form.h>
|
|
+#include <Object.h>
|
|
+#include <Link.h>
|
|
+
|
|
+#include "poppler-form.h"
|
|
+#include "poppler-page-private.h"
|
|
+#include "poppler-private.h"
|
|
+#include "poppler-annotation-helper.h"
|
|
+
|
|
+#include <math.h>
|
|
+
|
|
+namespace {
|
|
+
|
|
+Qt::Alignment formTextAlignment(::FormWidget *fm)
|
|
+{
|
|
+ Qt::Alignment qtalign = Qt::AlignLeft;
|
|
+ switch (fm->getField()->getTextQuadding())
|
|
+ {
|
|
+ case quaddingCentered:
|
|
+ qtalign = Qt::AlignHCenter;
|
|
+ break;
|
|
+ case quaddingRightJustified:
|
|
+ qtalign = Qt::AlignRight;
|
|
+ break;
|
|
+ case quaddingLeftJustified:
|
|
+ qtalign = Qt::AlignLeft;
|
|
+ }
|
|
+ return qtalign;
|
|
+}
|
|
+
|
|
+}
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+FormField::FormField(FormFieldData &dd)
|
|
+ : m_formData(&dd)
|
|
+{
|
|
+ const int rotation = m_formData->page->getRotate();
|
|
+ // reading the coords
|
|
+ double left, top, right, bottom;
|
|
+ m_formData->fm->getRect(&left, &bottom, &right, &top);
|
|
+ // build a normalized transform matrix for this page at 100% scale
|
|
+ GfxState gfxState( 72.0, 72.0, m_formData->page->getCropBox(), rotation, true );
|
|
+ const double * gfxCTM = gfxState.getCTM();
|
|
+ double MTX[6];
|
|
+ double pageWidth = m_formData->page->getCropWidth();
|
|
+ double pageHeight = m_formData->page->getCropHeight();
|
|
+ // landscape and seascape page rotation: be sure to use the correct (== rotated) page size
|
|
+ if (((rotation / 90) % 2) == 1)
|
|
+ qSwap(pageWidth, pageHeight);
|
|
+ for ( int i = 0; i < 6; i+=2 )
|
|
+ {
|
|
+ MTX[i] = gfxCTM[i] / pageWidth;
|
|
+ MTX[i+1] = gfxCTM[i+1] / pageHeight;
|
|
+ }
|
|
+ QPointF topLeft;
|
|
+ XPDFReader::transform( MTX, qMin( left, right ), qMax( top, bottom ), topLeft );
|
|
+ QPointF bottomRight;
|
|
+ XPDFReader::transform( MTX, qMax( left, right ), qMin( top, bottom ), bottomRight );
|
|
+ m_formData->box = QRectF(topLeft, QSizeF(bottomRight.x() - topLeft.x(), bottomRight.y() - topLeft.y()));
|
|
+}
|
|
+
|
|
+FormField::~FormField()
|
|
+{
|
|
+ delete m_formData;
|
|
+ m_formData = 0;
|
|
+}
|
|
+
|
|
+QRectF FormField::rect() const
|
|
+{
|
|
+ return m_formData->box;
|
|
+}
|
|
+
|
|
+int FormField::id() const
|
|
+{
|
|
+ return m_formData->fm->getID();
|
|
+}
|
|
+
|
|
+QString FormField::name() const
|
|
+{
|
|
+ QString name;
|
|
+ if (const GooString *goo = m_formData->fm->getPartialName())
|
|
+ {
|
|
+ name = QString::fromLatin1(goo->c_str());
|
|
+ }
|
|
+ return name;
|
|
+}
|
|
+
|
|
+QString FormField::fullyQualifiedName() const
|
|
+{
|
|
+ QString name;
|
|
+ if (const GooString *goo = m_formData->fm->getFullyQualifiedName())
|
|
+ {
|
|
+ name = UnicodeParsedString(goo);
|
|
+ }
|
|
+ return name;
|
|
+}
|
|
+
|
|
+QString FormField::uiName() const
|
|
+{
|
|
+ QString name;
|
|
+ if (const GooString *goo = m_formData->fm->getAlternateUiName())
|
|
+ {
|
|
+ name = QString::fromLatin1(goo->c_str());
|
|
+ }
|
|
+ return name;
|
|
+}
|
|
+
|
|
+bool FormField::isReadOnly() const
|
|
+{
|
|
+ return m_formData->fm->isReadOnly();
|
|
+}
|
|
+
|
|
+bool FormField::isVisible() const
|
|
+{
|
|
+ return !(m_formData->fm->getWidgetAnnotation()->getFlags() & Annot::flagHidden);
|
|
+}
|
|
+
|
|
+Link* FormField::activationAction() const
|
|
+{
|
|
+ Link* action = 0;
|
|
+ if (::LinkAction *act = m_formData->fm->getActivationAction())
|
|
+ {
|
|
+ action = PageData::convertLinkActionToLink(act, m_formData->doc, QRectF());
|
|
+ }
|
|
+ return action;
|
|
+}
|
|
+
|
|
+
|
|
+FormFieldButton::FormFieldButton(DocumentData *doc, ::Page *p, ::FormWidgetButton *w)
|
|
+ : FormField(*new FormFieldData(doc, p, w))
|
|
+{
|
|
+}
|
|
+
|
|
+FormFieldButton::~FormFieldButton()
|
|
+{
|
|
+}
|
|
+
|
|
+FormFieldButton::FormType FormFieldButton::type() const
|
|
+{
|
|
+ return FormField::FormButton;
|
|
+}
|
|
+
|
|
+FormFieldButton::ButtonType FormFieldButton::buttonType() const
|
|
+{
|
|
+ FormWidgetButton* fwb = static_cast<FormWidgetButton*>(m_formData->fm);
|
|
+ switch (fwb->getButtonType())
|
|
+ {
|
|
+ case formButtonCheck:
|
|
+ return FormFieldButton::CheckBox;
|
|
+ break;
|
|
+ case formButtonPush:
|
|
+ return FormFieldButton::Push;
|
|
+ break;
|
|
+ case formButtonRadio:
|
|
+ return FormFieldButton::Radio;
|
|
+ break;
|
|
+ }
|
|
+ return FormFieldButton::CheckBox;
|
|
+}
|
|
+
|
|
+QString FormFieldButton::caption() const
|
|
+{
|
|
+ FormWidgetButton* fwb = static_cast<FormWidgetButton*>(m_formData->fm);
|
|
+ QString ret;
|
|
+ if (fwb->getButtonType() == formButtonPush)
|
|
+ {
|
|
+ Dict *dict = m_formData->fm->getObj()->getDict();
|
|
+ Object obj1 = dict->lookup("MK");
|
|
+ if (obj1.isDict())
|
|
+ {
|
|
+ AnnotAppearanceCharacs appearCharacs(obj1.getDict());
|
|
+ if (appearCharacs.getNormalCaption())
|
|
+ {
|
|
+ ret = UnicodeParsedString(appearCharacs.getNormalCaption());
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (const char *goo = fwb->getOnStr())
|
|
+ {
|
|
+ ret = QString::fromUtf8(goo);
|
|
+ }
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+bool FormFieldButton::state() const
|
|
+{
|
|
+ FormWidgetButton* fwb = static_cast<FormWidgetButton*>(m_formData->fm);
|
|
+ return fwb->getState();
|
|
+}
|
|
+
|
|
+void FormFieldButton::setState( bool state )
|
|
+{
|
|
+ FormWidgetButton* fwb = static_cast<FormWidgetButton*>(m_formData->fm);
|
|
+ fwb->setState((bool)state);
|
|
+}
|
|
+
|
|
+QList<int> FormFieldButton::siblings() const
|
|
+{
|
|
+ FormWidgetButton* fwb = static_cast<FormWidgetButton*>(m_formData->fm);
|
|
+ ::FormFieldButton* ffb = static_cast< ::FormFieldButton* >(fwb->getField());
|
|
+ if (fwb->getButtonType() == formButtonPush)
|
|
+ return QList<int>();
|
|
+
|
|
+ QList<int> ret;
|
|
+ for (int i = 0; i < ffb->getNumSiblings(); ++i)
|
|
+ {
|
|
+ ::FormFieldButton* sibling = static_cast< ::FormFieldButton* >(ffb->getSibling(i));
|
|
+ for (int j = 0; j < sibling->getNumWidgets(); ++j)
|
|
+ {
|
|
+ FormWidget *w = sibling->getWidget(j);
|
|
+ if (w) ret.append(w->getID());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+
|
|
+FormFieldText::FormFieldText(DocumentData *doc, ::Page *p, ::FormWidgetText *w)
|
|
+ : FormField(*new FormFieldData(doc, p, w))
|
|
+{
|
|
+}
|
|
+
|
|
+FormFieldText::~FormFieldText()
|
|
+{
|
|
+}
|
|
+
|
|
+FormField::FormType FormFieldText::type() const
|
|
+{
|
|
+ return FormField::FormText;
|
|
+}
|
|
+
|
|
+FormFieldText::TextType FormFieldText::textType() const
|
|
+{
|
|
+ FormWidgetText* fwt = static_cast<FormWidgetText*>(m_formData->fm);
|
|
+ if (fwt->isFileSelect())
|
|
+ return FormFieldText::FileSelect;
|
|
+ else if (fwt->isMultiline())
|
|
+ return FormFieldText::Multiline;
|
|
+ return FormFieldText::Normal;
|
|
+}
|
|
+
|
|
+QString FormFieldText::text() const
|
|
+{
|
|
+ const GooString *goo = static_cast<FormWidgetText*>(m_formData->fm)->getContent();
|
|
+ return UnicodeParsedString(goo);
|
|
+}
|
|
+
|
|
+void FormFieldText::setText( const QString& text )
|
|
+{
|
|
+ FormWidgetText* fwt = static_cast<FormWidgetText*>(m_formData->fm);
|
|
+ GooString * goo = QStringToUnicodeGooString( text );
|
|
+ fwt->setContent( goo );
|
|
+ delete goo;
|
|
+}
|
|
+
|
|
+bool FormFieldText::isPassword() const
|
|
+{
|
|
+ FormWidgetText* fwt = static_cast<FormWidgetText*>(m_formData->fm);
|
|
+ return fwt->isPassword();
|
|
+}
|
|
+
|
|
+bool FormFieldText::isRichText() const
|
|
+{
|
|
+ FormWidgetText* fwt = static_cast<FormWidgetText*>(m_formData->fm);
|
|
+ return fwt->isRichText();
|
|
+}
|
|
+
|
|
+int FormFieldText::maximumLength() const
|
|
+{
|
|
+ FormWidgetText* fwt = static_cast<FormWidgetText*>(m_formData->fm);
|
|
+ const int maxlen = fwt->getMaxLen();
|
|
+ return maxlen > 0 ? maxlen : -1;
|
|
+}
|
|
+
|
|
+Qt::Alignment FormFieldText::textAlignment() const
|
|
+{
|
|
+ return formTextAlignment(m_formData->fm);
|
|
+}
|
|
+
|
|
+bool FormFieldText::canBeSpellChecked() const
|
|
+{
|
|
+ FormWidgetText* fwt = static_cast<FormWidgetText*>(m_formData->fm);
|
|
+ return !fwt->noSpellCheck();
|
|
+}
|
|
+
|
|
+
|
|
+FormFieldChoice::FormFieldChoice(DocumentData *doc, ::Page *p, ::FormWidgetChoice *w)
|
|
+ : FormField(*new FormFieldData(doc, p, w))
|
|
+{
|
|
+}
|
|
+
|
|
+FormFieldChoice::~FormFieldChoice()
|
|
+{
|
|
+}
|
|
+
|
|
+FormFieldChoice::FormType FormFieldChoice::type() const
|
|
+{
|
|
+ return FormField::FormChoice;
|
|
+}
|
|
+
|
|
+FormFieldChoice::ChoiceType FormFieldChoice::choiceType() const
|
|
+{
|
|
+ FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm);
|
|
+ if (fwc->isCombo())
|
|
+ return FormFieldChoice::ComboBox;
|
|
+ return FormFieldChoice::ListBox;
|
|
+}
|
|
+
|
|
+QStringList FormFieldChoice::choices() const
|
|
+{
|
|
+ FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm);
|
|
+ QStringList ret;
|
|
+ int num = fwc->getNumChoices();
|
|
+ ret.reserve(num);
|
|
+ for (int i = 0; i < num; ++i)
|
|
+ {
|
|
+ ret.append(UnicodeParsedString(fwc->getChoice(i)));
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+bool FormFieldChoice::isEditable() const
|
|
+{
|
|
+ FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm);
|
|
+ return fwc->isCombo() ? fwc->hasEdit() : false;
|
|
+}
|
|
+
|
|
+bool FormFieldChoice::multiSelect() const
|
|
+{
|
|
+ FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm);
|
|
+ return !fwc->isCombo() ? fwc->isMultiSelect() : false;
|
|
+}
|
|
+
|
|
+QList<int> FormFieldChoice::currentChoices() const
|
|
+{
|
|
+ FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm);
|
|
+ int num = fwc->getNumChoices();
|
|
+ QList<int> choices;
|
|
+ for ( int i = 0; i < num; ++i )
|
|
+ if ( fwc->isSelected( i ) )
|
|
+ choices.append( i );
|
|
+ return choices;
|
|
+}
|
|
+
|
|
+void FormFieldChoice::setCurrentChoices( const QList<int> &choice )
|
|
+{
|
|
+ FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm);
|
|
+ fwc->deselectAll();
|
|
+ for ( int i = 0; i < choice.count(); ++i )
|
|
+ fwc->select( choice.at( i ) );
|
|
+}
|
|
+
|
|
+QString FormFieldChoice::editChoice() const
|
|
+{
|
|
+ FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm);
|
|
+
|
|
+ if ( fwc->isCombo() && fwc->hasEdit() )
|
|
+ return UnicodeParsedString(fwc->getEditChoice());
|
|
+ else
|
|
+ return QString();
|
|
+}
|
|
+
|
|
+void FormFieldChoice::setEditChoice(const QString& text)
|
|
+{
|
|
+ FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm);
|
|
+
|
|
+ if ( fwc->isCombo() && fwc->hasEdit() )
|
|
+ {
|
|
+ GooString* goo = QStringToUnicodeGooString( text );
|
|
+ fwc->setEditChoice( goo );
|
|
+ delete goo;
|
|
+ }
|
|
+}
|
|
+
|
|
+Qt::Alignment FormFieldChoice::textAlignment() const
|
|
+{
|
|
+ return formTextAlignment(m_formData->fm);
|
|
+}
|
|
+
|
|
+bool FormFieldChoice::canBeSpellChecked() const
|
|
+{
|
|
+ FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm);
|
|
+ return !fwc->noSpellCheck();
|
|
+}
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-form.h b/qt4/src/poppler-form.h
|
|
new file mode 100644
|
|
index 00000000..79ed3932
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-form.h
|
|
@@ -0,0 +1,343 @@
|
|
+/* poppler-form.h: qt4 interface to poppler
|
|
+ * Copyright (C) 2007-2008, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2008, 2011, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2012, Adam Reichold <adamreichold@myopera.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef _POPPLER_QT4_FORM_H_
|
|
+#define _POPPLER_QT4_FORM_H_
|
|
+
|
|
+#include <QtCore/QRectF>
|
|
+#include <QtCore/QStringList>
|
|
+#include "poppler-export.h"
|
|
+
|
|
+class Page;
|
|
+class FormWidget;
|
|
+class FormWidgetButton;
|
|
+class FormWidgetText;
|
|
+class FormWidgetChoice;
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+ class DocumentData;
|
|
+ class Link;
|
|
+
|
|
+ class FormFieldData;
|
|
+ /**
|
|
+ The base class representing a form field.
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT FormField {
|
|
+ public:
|
|
+
|
|
+ /**
|
|
+ The different types of form field.
|
|
+ */
|
|
+ enum FormType {
|
|
+ FormButton, ///< A button field. See \ref Poppler::FormFieldButton::ButtonType "ButtonType"
|
|
+ FormText, ///< A text field. See \ref Poppler::FormFieldText::TextType "TextType"
|
|
+ FormChoice, ///< A single choice field. See \ref Poppler::FormFieldChoice::ChoiceType "ChoiceType"
|
|
+ FormSignature ///< A signature field.
|
|
+ };
|
|
+
|
|
+ virtual ~FormField();
|
|
+
|
|
+ /**
|
|
+ The type of the field.
|
|
+ */
|
|
+ virtual FormType type() const = 0;
|
|
+
|
|
+ /**
|
|
+ \return The size of the field, in normalized coordinates, i.e.
|
|
+ [0..1] with regard to the dimensions (cropbox) of the page
|
|
+ */
|
|
+ QRectF rect() const;
|
|
+
|
|
+ /**
|
|
+ The ID of the field.
|
|
+ */
|
|
+ int id() const;
|
|
+
|
|
+ /**
|
|
+ The internal name of the field.
|
|
+ */
|
|
+ QString name() const;
|
|
+
|
|
+ /**
|
|
+ The internal fully qualified name of the field.
|
|
+ \since 0.18
|
|
+ */
|
|
+ QString fullyQualifiedName() const;
|
|
+
|
|
+ /**
|
|
+ The name of the field to be used in user interface (eg messages to
|
|
+ the user).
|
|
+ */
|
|
+ QString uiName() const;
|
|
+
|
|
+ /**
|
|
+ Whether this form field is read-only.
|
|
+ */
|
|
+ bool isReadOnly() const;
|
|
+
|
|
+ /**
|
|
+ Whether this form field is visible.
|
|
+ */
|
|
+ bool isVisible() const;
|
|
+
|
|
+ /**
|
|
+ The activation action of this form field.
|
|
+
|
|
+ \note It may be null.
|
|
+ */
|
|
+ Link* activationAction() const;
|
|
+
|
|
+ protected:
|
|
+ /// \cond PRIVATE
|
|
+ FormField(FormFieldData &dd);
|
|
+
|
|
+ FormFieldData *m_formData;
|
|
+ /// \endcond
|
|
+
|
|
+ private:
|
|
+ Q_DISABLE_COPY(FormField)
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ A form field that represents a "button".
|
|
+
|
|
+ \since 0.8
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT FormFieldButton : public FormField {
|
|
+ public:
|
|
+
|
|
+ /**
|
|
+ * The types of button field.
|
|
+ */
|
|
+ enum ButtonType
|
|
+ {
|
|
+ Push, ///< A simple push button.
|
|
+ CheckBox, ///< A check box.
|
|
+ Radio ///< A radio button.
|
|
+ };
|
|
+
|
|
+ /// \cond PRIVATE
|
|
+ FormFieldButton(DocumentData *doc, ::Page *p, ::FormWidgetButton *w);
|
|
+ /// \endcond
|
|
+ virtual ~FormFieldButton();
|
|
+
|
|
+ virtual FormType type() const;
|
|
+
|
|
+ /**
|
|
+ The particular type of the button field.
|
|
+ */
|
|
+ ButtonType buttonType() const;
|
|
+
|
|
+ /**
|
|
+ * The caption to be used for the button.
|
|
+ */
|
|
+ QString caption() const;
|
|
+
|
|
+ /**
|
|
+ The state of the button.
|
|
+ */
|
|
+ bool state() const;
|
|
+
|
|
+ /**
|
|
+ Sets the state of the button to the new \p state .
|
|
+ */
|
|
+ void setState( bool state );
|
|
+
|
|
+ /**
|
|
+ The list with the IDs of siblings (ie, buttons belonging to the same
|
|
+ group as the current one.
|
|
+
|
|
+ Valid only for \ref Radio buttons, an empty list otherwise.
|
|
+ */
|
|
+ QList<int> siblings() const;
|
|
+
|
|
+ private:
|
|
+ Q_DISABLE_COPY(FormFieldButton)
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ A form field that represents a text input.
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT FormFieldText : public FormField {
|
|
+ public:
|
|
+
|
|
+ /**
|
|
+ The particular type of this text field.
|
|
+ */
|
|
+ enum TextType {
|
|
+ Normal, ///< A simple singleline text field.
|
|
+ Multiline, ///< A multiline text field.
|
|
+ FileSelect ///< An input field to select the path of a file on disk.
|
|
+ };
|
|
+
|
|
+ /// \cond PRIVATE
|
|
+ FormFieldText(DocumentData *doc, ::Page *p, ::FormWidgetText *w);
|
|
+ /// \endcond
|
|
+ virtual ~FormFieldText();
|
|
+
|
|
+ virtual FormType type() const;
|
|
+
|
|
+ /**
|
|
+ The text type of the text field.
|
|
+ */
|
|
+ TextType textType() const;
|
|
+
|
|
+ /**
|
|
+ The text associated with the text field.
|
|
+ */
|
|
+ QString text() const;
|
|
+
|
|
+ /**
|
|
+ Sets the text associated with the text field to the specified
|
|
+ \p text.
|
|
+ */
|
|
+ void setText( const QString& text );
|
|
+
|
|
+ /**
|
|
+ Whether this text field is a password input, eg its text \b must be
|
|
+ replaced with asterisks.
|
|
+
|
|
+ Always false for \ref FileSelect text fields.
|
|
+ */
|
|
+ bool isPassword() const;
|
|
+
|
|
+ /**
|
|
+ Whether this text field should allow rich text.
|
|
+ */
|
|
+ bool isRichText() const;
|
|
+
|
|
+ /**
|
|
+ The maximum length for the text of this field, or -1 if not set.
|
|
+ */
|
|
+ int maximumLength() const;
|
|
+
|
|
+ /**
|
|
+ The horizontal alignment for the text of this text field.
|
|
+ */
|
|
+ Qt::Alignment textAlignment() const;
|
|
+
|
|
+ /**
|
|
+ Whether the text inserted manually in the field (where possible)
|
|
+ can be spell-checked.
|
|
+ */
|
|
+ bool canBeSpellChecked() const;
|
|
+
|
|
+ private:
|
|
+ Q_DISABLE_COPY(FormFieldText)
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ A form field that represents a choice field.
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT FormFieldChoice : public FormField {
|
|
+ public:
|
|
+
|
|
+ /**
|
|
+ The particular type of this choice field.
|
|
+ */
|
|
+ enum ChoiceType {
|
|
+ ComboBox, ///< A simple singleline text field.
|
|
+ ListBox ///< A multiline text field.
|
|
+ };
|
|
+
|
|
+ /// \cond PRIVATE
|
|
+ FormFieldChoice(DocumentData *doc, ::Page *p, ::FormWidgetChoice *w);
|
|
+ /// \endcond
|
|
+ virtual ~FormFieldChoice();
|
|
+
|
|
+ virtual FormType type() const;
|
|
+
|
|
+ /**
|
|
+ The choice type of the choice field.
|
|
+ */
|
|
+ ChoiceType choiceType() const;
|
|
+
|
|
+ /**
|
|
+ The possible choices of the choice field.
|
|
+ */
|
|
+ QStringList choices() const;
|
|
+
|
|
+ /**
|
|
+ Whether this FormFieldChoice::ComboBox is editable, i.e. the user
|
|
+ can type in a custom value.
|
|
+
|
|
+ Always false for the other types of choices.
|
|
+ */
|
|
+ bool isEditable() const;
|
|
+
|
|
+ /**
|
|
+ Whether more than one choice of this FormFieldChoice::ListBox
|
|
+ can be selected at the same time.
|
|
+
|
|
+ Always false for the other types of choices.
|
|
+ */
|
|
+ bool multiSelect() const;
|
|
+
|
|
+ /**
|
|
+ The currently selected choices.
|
|
+ */
|
|
+ QList<int> currentChoices() const;
|
|
+
|
|
+ /**
|
|
+ Sets the selected choices to \p choice.
|
|
+ */
|
|
+ void setCurrentChoices( const QList<int> &choice );
|
|
+
|
|
+ /**
|
|
+ The text entered into an editable combo box choice field. Otherwise a null string.
|
|
+
|
|
+ \since 0.22
|
|
+ */
|
|
+ QString editChoice() const;
|
|
+
|
|
+ /**
|
|
+ Sets the text entered into an editable combo box choice field. Otherwise does nothing.
|
|
+
|
|
+ \since 0.22
|
|
+ */
|
|
+ void setEditChoice(const QString& text);
|
|
+
|
|
+ /**
|
|
+ The horizontal alignment for the text of this text field.
|
|
+ */
|
|
+ Qt::Alignment textAlignment() const;
|
|
+
|
|
+ /**
|
|
+ Whether the text inserted manually in the field (where possible)
|
|
+ can be spell-checked.
|
|
+
|
|
+ Returns false if the field is not an editable text field.
|
|
+ */
|
|
+ bool canBeSpellChecked() const;
|
|
+
|
|
+ private:
|
|
+ Q_DISABLE_COPY(FormFieldChoice)
|
|
+ };
|
|
+
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-link-extractor-private.h b/qt4/src/poppler-link-extractor-private.h
|
|
new file mode 100644
|
|
index 00000000..32ddd038
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-link-extractor-private.h
|
|
@@ -0,0 +1,57 @@
|
|
+/* poppler-link-extractor_p.h: qt interface to poppler
|
|
+ * Copyright (C) 2007, 2008, 2011, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef _POPPLER_LINK_EXTRACTOR_H_
|
|
+#define _POPPLER_LINK_EXTRACTOR_H_
|
|
+
|
|
+#include <Object.h>
|
|
+#include <OutputDev.h>
|
|
+
|
|
+#include <QtCore/QList>
|
|
+
|
|
+namespace Poppler
|
|
+{
|
|
+
|
|
+class Link;
|
|
+class PageData;
|
|
+
|
|
+class LinkExtractorOutputDev : public OutputDev
|
|
+{
|
|
+ public:
|
|
+ LinkExtractorOutputDev(PageData *data);
|
|
+ virtual ~LinkExtractorOutputDev();
|
|
+
|
|
+ // inherited from OutputDev
|
|
+ virtual bool upsideDown() { return false; }
|
|
+ virtual bool useDrawChar() { return false; }
|
|
+ virtual bool interpretType3Chars() { return false; }
|
|
+ virtual void processLink(::AnnotLink *link);
|
|
+
|
|
+ // our stuff
|
|
+ QList< Link* > links();
|
|
+
|
|
+ private:
|
|
+ PageData *m_data;
|
|
+ double m_pageCropWidth;
|
|
+ double m_pageCropHeight;
|
|
+ QList< Link* > m_links;
|
|
+};
|
|
+
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-link-extractor.cc b/qt4/src/poppler-link-extractor.cc
|
|
new file mode 100644
|
|
index 00000000..0b1563b6
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-link-extractor.cc
|
|
@@ -0,0 +1,84 @@
|
|
+/* poppler-link-extractor_p.h: qt interface to poppler
|
|
+ * Copyright (C) 2007, 2008, 2011, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2008, Albert Astals Cid <aacid@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-link-extractor-private.h"
|
|
+
|
|
+#include <GfxState.h>
|
|
+#include <Link.h>
|
|
+#include <Object.h>
|
|
+#include <Page.h>
|
|
+#include <Annot.h>
|
|
+
|
|
+#include "poppler-qt4.h"
|
|
+#include "poppler-page-private.h"
|
|
+
|
|
+namespace Poppler
|
|
+{
|
|
+
|
|
+LinkExtractorOutputDev::LinkExtractorOutputDev(PageData *data)
|
|
+ : m_data(data)
|
|
+{
|
|
+ Q_ASSERT(m_data);
|
|
+ ::Page *popplerPage = m_data->page;
|
|
+ m_pageCropWidth = popplerPage->getCropWidth();
|
|
+ m_pageCropHeight = popplerPage->getCropHeight();
|
|
+ if (popplerPage->getRotate() == 90 || popplerPage->getRotate() == 270)
|
|
+ qSwap(m_pageCropWidth, m_pageCropHeight);
|
|
+ GfxState gfxState(72.0, 72.0, popplerPage->getCropBox(), popplerPage->getRotate(), true);
|
|
+ setDefaultCTM(gfxState.getCTM());
|
|
+}
|
|
+
|
|
+LinkExtractorOutputDev::~LinkExtractorOutputDev()
|
|
+{
|
|
+ qDeleteAll(m_links);
|
|
+}
|
|
+
|
|
+void LinkExtractorOutputDev::processLink(::AnnotLink *link)
|
|
+{
|
|
+ if (!link->isOk())
|
|
+ return;
|
|
+
|
|
+ double left, top, right, bottom;
|
|
+ int leftAux, topAux, rightAux, bottomAux;
|
|
+ link->getRect(&left, &top, &right, &bottom);
|
|
+ QRectF linkArea;
|
|
+
|
|
+ cvtUserToDev(left, top, &leftAux, &topAux);
|
|
+ cvtUserToDev(right, bottom, &rightAux, &bottomAux);
|
|
+ linkArea.setLeft((double)leftAux / m_pageCropWidth);
|
|
+ linkArea.setTop((double)topAux / m_pageCropHeight);
|
|
+ linkArea.setRight((double)rightAux / m_pageCropWidth);
|
|
+ linkArea.setBottom((double)bottomAux / m_pageCropHeight);
|
|
+
|
|
+ Link *popplerLink = m_data->convertLinkActionToLink(link->getAction(), linkArea);
|
|
+ if (popplerLink)
|
|
+ {
|
|
+ m_links.append(popplerLink);
|
|
+ }
|
|
+ OutputDev::processLink(link);
|
|
+}
|
|
+
|
|
+QList< Link* > LinkExtractorOutputDev::links()
|
|
+{
|
|
+ QList< Link* > ret = m_links;
|
|
+ m_links.clear();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-link-private.h b/qt4/src/poppler-link-private.h
|
|
new file mode 100644
|
|
index 00000000..7b03c1c3
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-link-private.h
|
|
@@ -0,0 +1,57 @@
|
|
+/* poppler-link-private.h: qt interface to poppler
|
|
+ * Copyright (C) 2016, Albert Astals Cid <aacid@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef _POPPLER_LINK_PRIVATE_H_
|
|
+#define _POPPLER_LINK_PRIVATE_H_
|
|
+
|
|
+class LinkOCGState;
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+class LinkPrivate
|
|
+{
|
|
+public:
|
|
+ LinkPrivate( const QRectF &area )
|
|
+ : linkArea( area )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ virtual ~LinkPrivate()
|
|
+ {
|
|
+ }
|
|
+
|
|
+ QRectF linkArea;
|
|
+};
|
|
+
|
|
+
|
|
+
|
|
+class LinkOCGStatePrivate : public LinkPrivate
|
|
+{
|
|
+public:
|
|
+ LinkOCGStatePrivate( const QRectF &area, ::LinkOCGState *plocg )
|
|
+ : LinkPrivate( area )
|
|
+ , popplerLinkOCGState( plocg )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ ::LinkOCGState *popplerLinkOCGState;
|
|
+};
|
|
+
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-link.cc b/qt4/src/poppler-link.cc
|
|
new file mode 100644
|
|
index 00000000..1e37f5bd
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-link.cc
|
|
@@ -0,0 +1,705 @@
|
|
+/* poppler-link.cc: qt interface to poppler
|
|
+ * Copyright (C) 2006-2007, 2016, 2017, Albert Astals Cid
|
|
+ * Copyright (C) 2007-2008, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
|
|
+ * Copyright (C) 2012, Tobias Koenig <tokoe@kdab.com>
|
|
+ * Copyright (C) 2012, Guillermo A. Amaral B. <gamaral@kde.org>
|
|
+ * Adapting code from
|
|
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+#include <poppler-link-private.h>
|
|
+#include <poppler-private.h>
|
|
+#include <poppler-media.h>
|
|
+
|
|
+#include <QtCore/QStringList>
|
|
+
|
|
+#include "poppler-annotation-private.h"
|
|
+
|
|
+#include "Link.h"
|
|
+#include "Rendition.h"
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+class LinkDestinationPrivate : public QSharedData
|
|
+{
|
|
+ public:
|
|
+ LinkDestinationPrivate();
|
|
+
|
|
+ LinkDestination::Kind kind; // destination type
|
|
+ QString name;
|
|
+ int pageNum; // page number
|
|
+ double left, bottom; // position
|
|
+ double right, top;
|
|
+ double zoom; // zoom factor
|
|
+ bool changeLeft : 1, changeTop : 1; // for destXYZ links, which position
|
|
+ bool changeZoom : 1; // components to change
|
|
+};
|
|
+
|
|
+ LinkDestinationPrivate::LinkDestinationPrivate()
|
|
+ {
|
|
+ // sane defaults
|
|
+ kind = LinkDestination::destXYZ;
|
|
+ pageNum = 0;
|
|
+ left = 0;
|
|
+ bottom = 0;
|
|
+ right = 0;
|
|
+ top = 0;
|
|
+ zoom = 1;
|
|
+ changeLeft = true;
|
|
+ changeTop = true;
|
|
+ changeZoom = false;
|
|
+ }
|
|
+
|
|
+class LinkGotoPrivate : public LinkPrivate
|
|
+{
|
|
+ public:
|
|
+ LinkGotoPrivate( const QRectF &area, const LinkDestination &dest );
|
|
+
|
|
+ QString extFileName;
|
|
+ LinkDestination destination;
|
|
+};
|
|
+
|
|
+ LinkGotoPrivate::LinkGotoPrivate( const QRectF &area, const LinkDestination &dest )
|
|
+ : LinkPrivate( area ), destination( dest )
|
|
+ {
|
|
+ }
|
|
+
|
|
+class LinkExecutePrivate : public LinkPrivate
|
|
+{
|
|
+ public:
|
|
+ LinkExecutePrivate( const QRectF &area );
|
|
+
|
|
+ QString fileName;
|
|
+ QString parameters;
|
|
+};
|
|
+
|
|
+ LinkExecutePrivate::LinkExecutePrivate( const QRectF &area )
|
|
+ : LinkPrivate( area )
|
|
+ {
|
|
+ }
|
|
+
|
|
+class LinkBrowsePrivate : public LinkPrivate
|
|
+{
|
|
+ public:
|
|
+ LinkBrowsePrivate( const QRectF &area );
|
|
+
|
|
+ QString url;
|
|
+};
|
|
+
|
|
+ LinkBrowsePrivate::LinkBrowsePrivate( const QRectF &area )
|
|
+ : LinkPrivate( area )
|
|
+ {
|
|
+ }
|
|
+
|
|
+class LinkActionPrivate : public LinkPrivate
|
|
+{
|
|
+ public:
|
|
+ LinkActionPrivate( const QRectF &area );
|
|
+
|
|
+ LinkAction::ActionType type;
|
|
+};
|
|
+
|
|
+ LinkActionPrivate::LinkActionPrivate( const QRectF &area )
|
|
+ : LinkPrivate( area )
|
|
+ {
|
|
+ }
|
|
+
|
|
+class LinkSoundPrivate : public LinkPrivate
|
|
+{
|
|
+ public:
|
|
+ LinkSoundPrivate( const QRectF &area );
|
|
+ ~LinkSoundPrivate();
|
|
+
|
|
+ double volume;
|
|
+ bool sync : 1;
|
|
+ bool repeat : 1;
|
|
+ bool mix : 1;
|
|
+ SoundObject *sound;
|
|
+};
|
|
+
|
|
+ LinkSoundPrivate::LinkSoundPrivate( const QRectF &area )
|
|
+ : LinkPrivate( area ), sound( 0 )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ LinkSoundPrivate::~LinkSoundPrivate()
|
|
+ {
|
|
+ delete sound;
|
|
+ }
|
|
+
|
|
+class LinkRenditionPrivate : public LinkPrivate
|
|
+{
|
|
+ public:
|
|
+ LinkRenditionPrivate( const QRectF &area, ::MediaRendition *rendition, ::LinkRendition::RenditionOperation operation, const QString &script, const Ref &annotationReference );
|
|
+ ~LinkRenditionPrivate();
|
|
+
|
|
+ MediaRendition *rendition;
|
|
+ LinkRendition::RenditionAction action;
|
|
+ QString script;
|
|
+ Ref annotationReference;
|
|
+};
|
|
+
|
|
+ LinkRenditionPrivate::LinkRenditionPrivate( const QRectF &area, ::MediaRendition *r, ::LinkRendition::RenditionOperation operation, const QString &javaScript, const Ref &ref )
|
|
+ : LinkPrivate( area )
|
|
+ , rendition( r ? new MediaRendition( r ) : 0 )
|
|
+ , action( LinkRendition::PlayRendition )
|
|
+ , script( javaScript )
|
|
+ , annotationReference( ref )
|
|
+ {
|
|
+ switch ( operation )
|
|
+ {
|
|
+ case ::LinkRendition::NoRendition:
|
|
+ action = LinkRendition::NoRendition;
|
|
+ break;
|
|
+ case ::LinkRendition::PlayRendition:
|
|
+ action = LinkRendition::PlayRendition;
|
|
+ break;
|
|
+ case ::LinkRendition::StopRendition:
|
|
+ action = LinkRendition::StopRendition;
|
|
+ break;
|
|
+ case ::LinkRendition::PauseRendition:
|
|
+ action = LinkRendition::PauseRendition;
|
|
+ break;
|
|
+ case ::LinkRendition::ResumeRendition:
|
|
+ action = LinkRendition::ResumeRendition;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ LinkRenditionPrivate::~LinkRenditionPrivate()
|
|
+ {
|
|
+ delete rendition;
|
|
+ }
|
|
+
|
|
+class LinkJavaScriptPrivate : public LinkPrivate
|
|
+{
|
|
+ public:
|
|
+ LinkJavaScriptPrivate( const QRectF &area );
|
|
+
|
|
+ QString js;
|
|
+};
|
|
+
|
|
+ LinkJavaScriptPrivate::LinkJavaScriptPrivate( const QRectF &area )
|
|
+ : LinkPrivate( area )
|
|
+ {
|
|
+ }
|
|
+
|
|
+class LinkMoviePrivate : public LinkPrivate
|
|
+{
|
|
+ public:
|
|
+ LinkMoviePrivate( const QRectF &area, LinkMovie::Operation operation, const QString &title, const Ref &reference );
|
|
+
|
|
+ LinkMovie::Operation operation;
|
|
+ QString annotationTitle;
|
|
+ Ref annotationReference;
|
|
+};
|
|
+
|
|
+ LinkMoviePrivate::LinkMoviePrivate( const QRectF &area, LinkMovie::Operation _operation, const QString &title, const Ref &reference )
|
|
+ : LinkPrivate( area ), operation( _operation ), annotationTitle( title ), annotationReference( reference )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ static void cvtUserToDev(::Page *page, double xu, double yu, int *xd, int *yd) {
|
|
+ double ctm[6];
|
|
+
|
|
+ page->getDefaultCTM(ctm, 72.0, 72.0, 0, false, true);
|
|
+ *xd = (int)(ctm[0] * xu + ctm[2] * yu + ctm[4] + 0.5);
|
|
+ *yd = (int)(ctm[1] * xu + ctm[3] * yu + ctm[5] + 0.5);
|
|
+ }
|
|
+
|
|
+ LinkDestination::LinkDestination(const LinkDestinationData &data)
|
|
+ : d( new LinkDestinationPrivate )
|
|
+ {
|
|
+ bool deleteDest = false;
|
|
+ const LinkDest *ld = data.ld;
|
|
+
|
|
+ if ( data.namedDest && !ld && !data.externalDest )
|
|
+ {
|
|
+ deleteDest = true;
|
|
+ ld = data.doc->doc->findDest( data.namedDest );
|
|
+ }
|
|
+ // in case this destination was named one, and it was not resolved
|
|
+ if ( data.namedDest && !ld )
|
|
+ {
|
|
+ d->name = QString::fromLatin1( data.namedDest->c_str() );
|
|
+ }
|
|
+
|
|
+ if (!ld) return;
|
|
+
|
|
+ if (ld->getKind() == ::destXYZ) d->kind = destXYZ;
|
|
+ else if (ld->getKind() == ::destFit) d->kind = destFit;
|
|
+ else if (ld->getKind() == ::destFitH) d->kind = destFitH;
|
|
+ else if (ld->getKind() == ::destFitV) d->kind = destFitV;
|
|
+ else if (ld->getKind() == ::destFitR) d->kind = destFitR;
|
|
+ else if (ld->getKind() == ::destFitB) d->kind = destFitB;
|
|
+ else if (ld->getKind() == ::destFitBH) d->kind = destFitBH;
|
|
+ else if (ld->getKind() == ::destFitBV) d->kind = destFitBV;
|
|
+
|
|
+ if ( !ld->isPageRef() ) d->pageNum = ld->getPageNum();
|
|
+ else
|
|
+ {
|
|
+ Ref ref = ld->getPageRef();
|
|
+ d->pageNum = data.doc->doc->findPage( ref );
|
|
+ }
|
|
+ double left = ld->getLeft();
|
|
+ double bottom = ld->getBottom();
|
|
+ double right = ld->getRight();
|
|
+ double top = ld->getTop();
|
|
+ d->zoom = ld->getZoom();
|
|
+ d->changeLeft = ld->getChangeLeft();
|
|
+ d->changeTop = ld->getChangeTop();
|
|
+ d->changeZoom = ld->getChangeZoom();
|
|
+
|
|
+ int leftAux = 0, topAux = 0, rightAux = 0, bottomAux = 0;
|
|
+
|
|
+ if (!data.externalDest) {
|
|
+ ::Page *page;
|
|
+ if (d->pageNum > 0 &&
|
|
+ d->pageNum <= data.doc->doc->getNumPages() &&
|
|
+ (page = data.doc->doc->getPage( d->pageNum )))
|
|
+ {
|
|
+ cvtUserToDev( page, left, top, &leftAux, &topAux );
|
|
+ cvtUserToDev( page, right, bottom, &rightAux, &bottomAux );
|
|
+
|
|
+ d->left = leftAux / (double)page->getCropWidth();
|
|
+ d->top = topAux / (double)page->getCropHeight();
|
|
+ d->right = rightAux/ (double)page->getCropWidth();
|
|
+ d->bottom = bottomAux / (double)page->getCropHeight();
|
|
+ }
|
|
+ else d->pageNum = 0;
|
|
+ }
|
|
+
|
|
+ if (deleteDest) delete ld;
|
|
+ }
|
|
+
|
|
+ LinkDestination::LinkDestination(const QString &description)
|
|
+ : d( new LinkDestinationPrivate )
|
|
+ {
|
|
+ QStringList tokens = description.split( ';' );
|
|
+ d->kind = static_cast<Kind>(tokens.at(0).toInt());
|
|
+ d->pageNum = tokens.at(1).toInt();
|
|
+ d->left = tokens.at(2).toDouble();
|
|
+ d->bottom = tokens.at(3).toDouble();
|
|
+ d->right = tokens.at(4).toDouble();
|
|
+ d->top = tokens.at(5).toDouble();
|
|
+ d->zoom = tokens.at(6).toDouble();
|
|
+ d->changeLeft = static_cast<bool>(tokens.at(7).toInt());
|
|
+ d->changeTop = static_cast<bool>(tokens.at(8).toInt());
|
|
+ d->changeZoom = static_cast<bool>(tokens.at(9).toInt());
|
|
+ }
|
|
+
|
|
+ LinkDestination::LinkDestination(const LinkDestination &other)
|
|
+ : d( other.d )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ LinkDestination::~LinkDestination()
|
|
+ {
|
|
+ }
|
|
+
|
|
+ LinkDestination::Kind LinkDestination::kind() const
|
|
+ {
|
|
+ return d->kind;
|
|
+ }
|
|
+
|
|
+ int LinkDestination::pageNumber() const
|
|
+ {
|
|
+ return d->pageNum;
|
|
+ }
|
|
+
|
|
+ double LinkDestination::left() const
|
|
+ {
|
|
+ return d->left;
|
|
+ }
|
|
+
|
|
+ double LinkDestination::bottom() const
|
|
+ {
|
|
+ return d->bottom;
|
|
+ }
|
|
+
|
|
+ double LinkDestination::right() const
|
|
+ {
|
|
+ return d->right;
|
|
+ }
|
|
+
|
|
+ double LinkDestination::top() const
|
|
+ {
|
|
+ return d->top;
|
|
+ }
|
|
+
|
|
+ double LinkDestination::zoom() const
|
|
+ {
|
|
+ return d->zoom;
|
|
+ }
|
|
+
|
|
+ bool LinkDestination::isChangeLeft() const
|
|
+ {
|
|
+ return d->changeLeft;
|
|
+ }
|
|
+
|
|
+ bool LinkDestination::isChangeTop() const
|
|
+ {
|
|
+ return d->changeTop;
|
|
+ }
|
|
+
|
|
+ bool LinkDestination::isChangeZoom() const
|
|
+ {
|
|
+ return d->changeZoom;
|
|
+ }
|
|
+
|
|
+ QString LinkDestination::toString() const
|
|
+ {
|
|
+ QString s = QString::number( (qint8)d->kind );
|
|
+ s += ";" + QString::number( d->pageNum );
|
|
+ s += ";" + QString::number( d->left );
|
|
+ s += ";" + QString::number( d->bottom );
|
|
+ s += ";" + QString::number( d->right );
|
|
+ s += ";" + QString::number( d->top );
|
|
+ s += ";" + QString::number( d->zoom );
|
|
+ s += ";" + QString::number( (qint8)d->changeLeft );
|
|
+ s += ";" + QString::number( (qint8)d->changeTop );
|
|
+ s += ";" + QString::number( (qint8)d->changeZoom );
|
|
+ return s;
|
|
+ }
|
|
+
|
|
+ QString LinkDestination::destinationName() const
|
|
+ {
|
|
+ return d->name;
|
|
+ }
|
|
+
|
|
+ LinkDestination& LinkDestination::operator=(const LinkDestination &other)
|
|
+ {
|
|
+ if ( this == &other )
|
|
+ return *this;
|
|
+
|
|
+ d = other.d;
|
|
+ return *this;
|
|
+ }
|
|
+
|
|
+
|
|
+ // Link
|
|
+ Link::~Link()
|
|
+ {
|
|
+ delete d_ptr;
|
|
+ }
|
|
+
|
|
+ Link::Link(const QRectF &linkArea)
|
|
+ : d_ptr( new LinkPrivate( linkArea ) )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ Link::Link( LinkPrivate &dd )
|
|
+ : d_ptr( &dd )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ Link::LinkType Link::linkType() const
|
|
+ {
|
|
+ return None;
|
|
+ }
|
|
+
|
|
+ QRectF Link::linkArea() const
|
|
+ {
|
|
+ Q_D( const Link );
|
|
+ return d->linkArea;
|
|
+ }
|
|
+
|
|
+ // LinkGoto
|
|
+ LinkGoto::LinkGoto( const QRectF &linkArea, QString extFileName, const LinkDestination & destination )
|
|
+ : Link( *new LinkGotoPrivate( linkArea, destination ) )
|
|
+ {
|
|
+ Q_D( LinkGoto );
|
|
+ d->extFileName = extFileName;
|
|
+ }
|
|
+
|
|
+ LinkGoto::~LinkGoto()
|
|
+ {
|
|
+ }
|
|
+
|
|
+ bool LinkGoto::isExternal() const
|
|
+ {
|
|
+ Q_D( const LinkGoto );
|
|
+ return !d->extFileName.isEmpty();
|
|
+ }
|
|
+
|
|
+ QString LinkGoto::fileName() const
|
|
+ {
|
|
+ Q_D( const LinkGoto );
|
|
+ return d->extFileName;
|
|
+ }
|
|
+
|
|
+ LinkDestination LinkGoto::destination() const
|
|
+ {
|
|
+ Q_D( const LinkGoto );
|
|
+ return d->destination;
|
|
+ }
|
|
+
|
|
+ Link::LinkType LinkGoto::linkType() const
|
|
+ {
|
|
+ return Goto;
|
|
+ }
|
|
+
|
|
+ // LinkExecute
|
|
+ LinkExecute::LinkExecute( const QRectF &linkArea, const QString & file, const QString & params )
|
|
+ : Link( *new LinkExecutePrivate( linkArea ) )
|
|
+ {
|
|
+ Q_D( LinkExecute );
|
|
+ d->fileName = file;
|
|
+ d->parameters = params;
|
|
+ }
|
|
+
|
|
+ LinkExecute::~LinkExecute()
|
|
+ {
|
|
+ }
|
|
+
|
|
+ QString LinkExecute::fileName() const
|
|
+ {
|
|
+ Q_D( const LinkExecute );
|
|
+ return d->fileName;
|
|
+ }
|
|
+ QString LinkExecute::parameters() const
|
|
+ {
|
|
+ Q_D( const LinkExecute );
|
|
+ return d->parameters;
|
|
+ }
|
|
+
|
|
+ Link::LinkType LinkExecute::linkType() const
|
|
+ {
|
|
+ return Execute;
|
|
+ }
|
|
+
|
|
+ // LinkBrowse
|
|
+ LinkBrowse::LinkBrowse( const QRectF &linkArea, const QString &url )
|
|
+ : Link( *new LinkBrowsePrivate( linkArea ) )
|
|
+ {
|
|
+ Q_D( LinkBrowse );
|
|
+ d->url = url;
|
|
+ }
|
|
+
|
|
+ LinkBrowse::~LinkBrowse()
|
|
+ {
|
|
+ }
|
|
+
|
|
+ QString LinkBrowse::url() const
|
|
+ {
|
|
+ Q_D( const LinkBrowse );
|
|
+ return d->url;
|
|
+ }
|
|
+
|
|
+ Link::LinkType LinkBrowse::linkType() const
|
|
+ {
|
|
+ return Browse;
|
|
+ }
|
|
+
|
|
+ // LinkAction
|
|
+ LinkAction::LinkAction( const QRectF &linkArea, ActionType actionType )
|
|
+ : Link( *new LinkActionPrivate( linkArea ) )
|
|
+ {
|
|
+ Q_D( LinkAction );
|
|
+ d->type = actionType;
|
|
+ }
|
|
+
|
|
+ LinkAction::~LinkAction()
|
|
+ {
|
|
+ }
|
|
+
|
|
+ LinkAction::ActionType LinkAction::actionType() const
|
|
+ {
|
|
+ Q_D( const LinkAction );
|
|
+ return d->type;
|
|
+ }
|
|
+
|
|
+ Link::LinkType LinkAction::linkType() const
|
|
+ {
|
|
+ return Action;
|
|
+ }
|
|
+
|
|
+ // LinkSound
|
|
+ LinkSound::LinkSound( const QRectF &linkArea, double volume, bool sync, bool repeat, bool mix, SoundObject *sound )
|
|
+ : Link( *new LinkSoundPrivate( linkArea ) )
|
|
+ {
|
|
+ Q_D( LinkSound );
|
|
+ d->volume = volume;
|
|
+ d->sync = sync;
|
|
+ d->repeat = repeat;
|
|
+ d->mix = mix;
|
|
+ d->sound = sound;
|
|
+ }
|
|
+
|
|
+ LinkSound::~LinkSound()
|
|
+ {
|
|
+ }
|
|
+
|
|
+ Link::LinkType LinkSound::linkType() const
|
|
+ {
|
|
+ return Sound;
|
|
+ }
|
|
+
|
|
+ double LinkSound::volume() const
|
|
+ {
|
|
+ Q_D( const LinkSound );
|
|
+ return d->volume;
|
|
+ }
|
|
+
|
|
+ bool LinkSound::synchronous() const
|
|
+ {
|
|
+ Q_D( const LinkSound );
|
|
+ return d->sync;
|
|
+ }
|
|
+
|
|
+ bool LinkSound::repeat() const
|
|
+ {
|
|
+ Q_D( const LinkSound );
|
|
+ return d->repeat;
|
|
+ }
|
|
+
|
|
+ bool LinkSound::mix() const
|
|
+ {
|
|
+ Q_D( const LinkSound );
|
|
+ return d->mix;
|
|
+ }
|
|
+
|
|
+ SoundObject *LinkSound::sound() const
|
|
+ {
|
|
+ Q_D( const LinkSound );
|
|
+ return d->sound;
|
|
+ }
|
|
+
|
|
+ // LinkRendition
|
|
+ LinkRendition::LinkRendition( const QRectF &linkArea, ::MediaRendition *rendition )
|
|
+ : Link( *new LinkRenditionPrivate( linkArea, rendition, ::LinkRendition::NoRendition, QString(), Ref() ) )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ LinkRendition::LinkRendition( const QRectF &linkArea, ::MediaRendition *rendition, int operation, const QString &script, const Ref &annotationReference )
|
|
+ : Link( *new LinkRenditionPrivate( linkArea, rendition, static_cast<enum ::LinkRendition::RenditionOperation>(operation), script, annotationReference ) )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ LinkRendition::~LinkRendition()
|
|
+ {
|
|
+ }
|
|
+
|
|
+ Link::LinkType LinkRendition::linkType() const
|
|
+ {
|
|
+ return Rendition;
|
|
+ }
|
|
+
|
|
+ MediaRendition * LinkRendition::rendition() const
|
|
+ {
|
|
+ Q_D( const LinkRendition );
|
|
+ return d->rendition;
|
|
+ }
|
|
+
|
|
+ LinkRendition::RenditionAction LinkRendition::action() const
|
|
+ {
|
|
+ Q_D( const LinkRendition );
|
|
+ return d->action;
|
|
+ }
|
|
+
|
|
+ QString LinkRendition::script() const
|
|
+ {
|
|
+ Q_D( const LinkRendition );
|
|
+ return d->script;
|
|
+ }
|
|
+
|
|
+ bool LinkRendition::isReferencedAnnotation( const ScreenAnnotation *annotation ) const
|
|
+ {
|
|
+ Q_D( const LinkRendition );
|
|
+ if ( d->annotationReference.num != -1 && d->annotationReference == annotation->d_ptr->pdfObjectReference() )
|
|
+ {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ // LinkJavaScript
|
|
+ LinkJavaScript::LinkJavaScript( const QRectF &linkArea, const QString &js )
|
|
+ : Link( *new LinkJavaScriptPrivate( linkArea ) )
|
|
+ {
|
|
+ Q_D( LinkJavaScript );
|
|
+ d->js = js;
|
|
+ }
|
|
+
|
|
+ LinkJavaScript::~LinkJavaScript()
|
|
+ {
|
|
+ }
|
|
+
|
|
+ Link::LinkType LinkJavaScript::linkType() const
|
|
+ {
|
|
+ return JavaScript;
|
|
+ }
|
|
+
|
|
+ QString LinkJavaScript::script() const
|
|
+ {
|
|
+ Q_D( const LinkJavaScript );
|
|
+ return d->js;
|
|
+ }
|
|
+
|
|
+ // LinkMovie
|
|
+ LinkMovie::LinkMovie( const QRectF &linkArea, Operation operation, const QString &annotationTitle, const Ref &annotationReference )
|
|
+ : Link( *new LinkMoviePrivate( linkArea, operation, annotationTitle, annotationReference ) )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ LinkMovie::~LinkMovie()
|
|
+ {
|
|
+ }
|
|
+
|
|
+ Link::LinkType LinkMovie::linkType() const
|
|
+ {
|
|
+ return Movie;
|
|
+ }
|
|
+
|
|
+ LinkMovie::Operation LinkMovie::operation() const
|
|
+ {
|
|
+ Q_D( const LinkMovie );
|
|
+ return d->operation;
|
|
+ }
|
|
+
|
|
+ bool LinkMovie::isReferencedAnnotation( const MovieAnnotation *annotation ) const
|
|
+ {
|
|
+ Q_D( const LinkMovie );
|
|
+ if ( d->annotationReference.num != -1 && d->annotationReference == annotation->d_ptr->pdfObjectReference() )
|
|
+ {
|
|
+ return true;
|
|
+ }
|
|
+ else if ( !d->annotationTitle.isNull() )
|
|
+ {
|
|
+ return ( annotation->movieTitle() == d->annotationTitle );
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ LinkOCGState::LinkOCGState( LinkOCGStatePrivate *ocgp )
|
|
+ : Link ( *ocgp )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ LinkOCGState::~LinkOCGState()
|
|
+ {
|
|
+ }
|
|
+
|
|
+ Link::LinkType LinkOCGState::linkType() const
|
|
+ {
|
|
+ return OCGState;
|
|
+ }
|
|
+}
|
|
diff --git a/qt4/src/poppler-link.h b/qt4/src/poppler-link.h
|
|
new file mode 100644
|
|
index 00000000..42a8c1fc
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-link.h
|
|
@@ -0,0 +1,641 @@
|
|
+/* poppler-link.h: qt interface to poppler
|
|
+ * Copyright (C) 2006, 2013, 2016, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2007-2008, 2010, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2010, 2012, Guillermo Amaral <gamaral@kdab.com>
|
|
+ * Copyright (C) 2012, Tobias Koenig <tokoe@kdab.com>
|
|
+ * Adapting code from
|
|
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef _POPPLER_LINK_H_
|
|
+#define _POPPLER_LINK_H_
|
|
+
|
|
+#include <QtCore/QString>
|
|
+#include <QtCore/QRectF>
|
|
+#include <QtCore/QSharedDataPointer>
|
|
+#include "poppler-export.h"
|
|
+
|
|
+struct Ref;
|
|
+class MediaRendition;
|
|
+class MovieAnnotation;
|
|
+class ScreenAnnotation;
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+class LinkPrivate;
|
|
+class LinkGotoPrivate;
|
|
+class LinkExecutePrivate;
|
|
+class LinkBrowsePrivate;
|
|
+class LinkActionPrivate;
|
|
+class LinkSoundPrivate;
|
|
+class LinkJavaScriptPrivate;
|
|
+class LinkMoviePrivate;
|
|
+class LinkDestinationData;
|
|
+class LinkDestinationPrivate;
|
|
+class LinkRenditionPrivate;
|
|
+class LinkOCGStatePrivate;
|
|
+class MediaRendition;
|
|
+class SoundObject;
|
|
+
|
|
+/**
|
|
+ * \short A destination.
|
|
+ *
|
|
+ * The LinkDestination class represent a "destination" (in terms of visual
|
|
+ * viewport to be displayed) for \link Poppler::LinkGoto GoTo\endlink links,
|
|
+ * and items in the table of contents (TOC) of a document.
|
|
+ *
|
|
+ * Coordinates are in 0..1 range
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT LinkDestination
|
|
+{
|
|
+ public:
|
|
+ /**
|
|
+ * The possible kind of "viewport destination".
|
|
+ */
|
|
+ enum Kind
|
|
+ {
|
|
+ /**
|
|
+ * The new viewport is specified in terms of:
|
|
+ * - possibile new left coordinate (see isChangeLeft() )
|
|
+ * - possibile new top coordinate (see isChangeTop() )
|
|
+ * - possibile new zoom level (see isChangeZoom() )
|
|
+ */
|
|
+ destXYZ = 1,
|
|
+ destFit = 2,
|
|
+ destFitH = 3,
|
|
+ destFitV = 4,
|
|
+ destFitR = 5,
|
|
+ destFitB = 6,
|
|
+ destFitBH = 7,
|
|
+ destFitBV = 8
|
|
+ };
|
|
+
|
|
+ /// \cond PRIVATE
|
|
+ LinkDestination(const LinkDestinationData &data);
|
|
+ LinkDestination(const QString &description);
|
|
+ /// \endcond
|
|
+ /**
|
|
+ * Copy constructor.
|
|
+ */
|
|
+ LinkDestination(const LinkDestination &other);
|
|
+ /**
|
|
+ * Destructor.
|
|
+ */
|
|
+ ~LinkDestination();
|
|
+
|
|
+ // Accessors.
|
|
+ /**
|
|
+ * The kind of destination.
|
|
+ */
|
|
+ Kind kind() const;
|
|
+ /**
|
|
+ * Which page is the target of this destination.
|
|
+ *
|
|
+ * \note this number is 1-based, so for a 5 pages document the
|
|
+ * valid page numbers go from 1 to 5 (both included).
|
|
+ */
|
|
+ int pageNumber() const;
|
|
+ /**
|
|
+ * The new left for the viewport of the target page, in case
|
|
+ * it is specified to be changed (see isChangeLeft() )
|
|
+ */
|
|
+ double left() const;
|
|
+ double bottom() const;
|
|
+ double right() const;
|
|
+ /**
|
|
+ * The new top for the viewport of the target page, in case
|
|
+ * it is specified to be changed (see isChangeTop() )
|
|
+ */
|
|
+ double top() const;
|
|
+ double zoom() const;
|
|
+ /**
|
|
+ * Whether the left of the viewport on the target page should
|
|
+ * be changed.
|
|
+ *
|
|
+ * \see left()
|
|
+ */
|
|
+ bool isChangeLeft() const;
|
|
+ /**
|
|
+ * Whether the top of the viewport on the target page should
|
|
+ * be changed.
|
|
+ *
|
|
+ * \see top()
|
|
+ */
|
|
+ bool isChangeTop() const;
|
|
+ /**
|
|
+ * Whether the zoom level should be changed.
|
|
+ *
|
|
+ * \see zoom()
|
|
+ */
|
|
+ bool isChangeZoom() const;
|
|
+
|
|
+ /**
|
|
+ * Return a string repesentation of this destination.
|
|
+ */
|
|
+ QString toString() const;
|
|
+
|
|
+ /**
|
|
+ * Return the name of this destination.
|
|
+ *
|
|
+ * \since 0.12
|
|
+ */
|
|
+ QString destinationName() const;
|
|
+
|
|
+ /**
|
|
+ * Assignment operator.
|
|
+ */
|
|
+ LinkDestination& operator=(const LinkDestination &other);
|
|
+
|
|
+ private:
|
|
+ QSharedDataPointer< LinkDestinationPrivate > d;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \short Encapsulates data that describes a link.
|
|
+ *
|
|
+ * This is the base class for links. It makes mandatory for inherited
|
|
+ * kind of links to reimplement the linkType() method and return the type of
|
|
+ * the link described by the reimplemented class.
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT Link
|
|
+{
|
|
+ friend class OptContentModel;
|
|
+
|
|
+ public:
|
|
+ /// \cond PRIVATE
|
|
+ Link( const QRectF &linkArea );
|
|
+ /// \endcond
|
|
+
|
|
+ /**
|
|
+ * The possible kinds of link.
|
|
+ *
|
|
+ * Inherited classes must return an unique identifier
|
|
+ */
|
|
+ enum LinkType
|
|
+ {
|
|
+ None, ///< Unknown link
|
|
+ Goto, ///< A "Go To" link
|
|
+ Execute, ///< A command to be executed
|
|
+ Browse, ///< An URL to be browsed (eg "http://poppler.freedesktop.org")
|
|
+ Action, ///< A "standard" action to be executed in the viewer
|
|
+ Sound, ///< A link representing a sound to be played
|
|
+ Movie, ///< An action to be executed on a movie
|
|
+ Rendition, ///< A rendition link \since 0.20
|
|
+ JavaScript, ///< A JavaScript code to be interpreted \since 0.10
|
|
+ OCGState ///< An Optional Content Group state change \since 0.50
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ * The type of this link.
|
|
+ */
|
|
+ virtual LinkType linkType() const;
|
|
+
|
|
+ /**
|
|
+ * Destructor.
|
|
+ */
|
|
+ virtual ~Link();
|
|
+
|
|
+ /**
|
|
+ * The area of a Page where the link should be active.
|
|
+ *
|
|
+ * \note this can be a null rect, in this case the link represents
|
|
+ * a general action. The area is given in 0..1 range
|
|
+ */
|
|
+ QRectF linkArea() const;
|
|
+
|
|
+ protected:
|
|
+ /// \cond PRIVATE
|
|
+ Link( LinkPrivate &dd );
|
|
+ Q_DECLARE_PRIVATE( Link )
|
|
+ LinkPrivate *d_ptr;
|
|
+ /// \endcond
|
|
+
|
|
+ private:
|
|
+ Q_DISABLE_COPY( Link )
|
|
+};
|
|
+
|
|
+
|
|
+/**
|
|
+ * \brief Viewport reaching request.
|
|
+ *
|
|
+ * With a LinkGoto link, the document requests the specified viewport to be
|
|
+ * reached (aka, displayed in a viewer). Furthermore, if a file name is specified,
|
|
+ * then the destination refers to that document (and not to the document the
|
|
+ * current LinkGoto belongs to).
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT LinkGoto : public Link
|
|
+{
|
|
+ public:
|
|
+ /**
|
|
+ * Create a new Goto link.
|
|
+ *
|
|
+ * \param linkArea the active area of the link
|
|
+ * \param extFileName if not empty, the file name to be open
|
|
+ * \param destination the destination to be reached
|
|
+ */
|
|
+ LinkGoto( const QRectF &linkArea, QString extFileName, const LinkDestination & destination );
|
|
+ /**
|
|
+ * Destructor.
|
|
+ */
|
|
+ ~LinkGoto();
|
|
+
|
|
+ /**
|
|
+ * Whether the destination is in an external document
|
|
+ * (i.e. not the current document)
|
|
+ */
|
|
+ bool isExternal() const;
|
|
+ // query for goto parameters
|
|
+ /**
|
|
+ * The file name of the document the destination() refers to,
|
|
+ * or an empty string in case it refers to the current document.
|
|
+ */
|
|
+ QString fileName() const;
|
|
+ /**
|
|
+ * The destination to reach.
|
|
+ */
|
|
+ LinkDestination destination() const;
|
|
+ LinkType linkType() const override;
|
|
+
|
|
+ private:
|
|
+ Q_DECLARE_PRIVATE( LinkGoto )
|
|
+ Q_DISABLE_COPY( LinkGoto )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \brief Generic execution request.
|
|
+ *
|
|
+ * The LinkExecute link represent a "file name" execution request. The result
|
|
+ * depends on the \link fileName() file name\endlink:
|
|
+ * - if it is a document, then it is requested to be open
|
|
+ * - otherwise, it represents an executable to be run with the specified parameters
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT LinkExecute : public Link
|
|
+{
|
|
+ public:
|
|
+ /**
|
|
+ * The file name to be executed
|
|
+ */
|
|
+ QString fileName() const;
|
|
+ /**
|
|
+ * The parameters for the command.
|
|
+ */
|
|
+ QString parameters() const;
|
|
+
|
|
+ /**
|
|
+ * Create a new Execute link.
|
|
+ *
|
|
+ * \param linkArea the active area of the link
|
|
+ * \param file the file name to be open, or the program to be execute
|
|
+ * \param params the parameters for the program to execute
|
|
+ */
|
|
+ LinkExecute( const QRectF &linkArea, const QString & file, const QString & params );
|
|
+ /**
|
|
+ * Destructor.
|
|
+ */
|
|
+ ~LinkExecute();
|
|
+ LinkType linkType() const;
|
|
+
|
|
+ private:
|
|
+ Q_DECLARE_PRIVATE( LinkExecute )
|
|
+ Q_DISABLE_COPY( LinkExecute )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \brief An URL to browse.
|
|
+ *
|
|
+ * The LinkBrowse link holds a URL (eg 'http://poppler.freedesktop.org',
|
|
+ * 'mailto:john@some.org', etc) to be open.
|
|
+ *
|
|
+ * The format of the URL is specified by RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt)
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT LinkBrowse : public Link
|
|
+{
|
|
+ public:
|
|
+ /**
|
|
+ * The URL to open
|
|
+ */
|
|
+ QString url() const;
|
|
+
|
|
+ /**
|
|
+ * Create a new browse link.
|
|
+ *
|
|
+ * \param linkArea the active area of the link
|
|
+ * \param url the URL to be open
|
|
+ */
|
|
+ LinkBrowse( const QRectF &linkArea, const QString &url );
|
|
+ /**
|
|
+ * Destructor.
|
|
+ */
|
|
+ ~LinkBrowse();
|
|
+ LinkType linkType() const;
|
|
+
|
|
+ private:
|
|
+ Q_DECLARE_PRIVATE( LinkBrowse )
|
|
+ Q_DISABLE_COPY( LinkBrowse )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \brief "Standard" action request.
|
|
+ *
|
|
+ * The LinkAction class represents a link that request a "standard" action
|
|
+ * to be performed by the viewer on the displayed document.
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT LinkAction : public Link
|
|
+{
|
|
+ public:
|
|
+ /**
|
|
+ * The possible types of actions
|
|
+ */
|
|
+ enum ActionType { PageFirst = 1,
|
|
+ PagePrev = 2,
|
|
+ PageNext = 3,
|
|
+ PageLast = 4,
|
|
+ HistoryBack = 5,
|
|
+ HistoryForward = 6,
|
|
+ Quit = 7,
|
|
+ Presentation = 8,
|
|
+ EndPresentation = 9,
|
|
+ Find = 10,
|
|
+ GoToPage = 11,
|
|
+ Close = 12,
|
|
+ Print = 13 ///< \since 0.16
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ * The action of the current LinkAction
|
|
+ */
|
|
+ ActionType actionType() const;
|
|
+
|
|
+ /**
|
|
+ * Create a new Action link, that executes a specified action
|
|
+ * on the document.
|
|
+ *
|
|
+ * \param linkArea the active area of the link
|
|
+ * \param actionType which action should be executed
|
|
+ */
|
|
+ LinkAction( const QRectF &linkArea, ActionType actionType );
|
|
+ /**
|
|
+ * Destructor.
|
|
+ */
|
|
+ ~LinkAction();
|
|
+ LinkType linkType() const;
|
|
+
|
|
+ private:
|
|
+ Q_DECLARE_PRIVATE( LinkAction )
|
|
+ Q_DISABLE_COPY( LinkAction )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * Sound: a sound to be played.
|
|
+ *
|
|
+ * \since 0.6
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT LinkSound : public Link
|
|
+{
|
|
+ public:
|
|
+ // create a Link_Sound
|
|
+ LinkSound( const QRectF &linkArea, double volume, bool sync, bool repeat, bool mix, SoundObject *sound );
|
|
+ /**
|
|
+ * Destructor.
|
|
+ */
|
|
+ virtual ~LinkSound();
|
|
+
|
|
+ LinkType linkType() const;
|
|
+
|
|
+ /**
|
|
+ * The volume to be used when playing the sound.
|
|
+ *
|
|
+ * The volume is in the range [ -1, 1 ], where:
|
|
+ * - a negative number: no volume (mute)
|
|
+ * - 1: full volume
|
|
+ */
|
|
+ double volume() const;
|
|
+ /**
|
|
+ * Whether the playback of the sound should be synchronous
|
|
+ * (thus blocking, waiting for the end of the sound playback).
|
|
+ */
|
|
+ bool synchronous() const;
|
|
+ /**
|
|
+ * Whether the sound should be played continuously (that is,
|
|
+ * started again when it ends)
|
|
+ */
|
|
+ bool repeat() const;
|
|
+ /**
|
|
+ * Whether the playback of this sound can be mixed with
|
|
+ * playbacks with other sounds of the same document.
|
|
+ *
|
|
+ * \note When false, any other playback must be stopped before
|
|
+ * playing the sound.
|
|
+ */
|
|
+ bool mix() const;
|
|
+ /**
|
|
+ * The sound object to be played
|
|
+ */
|
|
+ SoundObject *sound() const;
|
|
+
|
|
+ private:
|
|
+ Q_DECLARE_PRIVATE( LinkSound )
|
|
+ Q_DISABLE_COPY( LinkSound )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * Rendition: Rendition link.
|
|
+ *
|
|
+ * \since 0.20
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT LinkRendition : public Link
|
|
+{
|
|
+ public:
|
|
+ /**
|
|
+ * Describes the possible rendition actions.
|
|
+ *
|
|
+ * \since 0.22
|
|
+ */
|
|
+ enum RenditionAction {
|
|
+ NoRendition,
|
|
+ PlayRendition,
|
|
+ StopRendition,
|
|
+ PauseRendition,
|
|
+ ResumeRendition
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ * Create a new rendition link.
|
|
+ *
|
|
+ * \param linkArea the active area of the link
|
|
+ * \param rendition the media rendition object. Ownership is taken
|
|
+ *
|
|
+ * \deprecated Use the constructor that takes all parameter instead
|
|
+ */
|
|
+ Q_DECL_DEPRECATED LinkRendition( const QRectF &linkArea, ::MediaRendition *rendition );
|
|
+
|
|
+ /**
|
|
+ * Create a new rendition link.
|
|
+ *
|
|
+ * \param linkArea the active area of the link
|
|
+ * \param rendition the media rendition object. Ownership is taken
|
|
+ * \param operation the numeric operation (action) (@see ::LinkRendition::RenditionOperation)
|
|
+ * \param script the java script code
|
|
+ * \param annotationReference the object reference of the screen annotation associated with this rendition action
|
|
+ * \since 0.22
|
|
+ */
|
|
+ LinkRendition( const QRectF &linkArea, ::MediaRendition *rendition, int operation, const QString &script, const Ref &annotationReference );
|
|
+
|
|
+ /**
|
|
+ * Destructor.
|
|
+ */
|
|
+ virtual ~LinkRendition();
|
|
+
|
|
+ LinkType linkType() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the media rendition object if the redition provides one, @c 0 otherwise
|
|
+ */
|
|
+ MediaRendition *rendition() const;
|
|
+
|
|
+ /**
|
|
+ * Returns the action that should be executed if a rendition object is provided.
|
|
+ *
|
|
+ * \since 0.22
|
|
+ */
|
|
+ RenditionAction action() const;
|
|
+
|
|
+ /**
|
|
+ * The JS code that shall be executed or an empty string.
|
|
+ *
|
|
+ * \since 0.22
|
|
+ */
|
|
+ QString script() const;
|
|
+
|
|
+ /**
|
|
+ * Returns whether the given @p annotation is the referenced screen annotation for this rendition @p link.
|
|
+ *
|
|
+ * \since 0.22
|
|
+ */
|
|
+ bool isReferencedAnnotation( const ScreenAnnotation *annotation ) const;
|
|
+
|
|
+ private:
|
|
+ Q_DECLARE_PRIVATE( LinkRendition )
|
|
+ Q_DISABLE_COPY( LinkRendition )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * JavaScript: a JavaScript code to be interpreted.
|
|
+ *
|
|
+ * \since 0.10
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT LinkJavaScript : public Link
|
|
+{
|
|
+ public:
|
|
+ /**
|
|
+ * Create a new JavaScript link.
|
|
+ *
|
|
+ * \param linkArea the active area of the link
|
|
+ * \param js the JS code to be interpreted
|
|
+ */
|
|
+ LinkJavaScript( const QRectF &linkArea, const QString &js );
|
|
+ /**
|
|
+ * Destructor.
|
|
+ */
|
|
+ virtual ~LinkJavaScript();
|
|
+
|
|
+ LinkType linkType() const;
|
|
+
|
|
+ /**
|
|
+ * The JS code
|
|
+ */
|
|
+ QString script() const;
|
|
+
|
|
+ private:
|
|
+ Q_DECLARE_PRIVATE( LinkJavaScript )
|
|
+ Q_DISABLE_COPY( LinkJavaScript )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * Movie: a movie to be played.
|
|
+ *
|
|
+ * \since 0.20
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT LinkMovie : public Link
|
|
+{
|
|
+ public:
|
|
+ /**
|
|
+ * Describes the operation to be performed on the movie.
|
|
+ */
|
|
+ enum Operation { Play,
|
|
+ Stop,
|
|
+ Pause,
|
|
+ Resume
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ * Create a new Movie link.
|
|
+ *
|
|
+ * \param linkArea the active area of the link
|
|
+ * \param operation the operation to be performed on the movie
|
|
+ * \param annotationTitle the title of the movie annotation identifying the movie to be played
|
|
+ * \param annotationReference the object reference of the movie annotation identifying the movie to be played
|
|
+ *
|
|
+ * Note: This constructor is supposed to be used by Poppler::Page only.
|
|
+ */
|
|
+ LinkMovie( const QRectF &linkArea, Operation operation, const QString &annotationTitle, const Ref &annotationReference );
|
|
+ /**
|
|
+ * Destructor.
|
|
+ */
|
|
+ ~LinkMovie();
|
|
+ LinkType linkType() const;
|
|
+ /**
|
|
+ * Returns the operation to be performed on the movie.
|
|
+ */
|
|
+ Operation operation() const;
|
|
+ /**
|
|
+ * Returns whether the given @p annotation is the referenced movie annotation for this movie @p link.
|
|
+ */
|
|
+ bool isReferencedAnnotation( const MovieAnnotation *annotation ) const;
|
|
+
|
|
+ private:
|
|
+ Q_DECLARE_PRIVATE( LinkMovie )
|
|
+ Q_DISABLE_COPY( LinkMovie )
|
|
+};
|
|
+
|
|
+/**
|
|
+ * OCGState: an optional content group state change.
|
|
+ *
|
|
+ * \since 0.50
|
|
+ */
|
|
+class POPPLER_QT4_EXPORT LinkOCGState : public Link
|
|
+{
|
|
+ public:
|
|
+ /**
|
|
+ * Create a new OCGState link. This is only used by Poppler::Page.
|
|
+ */
|
|
+ LinkOCGState( LinkOCGStatePrivate *ocgp );
|
|
+ /**
|
|
+ * Destructor.
|
|
+ */
|
|
+ ~LinkOCGState();
|
|
+
|
|
+ LinkType linkType() const;
|
|
+
|
|
+ private:
|
|
+ Q_DECLARE_PRIVATE( LinkOCGState )
|
|
+ Q_DISABLE_COPY( LinkOCGState )
|
|
+};
|
|
+
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-media.cc b/qt4/src/poppler-media.cc
|
|
new file mode 100644
|
|
index 00000000..f385f02e
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-media.cc
|
|
@@ -0,0 +1,168 @@
|
|
+/* poppler-media.cc: qt interface to poppler
|
|
+ * Copyright (C) 2012 Guillermo A. Amaral B. <gamaral@kde.org>
|
|
+ * Copyright (C) 2013 Albert Astals Cid <aacid@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-media.h"
|
|
+
|
|
+#include "Rendition.h"
|
|
+
|
|
+#include "poppler-private.h"
|
|
+
|
|
+#include <QtCore/QBuffer>
|
|
+
|
|
+#define BUFFER_MAX 4096
|
|
+
|
|
+namespace Poppler
|
|
+{
|
|
+
|
|
+class MediaRenditionPrivate
|
|
+{
|
|
+public:
|
|
+
|
|
+ MediaRenditionPrivate(::MediaRendition *rendition)
|
|
+ : rendition(rendition)
|
|
+ {
|
|
+ }
|
|
+
|
|
+ ~MediaRenditionPrivate()
|
|
+ {
|
|
+ delete rendition;
|
|
+ }
|
|
+
|
|
+ ::MediaRendition *rendition;
|
|
+};
|
|
+
|
|
+MediaRendition::MediaRendition(::MediaRendition *rendition)
|
|
+ : d_ptr(new MediaRenditionPrivate(rendition))
|
|
+{
|
|
+}
|
|
+
|
|
+MediaRendition::~MediaRendition()
|
|
+{
|
|
+ delete d_ptr;
|
|
+}
|
|
+
|
|
+bool
|
|
+MediaRendition::isValid() const
|
|
+{
|
|
+ Q_D( const MediaRendition );
|
|
+ return d->rendition && d->rendition->isOk();
|
|
+}
|
|
+
|
|
+QString
|
|
+MediaRendition::contentType() const
|
|
+{
|
|
+ Q_ASSERT(isValid() && "Invalid media rendition.");
|
|
+ Q_D( const MediaRendition );
|
|
+ return UnicodeParsedString(d->rendition->getContentType());
|
|
+}
|
|
+
|
|
+QString
|
|
+MediaRendition::fileName() const
|
|
+{
|
|
+ Q_ASSERT(isValid() && "Invalid media rendition.");
|
|
+ Q_D( const MediaRendition );
|
|
+ return UnicodeParsedString(d->rendition->getFileName());
|
|
+}
|
|
+
|
|
+bool
|
|
+MediaRendition::isEmbedded() const
|
|
+{
|
|
+ Q_ASSERT(isValid() && "Invalid media rendition.");
|
|
+ Q_D( const MediaRendition );
|
|
+ return d->rendition->getIsEmbedded();
|
|
+}
|
|
+
|
|
+QByteArray
|
|
+MediaRendition::data() const
|
|
+{
|
|
+ Q_ASSERT(isValid() && "Invalid media rendition.");
|
|
+ Q_D( const MediaRendition );
|
|
+
|
|
+ Stream *s = d->rendition->getEmbbededStream();
|
|
+ if (!s)
|
|
+ return QByteArray();
|
|
+
|
|
+ QBuffer buffer;
|
|
+ unsigned char data[BUFFER_MAX];
|
|
+ int bread;
|
|
+
|
|
+ buffer.open(QIODevice::WriteOnly);
|
|
+ s->reset();
|
|
+ while ((bread = s->doGetChars(BUFFER_MAX, data)) != 0)
|
|
+ buffer.write(reinterpret_cast<const char *>(data), bread);
|
|
+ buffer.close();
|
|
+
|
|
+ return buffer.data();
|
|
+}
|
|
+
|
|
+bool
|
|
+MediaRendition::autoPlay() const
|
|
+{
|
|
+ Q_D( const MediaRendition );
|
|
+ if (d->rendition->getBEParameters()) {
|
|
+ return d->rendition->getBEParameters()->autoPlay;
|
|
+ } else if (d->rendition->getMHParameters()) {
|
|
+ return d->rendition->getMHParameters()->autoPlay;
|
|
+ } else qDebug("No BE or MH parameters to reference!");
|
|
+ return false;
|
|
+}
|
|
+
|
|
+bool
|
|
+MediaRendition::showControls() const
|
|
+{
|
|
+ Q_D( const MediaRendition );
|
|
+ if (d->rendition->getBEParameters()) {
|
|
+ return d->rendition->getBEParameters()->showControls;
|
|
+ } else if (d->rendition->getMHParameters()) {
|
|
+ return d->rendition->getMHParameters()->showControls;
|
|
+ } else qDebug("No BE or MH parameters to reference!");
|
|
+ return false;
|
|
+}
|
|
+
|
|
+float
|
|
+MediaRendition::repeatCount() const
|
|
+{
|
|
+ Q_D( const MediaRendition );
|
|
+ if (d->rendition->getBEParameters()) {
|
|
+ return d->rendition->getBEParameters()->repeatCount;
|
|
+ } else if (d->rendition->getMHParameters()) {
|
|
+ return d->rendition->getMHParameters()->repeatCount;
|
|
+ } else qDebug("No BE or MH parameters to reference!");
|
|
+ return 1.f;
|
|
+}
|
|
+
|
|
+QSize
|
|
+MediaRendition::size() const
|
|
+{
|
|
+ Q_D( const MediaRendition );
|
|
+ const MediaParameters *mp = 0;
|
|
+
|
|
+ if (d->rendition->getBEParameters())
|
|
+ mp = d->rendition->getBEParameters();
|
|
+ else if (d->rendition->getMHParameters())
|
|
+ mp = d->rendition->getMHParameters();
|
|
+ else qDebug("No BE or MH parameters to reference!");
|
|
+
|
|
+ if (mp)
|
|
+ return QSize(mp->windowParams.width, mp->windowParams.height);
|
|
+ return QSize();
|
|
+}
|
|
+
|
|
+}
|
|
+
|
|
diff --git a/qt4/src/poppler-media.h b/qt4/src/poppler-media.h
|
|
new file mode 100644
|
|
index 00000000..34e5c361
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-media.h
|
|
@@ -0,0 +1,100 @@
|
|
+/* poppler-media.h: qt interface to poppler
|
|
+ * Copyright (C) 2012 Guillermo A. Amaral B. <gamaral@kde.org>
|
|
+ * Copyright (C) 2012, 2013 Albert Astals Cid <aacid@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef __POPPLER_MEDIARENDITION_H__
|
|
+#define __POPPLER_MEDIARENDITION_H__
|
|
+
|
|
+#include "poppler-export.h"
|
|
+
|
|
+#include <QtCore/QSize>
|
|
+#include <QtCore/QString>
|
|
+
|
|
+class MediaRendition;
|
|
+class QIODevice;
|
|
+
|
|
+namespace Poppler
|
|
+{
|
|
+ class MediaRenditionPrivate;
|
|
+
|
|
+ /**
|
|
+ Qt wrapper for MediaRendition.
|
|
+
|
|
+ \since 0.20
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT MediaRendition {
|
|
+ public:
|
|
+ /**
|
|
+ Constructs a MediaRendition. Takes ownership of the passed rendition
|
|
+ */
|
|
+ MediaRendition(::MediaRendition *rendition);
|
|
+ ~MediaRendition();
|
|
+
|
|
+ /**
|
|
+ Check if wrapper is holding a valid rendition object.
|
|
+ */
|
|
+ bool isValid() const;
|
|
+
|
|
+ /**
|
|
+ Returns content type.
|
|
+ */
|
|
+ QString contentType() const;
|
|
+
|
|
+ /**
|
|
+ Returns file name.
|
|
+ */
|
|
+ QString fileName() const;
|
|
+
|
|
+ /**
|
|
+ Returns true if media is embedded.
|
|
+ */
|
|
+ bool isEmbedded() const;
|
|
+
|
|
+ /**
|
|
+ Returns data buffer.
|
|
+ */
|
|
+ QByteArray data() const;
|
|
+
|
|
+ /**
|
|
+ Convenience accessor for auto-play parameter.
|
|
+ */
|
|
+ bool autoPlay() const;
|
|
+
|
|
+ /**
|
|
+ Convenience accessor for show controls parameter.
|
|
+ */
|
|
+ bool showControls() const;
|
|
+
|
|
+ /**
|
|
+ Convenience accessor for repeat count parameter.
|
|
+ */
|
|
+ float repeatCount() const;
|
|
+
|
|
+ /**
|
|
+ Convenience accessor for size parameter.
|
|
+ */
|
|
+ QSize size() const;
|
|
+
|
|
+ private:
|
|
+ Q_DECLARE_PRIVATE( MediaRendition )
|
|
+ MediaRenditionPrivate *d_ptr;
|
|
+ Q_DISABLE_COPY( MediaRendition )
|
|
+ };
|
|
+}
|
|
+
|
|
+#endif /* __POPPLER_MEDIARENDITION_H__ */
|
|
diff --git a/qt4/src/poppler-movie.cc b/qt4/src/poppler-movie.cc
|
|
new file mode 100644
|
|
index 00000000..a64847c0
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-movie.cc
|
|
@@ -0,0 +1,110 @@
|
|
+/* poppler-sound.cc: qt interface to poppler
|
|
+ * Copyright (C) 2008, 2010, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2008, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2010, Carlos Garcia Campos <carlosgc@gnome.org>
|
|
+ * Copyright (C) 2012, Tobias Koenig <tobias.koenig@kdab.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-qt4.h"
|
|
+
|
|
+#include "Object.h"
|
|
+#include "Annot.h"
|
|
+#include "Movie.h"
|
|
+
|
|
+#include <QtGui/QImage>
|
|
+
|
|
+namespace Poppler
|
|
+{
|
|
+
|
|
+class MovieData
|
|
+{
|
|
+public:
|
|
+ MovieData()
|
|
+ : m_movieObj( 0 )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ ~MovieData()
|
|
+ {
|
|
+ delete m_movieObj;
|
|
+ }
|
|
+
|
|
+ Movie *m_movieObj;
|
|
+ QSize m_size;
|
|
+ int m_rotation;
|
|
+ QImage m_posterImage;
|
|
+ MovieObject::PlayMode m_playMode : 3;
|
|
+ bool m_showControls : 1;
|
|
+};
|
|
+
|
|
+MovieObject::MovieObject( AnnotMovie *ann )
|
|
+{
|
|
+ m_movieData = new MovieData();
|
|
+ m_movieData->m_movieObj = ann->getMovie()->copy();
|
|
+ //TODO: copy poster image
|
|
+
|
|
+ MovieActivationParameters *mp = m_movieData->m_movieObj->getActivationParameters();
|
|
+ int width, height;
|
|
+ m_movieData->m_movieObj->getFloatingWindowSize(&width, &height);
|
|
+ m_movieData->m_size = QSize(width, height);
|
|
+ m_movieData->m_rotation = m_movieData->m_movieObj->getRotationAngle();
|
|
+ m_movieData->m_showControls = mp->showControls;
|
|
+ m_movieData->m_playMode = (MovieObject::PlayMode)mp->repeatMode;
|
|
+}
|
|
+
|
|
+MovieObject::~MovieObject()
|
|
+{
|
|
+ delete m_movieData;
|
|
+}
|
|
+
|
|
+QString MovieObject::url() const
|
|
+{
|
|
+ GooString * goo = m_movieData->m_movieObj->getFileName();
|
|
+ return goo ? QString( goo->c_str() ) : QString();
|
|
+}
|
|
+
|
|
+QSize MovieObject::size() const
|
|
+{
|
|
+ return m_movieData->m_size;
|
|
+}
|
|
+
|
|
+int MovieObject::rotation() const
|
|
+{
|
|
+ return m_movieData->m_rotation;
|
|
+}
|
|
+
|
|
+bool MovieObject::showControls() const
|
|
+{
|
|
+ return m_movieData->m_showControls;
|
|
+}
|
|
+
|
|
+MovieObject::PlayMode MovieObject::playMode() const
|
|
+{
|
|
+ return m_movieData->m_playMode;
|
|
+}
|
|
+
|
|
+bool MovieObject::showPosterImage() const
|
|
+{
|
|
+ return (m_movieData->m_movieObj->getShowPoster() == true);
|
|
+}
|
|
+
|
|
+QImage MovieObject::posterImage() const
|
|
+{
|
|
+ return m_movieData->m_posterImage;
|
|
+}
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-optcontent-private.h b/qt4/src/poppler-optcontent-private.h
|
|
new file mode 100644
|
|
index 00000000..b5e52999
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-optcontent-private.h
|
|
@@ -0,0 +1,124 @@
|
|
+/* poppler-optcontent-private.h: qt interface to poppler
|
|
+ *
|
|
+ * Copyright (C) 2007, Brad Hards <bradh@kde.org>
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2016, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2017, Hubert Figuière <hub@figuiere.net>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef POPPLER_OPTCONTENT_PRIVATE_H
|
|
+#define POPPLER_OPTCONTENT_PRIVATE_H
|
|
+
|
|
+#include <QtCore/QMap>
|
|
+#include <QtCore/QSet>
|
|
+#include <QtCore/QString>
|
|
+
|
|
+class Array;
|
|
+class OCGs;
|
|
+class OptionalContentGroup;
|
|
+
|
|
+class QModelIndex;
|
|
+
|
|
+namespace Poppler
|
|
+{
|
|
+ class OptContentItem;
|
|
+ class OptContentModel;
|
|
+ class OptContentModelPrivate;
|
|
+
|
|
+ class RadioButtonGroup
|
|
+ {
|
|
+ public:
|
|
+ RadioButtonGroup( OptContentModelPrivate *ocModel, Array *rbarray);
|
|
+ ~RadioButtonGroup();
|
|
+ QSet<OptContentItem *> setItemOn( OptContentItem *itemToSetOn );
|
|
+
|
|
+ private:
|
|
+ QList<OptContentItem*> itemsInGroup;
|
|
+ };
|
|
+
|
|
+ class OptContentItem
|
|
+ {
|
|
+ public:
|
|
+ enum ItemState { On, Off, HeadingOnly };
|
|
+
|
|
+ OptContentItem( OptionalContentGroup *group );
|
|
+ OptContentItem( const QString &label );
|
|
+ OptContentItem();
|
|
+ ~OptContentItem();
|
|
+
|
|
+ QString name() const { return m_name; }
|
|
+ ItemState state() const { return m_stateBackup; }
|
|
+ void setState(ItemState state, bool obeyRadioGroups, QSet<OptContentItem *> &changedItems);
|
|
+
|
|
+ QList<OptContentItem*> childList() { return m_children; }
|
|
+
|
|
+ void setParent( OptContentItem* parent) { m_parent = parent; }
|
|
+ OptContentItem* parent() { return m_parent; }
|
|
+
|
|
+ void addChild( OptContentItem *child );
|
|
+
|
|
+ void appendRBGroup( RadioButtonGroup *rbgroup );
|
|
+
|
|
+ bool isEnabled() const { return m_enabled; }
|
|
+
|
|
+ QSet<OptContentItem*> recurseListChildren(bool includeMe = false) const;
|
|
+
|
|
+ private:
|
|
+ OptionalContentGroup *m_group;
|
|
+ QString m_name;
|
|
+ ItemState m_state; // true for ON, false for OFF
|
|
+ ItemState m_stateBackup;
|
|
+ QList<OptContentItem*> m_children;
|
|
+ OptContentItem *m_parent;
|
|
+ QList<RadioButtonGroup*> m_rbGroups;
|
|
+ bool m_enabled;
|
|
+ };
|
|
+
|
|
+ class OptContentModelPrivate
|
|
+ {
|
|
+ public:
|
|
+ OptContentModelPrivate( OptContentModel *qq, OCGs *optContent );
|
|
+ ~OptContentModelPrivate();
|
|
+
|
|
+ void parseRBGroupsArray( Array *rBGroupArray );
|
|
+ OptContentItem *nodeFromIndex(const QModelIndex &index, bool canBeNull = false) const;
|
|
+ QModelIndex indexFromItem(OptContentItem *node, int column) const;
|
|
+
|
|
+ /**
|
|
+ Get the OptContentItem corresponding to a given reference value.
|
|
+
|
|
+ \param ref the reference number (e.g. from Object.getRefNum()) to look up
|
|
+
|
|
+ \return the matching optional content item, or null if the reference wasn't found
|
|
+ */
|
|
+ OptContentItem *itemFromRef( const QString &ref ) const;
|
|
+ void setRootNode(OptContentItem *node);
|
|
+
|
|
+ OptContentModel *q;
|
|
+
|
|
+ QMap<QString, OptContentItem*> m_optContentItems;
|
|
+ QList<OptContentItem*> m_headerOptContentItems;
|
|
+ QList<RadioButtonGroup*> m_rbgroups;
|
|
+ OptContentItem *m_rootNode;
|
|
+
|
|
+ private:
|
|
+ void addChild( OptContentItem *parent, OptContentItem *child);
|
|
+ void parseOrderArray( OptContentItem *parentNode, Array *orderArray );
|
|
+ };
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-optcontent.cc b/qt4/src/poppler-optcontent.cc
|
|
new file mode 100644
|
|
index 00000000..0e7b5345
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-optcontent.cc
|
|
@@ -0,0 +1,455 @@
|
|
+/* poppler-optcontent.cc: qt interface to poppler
|
|
+ *
|
|
+ * Copyright (C) 2007, Brad Hards <bradh@kde.org>
|
|
+ * Copyright (C) 2008, 2014, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2008, Carlos Garcia Campos <carlosgc@gnome.org>
|
|
+ * Copyright (C) 2015-2017, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2017, Hubert Figuière <hub@figuiere.net>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-optcontent.h"
|
|
+
|
|
+#include "poppler-optcontent-private.h"
|
|
+
|
|
+#include "poppler-private.h"
|
|
+#include "poppler-link-private.h"
|
|
+
|
|
+#include <QtCore/QDebug>
|
|
+#include <QtCore/QtAlgorithms>
|
|
+
|
|
+#include "poppler/OptionalContent.h"
|
|
+#include "poppler/Link.h"
|
|
+
|
|
+namespace Poppler
|
|
+{
|
|
+
|
|
+ RadioButtonGroup::RadioButtonGroup( OptContentModelPrivate *ocModel, Array *rbarray )
|
|
+ {
|
|
+ itemsInGroup.reserve( rbarray->getLength() );
|
|
+ for (int i = 0; i < rbarray->getLength(); ++i) {
|
|
+ const Object &ref = rbarray->getNF( i );
|
|
+ if ( ! ref.isRef() ) {
|
|
+ qDebug() << "expected ref, but got:" << ref.getType();
|
|
+ }
|
|
+ OptContentItem *item = ocModel->itemFromRef( QString::number(ref.getRefNum() ) );
|
|
+ itemsInGroup.append( item );
|
|
+ }
|
|
+ for (int i = 0; i < itemsInGroup.size(); ++i) {
|
|
+ OptContentItem *item = itemsInGroup.at(i);
|
|
+ item->appendRBGroup( this );
|
|
+ }
|
|
+ }
|
|
+
|
|
+ RadioButtonGroup::~RadioButtonGroup()
|
|
+ {
|
|
+ }
|
|
+
|
|
+ QSet<OptContentItem *> RadioButtonGroup::setItemOn( OptContentItem *itemToSetOn )
|
|
+ {
|
|
+ QSet<OptContentItem *> changedItems;
|
|
+ for (int i = 0; i < itemsInGroup.size(); ++i) {
|
|
+ OptContentItem *thisItem = itemsInGroup.at(i);
|
|
+ if (thisItem != itemToSetOn) {
|
|
+ QSet<OptContentItem *> newChangedItems;
|
|
+ thisItem->setState(OptContentItem::Off, false /*obeyRadioGroups*/, newChangedItems);
|
|
+ changedItems += newChangedItems;
|
|
+ }
|
|
+ }
|
|
+ return changedItems;
|
|
+ }
|
|
+
|
|
+
|
|
+
|
|
+ OptContentItem::OptContentItem( OptionalContentGroup *group )
|
|
+ {
|
|
+ m_group = group;
|
|
+ m_parent = 0;
|
|
+ m_name = UnicodeParsedString( group->getName() );
|
|
+ if ( group->getState() == OptionalContentGroup::On ) {
|
|
+ m_state = OptContentItem::On;
|
|
+ } else {
|
|
+ m_state = OptContentItem::Off;
|
|
+ }
|
|
+ m_stateBackup = m_state;
|
|
+ m_enabled = true;
|
|
+ }
|
|
+
|
|
+ OptContentItem::OptContentItem( const QString &label )
|
|
+ {
|
|
+ m_parent = 0;
|
|
+ m_name = label;
|
|
+ m_group = 0;
|
|
+ m_state = OptContentItem::HeadingOnly;
|
|
+ m_stateBackup = m_state;
|
|
+ m_enabled = true;
|
|
+ }
|
|
+
|
|
+ OptContentItem::OptContentItem() :
|
|
+ m_parent( 0 ), m_enabled(true)
|
|
+ {
|
|
+ }
|
|
+
|
|
+ OptContentItem::~OptContentItem()
|
|
+ {
|
|
+ }
|
|
+
|
|
+ void OptContentItem::appendRBGroup( RadioButtonGroup *rbgroup )
|
|
+ {
|
|
+ m_rbGroups.append( rbgroup );
|
|
+ }
|
|
+
|
|
+
|
|
+ void OptContentItem::setState(ItemState state, bool obeyRadioGroups, QSet<OptContentItem *> &changedItems)
|
|
+ {
|
|
+ if (state == m_state)
|
|
+ return;
|
|
+
|
|
+ m_state = state;
|
|
+ m_stateBackup = m_state;
|
|
+ changedItems.insert(this);
|
|
+ QSet<OptContentItem *> empty;
|
|
+ Q_FOREACH (OptContentItem *child, m_children) {
|
|
+ ItemState oldState = child->m_stateBackup;
|
|
+ child->setState(state == OptContentItem::On ? child->m_stateBackup : OptContentItem::Off, true /*obeyRadioGroups*/, empty);
|
|
+ child->m_enabled = state == OptContentItem::On;
|
|
+ child->m_stateBackup = oldState;
|
|
+ }
|
|
+ if (!m_group || !obeyRadioGroups) {
|
|
+ return;
|
|
+ }
|
|
+ if ( state == OptContentItem::On ) {
|
|
+ m_group->setState( OptionalContentGroup::On );
|
|
+ for (int i = 0; i < m_rbGroups.size(); ++i) {
|
|
+ RadioButtonGroup *rbgroup = m_rbGroups.at(i);
|
|
+ changedItems += rbgroup->setItemOn( this );
|
|
+ }
|
|
+ } else if ( state == OptContentItem::Off ) {
|
|
+ m_group->setState( OptionalContentGroup::Off );
|
|
+ }
|
|
+ }
|
|
+
|
|
+ void OptContentItem::addChild( OptContentItem *child )
|
|
+ {
|
|
+ m_children += child;
|
|
+ child->setParent( this );
|
|
+ }
|
|
+
|
|
+ QSet<OptContentItem*> OptContentItem::recurseListChildren(bool includeMe) const
|
|
+ {
|
|
+ QSet<OptContentItem*> ret;
|
|
+ if (includeMe) {
|
|
+ ret.insert(const_cast<OptContentItem*>(this));
|
|
+ }
|
|
+ Q_FOREACH (OptContentItem *child, m_children) {
|
|
+ ret += child->recurseListChildren(true);
|
|
+ }
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ OptContentModelPrivate::OptContentModelPrivate( OptContentModel *qq, OCGs *optContent )
|
|
+ : q(qq)
|
|
+ {
|
|
+ m_rootNode = new OptContentItem();
|
|
+ const auto &ocgs = optContent->getOCGs();
|
|
+
|
|
+ for (const auto& ocg : ocgs) {
|
|
+ OptContentItem *node = new OptContentItem( ocg.second.get() );
|
|
+ m_optContentItems.insert( QString::number( ocg.first.num ), node );
|
|
+ }
|
|
+
|
|
+ if ( optContent->getOrderArray() == 0 ) {
|
|
+ // no Order array, so drop them all at the top level
|
|
+ QMapIterator<QString, OptContentItem*> i(m_optContentItems);
|
|
+ while ( i.hasNext() ) {
|
|
+ i.next();
|
|
+ addChild( m_rootNode, i.value() );
|
|
+ }
|
|
+ } else {
|
|
+ parseOrderArray( m_rootNode, optContent->getOrderArray() );
|
|
+ }
|
|
+
|
|
+ parseRBGroupsArray( optContent->getRBGroupsArray() );
|
|
+ }
|
|
+
|
|
+ OptContentModelPrivate::~OptContentModelPrivate()
|
|
+ {
|
|
+ qDeleteAll( m_optContentItems );
|
|
+ qDeleteAll( m_rbgroups );
|
|
+ qDeleteAll( m_headerOptContentItems );
|
|
+ delete m_rootNode;
|
|
+ }
|
|
+
|
|
+ void OptContentModelPrivate::parseOrderArray( OptContentItem *parentNode, Array *orderArray )
|
|
+ {
|
|
+ OptContentItem *lastItem = parentNode;
|
|
+ for (int i = 0; i < orderArray->getLength(); ++i) {
|
|
+ Object orderItem = orderArray->get(i);
|
|
+ if ( orderItem.isDict() ) {
|
|
+ const Object &item = orderArray->getNF(i);
|
|
+ if (item.isRef() ) {
|
|
+ OptContentItem *ocItem = m_optContentItems.value(QString::number(item.getRefNum()), 0);
|
|
+ if (ocItem) {
|
|
+ addChild( parentNode, ocItem );
|
|
+ lastItem = ocItem;
|
|
+ } else {
|
|
+ qDebug() << "could not find group for object" << item.getRefNum();
|
|
+ }
|
|
+ }
|
|
+ } else if ( (orderItem.isArray()) && (orderItem.arrayGetLength() > 0) ) {
|
|
+ parseOrderArray(lastItem, orderItem.getArray());
|
|
+ } else if ( orderItem.isString() ) {
|
|
+ const GooString *label = orderItem.getString();
|
|
+ OptContentItem *header = new OptContentItem ( UnicodeParsedString ( label ) );
|
|
+ m_headerOptContentItems.append( header );
|
|
+ addChild( parentNode, header );
|
|
+ parentNode = header;
|
|
+ lastItem = header;
|
|
+ } else {
|
|
+ qDebug() << "something unexpected";
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ void OptContentModelPrivate::parseRBGroupsArray( Array *rBGroupArray )
|
|
+ {
|
|
+ if (! rBGroupArray) {
|
|
+ return;
|
|
+ }
|
|
+ // This is an array of array(s)
|
|
+ for (int i = 0; i < rBGroupArray->getLength(); ++i) {
|
|
+ Object rbObj = rBGroupArray->get(i);
|
|
+ if ( ! rbObj.isArray() ) {
|
|
+ qDebug() << "expected inner array, got:" << rbObj.getType();
|
|
+ return;
|
|
+ }
|
|
+ Array *rbarray = rbObj.getArray();
|
|
+ RadioButtonGroup *rbg = new RadioButtonGroup( this, rbarray );
|
|
+ m_rbgroups.append( rbg );
|
|
+ }
|
|
+ }
|
|
+
|
|
+ OptContentModel::OptContentModel( OCGs *optContent, QObject *parent)
|
|
+ : QAbstractItemModel(parent)
|
|
+ {
|
|
+ d = new OptContentModelPrivate( this, optContent );
|
|
+ }
|
|
+
|
|
+ OptContentModel::~OptContentModel()
|
|
+ {
|
|
+ delete d;
|
|
+ }
|
|
+
|
|
+ void OptContentModelPrivate::setRootNode(OptContentItem *node)
|
|
+ {
|
|
+ delete m_rootNode;
|
|
+ m_rootNode = node;
|
|
+ q->reset();
|
|
+ }
|
|
+
|
|
+ QModelIndex OptContentModel::index(int row, int column, const QModelIndex &parent) const
|
|
+ {
|
|
+ if (row < 0 || column != 0) {
|
|
+ return QModelIndex();
|
|
+ }
|
|
+
|
|
+ OptContentItem *parentNode = d->nodeFromIndex( parent );
|
|
+ if (row < parentNode->childList().count()) {
|
|
+ return createIndex(row, column, parentNode->childList().at(row));
|
|
+ }
|
|
+ return QModelIndex();
|
|
+ }
|
|
+
|
|
+ QModelIndex OptContentModel::parent(const QModelIndex &child) const
|
|
+ {
|
|
+ OptContentItem *childNode = d->nodeFromIndex( child );
|
|
+ if (!childNode) {
|
|
+ return QModelIndex();
|
|
+ }
|
|
+ return d->indexFromItem(childNode->parent(), child.column());
|
|
+ }
|
|
+
|
|
+ QModelIndex OptContentModelPrivate::indexFromItem(OptContentItem *node, int column) const
|
|
+ {
|
|
+ if (!node) {
|
|
+ return QModelIndex();
|
|
+ }
|
|
+ OptContentItem *parentNode = node->parent();
|
|
+ if (!parentNode) {
|
|
+ return QModelIndex();
|
|
+ }
|
|
+ const int row = parentNode->childList().indexOf(node);
|
|
+ return q->createIndex(row, column, node);
|
|
+ }
|
|
+
|
|
+ int OptContentModel::rowCount(const QModelIndex &parent) const
|
|
+ {
|
|
+ OptContentItem *parentNode = d->nodeFromIndex( parent );
|
|
+ if (!parentNode) {
|
|
+ return 0;
|
|
+ } else {
|
|
+ return parentNode->childList().count();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ int OptContentModel::columnCount(const QModelIndex &parent) const
|
|
+ {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+
|
|
+ QVariant OptContentModel::data(const QModelIndex &index, int role) const
|
|
+ {
|
|
+ OptContentItem *node = d->nodeFromIndex(index, true);
|
|
+ if (!node) {
|
|
+ return QVariant();
|
|
+ }
|
|
+
|
|
+ switch (role) {
|
|
+ case Qt::DisplayRole:
|
|
+ return node->name();
|
|
+ break;
|
|
+ case Qt::EditRole:
|
|
+ if (node->state() == OptContentItem::On) {
|
|
+ return true;
|
|
+ } else if (node->state() == OptContentItem::Off) {
|
|
+ return false;
|
|
+ }
|
|
+ break;
|
|
+ case Qt::CheckStateRole:
|
|
+ if (node->state() == OptContentItem::On) {
|
|
+ return Qt::Checked;
|
|
+ } else if (node->state() == OptContentItem::Off) {
|
|
+ return Qt::Unchecked;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return QVariant();
|
|
+ }
|
|
+
|
|
+ bool OptContentModel::setData ( const QModelIndex & index, const QVariant & value, int role )
|
|
+ {
|
|
+ OptContentItem *node = d->nodeFromIndex(index, true);
|
|
+ if (!node) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ switch (role) {
|
|
+ case Qt::CheckStateRole:
|
|
+ {
|
|
+ const bool newvalue = value.toBool();
|
|
+ QSet<OptContentItem *> changedItems;
|
|
+ node->setState(newvalue ? OptContentItem::On : OptContentItem::Off, true /*obeyRadioGroups*/, changedItems);
|
|
+
|
|
+ if (!changedItems.isEmpty()) {
|
|
+ changedItems += node->recurseListChildren(false);
|
|
+ QModelIndexList indexes;
|
|
+ Q_FOREACH (OptContentItem *item, changedItems) {
|
|
+ indexes.append(d->indexFromItem(item, 0));
|
|
+ }
|
|
+ qStableSort(indexes);
|
|
+ Q_FOREACH (const QModelIndex &changedIndex, indexes) {
|
|
+ emit dataChanged(changedIndex, changedIndex);
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ Qt::ItemFlags OptContentModel::flags ( const QModelIndex & index ) const
|
|
+ {
|
|
+ OptContentItem *node = d->nodeFromIndex(index);
|
|
+ Qt::ItemFlags itemFlags = Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
|
|
+ if (node->isEnabled()) {
|
|
+ itemFlags |= Qt::ItemIsEnabled;
|
|
+ }
|
|
+ return itemFlags;
|
|
+ }
|
|
+
|
|
+ QVariant OptContentModel::headerData( int section, Qt::Orientation orientation, int role ) const
|
|
+ {
|
|
+ return QAbstractItemModel::headerData( section, orientation, role );
|
|
+ }
|
|
+
|
|
+ void OptContentModel::applyLink( LinkOCGState *link )
|
|
+ {
|
|
+ ::LinkOCGState *popplerLinkOCGState = static_cast<LinkOCGStatePrivate*>(link->d_ptr)->popplerLinkOCGState;
|
|
+
|
|
+ QSet<OptContentItem *> changedItems;
|
|
+
|
|
+ const std::vector<::LinkOCGState::StateList>& statesList = popplerLinkOCGState->getStateList();
|
|
+ for (const ::LinkOCGState::StateList& stateList : statesList) {
|
|
+ const std::vector<Ref>& refsList = stateList.list;
|
|
+ for (const Ref& ref : refsList) {
|
|
+ OptContentItem *item = d->itemFromRef(QString::number(ref.num));
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+ if (stateList.st == ::LinkOCGState::On) {
|
|
+ item->setState(OptContentItem::On, popplerLinkOCGState->getPreserveRB(), changedItems);
|
|
+ } else if (stateList.st == ::LinkOCGState::Off) {
|
|
+ item->setState(OptContentItem::Off, popplerLinkOCGState->getPreserveRB(), changedItems);
|
|
+ } else {
|
|
+ OptContentItem::ItemState newState = item->state() == OptContentItem::On ? OptContentItem::Off : OptContentItem::On;
|
|
+ item->setState(newState, popplerLinkOCGState->getPreserveRB(), changedItems);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!changedItems.isEmpty()) {
|
|
+ QSet<OptContentItem *> aux;
|
|
+ Q_FOREACH (OptContentItem *item, aux) {
|
|
+ changedItems += item->recurseListChildren(false);
|
|
+ }
|
|
+
|
|
+ QModelIndexList indexes;
|
|
+ Q_FOREACH (OptContentItem *item, changedItems) {
|
|
+ indexes.append(d->indexFromItem(item, 0));
|
|
+ }
|
|
+ qStableSort(indexes);
|
|
+ Q_FOREACH (const QModelIndex &changedIndex, indexes) {
|
|
+ emit dataChanged(changedIndex, changedIndex);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ void OptContentModelPrivate::addChild( OptContentItem *parent, OptContentItem *child )
|
|
+ {
|
|
+ parent->addChild( child );
|
|
+ }
|
|
+
|
|
+ OptContentItem* OptContentModelPrivate::itemFromRef( const QString &ref ) const
|
|
+ {
|
|
+ return m_optContentItems.value(ref, 0);
|
|
+ }
|
|
+
|
|
+ OptContentItem* OptContentModelPrivate::nodeFromIndex(const QModelIndex &index, bool canBeNull) const
|
|
+ {
|
|
+ if (index.isValid()) {
|
|
+ return static_cast<OptContentItem *>(index.internalPointer());
|
|
+ } else {
|
|
+ return canBeNull ? 0 : m_rootNode;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+#include "poppler-optcontent.moc"
|
|
diff --git a/qt4/src/poppler-optcontent.h b/qt4/src/poppler-optcontent.h
|
|
new file mode 100644
|
|
index 00000000..bf00a88d
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-optcontent.h
|
|
@@ -0,0 +1,84 @@
|
|
+/* poppler-optcontent.h: qt interface to poppler
|
|
+ *
|
|
+ * Copyright (C) 2007, Brad Hards <bradh@kde.org>
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2016, Albert Astals Cid <aacid@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef POPPLER_OPTCONTENT_H
|
|
+#define POPPLER_OPTCONTENT_H
|
|
+
|
|
+#include <QtCore/QAbstractListModel>
|
|
+
|
|
+#include "poppler-export.h"
|
|
+#include "poppler-link.h"
|
|
+
|
|
+class OCGs;
|
|
+
|
|
+namespace Poppler
|
|
+{
|
|
+ class Document;
|
|
+ class OptContentModelPrivate;
|
|
+
|
|
+ /**
|
|
+ * \brief Model for optional content
|
|
+ *
|
|
+ * OptContentModel is an item model representing the optional content items
|
|
+ * that can be found in PDF documents.
|
|
+ *
|
|
+ * The model offers a mostly read-only display of the data, allowing to
|
|
+ * enable/disable some contents setting the Qt::CheckStateRole data role.
|
|
+ *
|
|
+ * \since 0.8
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT OptContentModel : public QAbstractItemModel
|
|
+ {
|
|
+ friend class Document;
|
|
+
|
|
+ Q_OBJECT
|
|
+
|
|
+ public:
|
|
+ virtual ~OptContentModel();
|
|
+
|
|
+ QModelIndex index(int row, int column, const QModelIndex &parent) const;
|
|
+ QModelIndex parent(const QModelIndex &child) const;
|
|
+
|
|
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
|
+ int columnCount(const QModelIndex &parent) const;
|
|
+
|
|
+ QVariant data(const QModelIndex &index, int role) const;
|
|
+ virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole );
|
|
+
|
|
+ Qt::ItemFlags flags ( const QModelIndex & index ) const;
|
|
+
|
|
+ virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
|
|
+
|
|
+ /**
|
|
+ * Applies the Optional Content Changes specified by that link.
|
|
+ * \since 0.50
|
|
+ */
|
|
+ void applyLink( LinkOCGState *link );
|
|
+
|
|
+ private:
|
|
+ OptContentModel( OCGs *optContent, QObject *parent = 0);
|
|
+
|
|
+ friend class OptContentModelPrivate;
|
|
+ OptContentModelPrivate *d;
|
|
+ };
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-page-private.h b/qt4/src/poppler-page-private.h
|
|
new file mode 100644
|
|
index 00000000..1cb63e9f
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-page-private.h
|
|
@@ -0,0 +1,57 @@
|
|
+/* poppler-page.cc: qt interface to poppler
|
|
+ * Copyright (C) 2005, Net Integration Technologies, Inc.
|
|
+ * Copyright (C) 2007, 2012, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2015 Adam Reichold <adamreichold@myopera.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef _POPPLER_PAGE_PRIVATE_H_
|
|
+#define _POPPLER_PAGE_PRIVATE_H_
|
|
+
|
|
+#include "CharTypes.h"
|
|
+
|
|
+class QRectF;
|
|
+
|
|
+class LinkAction;
|
|
+class Page;
|
|
+class TextPage;
|
|
+
|
|
+namespace Poppler
|
|
+{
|
|
+
|
|
+class DocumentData;
|
|
+class PageTransition;
|
|
+
|
|
+class PageData {
|
|
+public:
|
|
+ Link* convertLinkActionToLink(::LinkAction * a, const QRectF &linkArea);
|
|
+
|
|
+ DocumentData *parentDoc;
|
|
+ ::Page *page;
|
|
+ int index;
|
|
+ PageTransition *transition;
|
|
+
|
|
+ static Link* convertLinkActionToLink(::LinkAction * a, DocumentData *parentDoc, const QRectF &linkArea);
|
|
+
|
|
+ TextPage *prepareTextSearch(const QString &text, Page::Rotation rotate, QVector<Unicode> *u);
|
|
+ bool performSingleTextSearch(TextPage* textPage, QVector<Unicode> &u, double &sLeft, double &sTop, double &sRight, double &sBottom, Page::SearchDirection direction, bool sCase, bool sWords);
|
|
+ QList<QRectF> performMultipleTextSearch(TextPage* textPage, QVector<Unicode> &u, bool sCase, bool sWords);
|
|
+};
|
|
+
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-page-transition-private.h b/qt4/src/poppler-page-transition-private.h
|
|
new file mode 100644
|
|
index 00000000..63febb09
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-page-transition-private.h
|
|
@@ -0,0 +1,28 @@
|
|
+/*
|
|
+ * Copyright (C) 2005, Albert Astals Cid
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+class Object;
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+class PageTransitionParams {
|
|
+ public:
|
|
+ Object *dictObj;
|
|
+};
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-page-transition.cc b/qt4/src/poppler-page-transition.cc
|
|
new file mode 100644
|
|
index 00000000..4fa39edd
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-page-transition.cc
|
|
@@ -0,0 +1,101 @@
|
|
+/* PageTransition.cc
|
|
+ * Copyright (C) 2005, Net Integration Technologies, Inc.
|
|
+ * Copyright (C) 2015, Arseniy Lartsev <arseniy@alumni.chalmers.se>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "PageTransition.h"
|
|
+#include "poppler-page-transition.h"
|
|
+#include "poppler-page-transition-private.h"
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+class PageTransitionData
|
|
+{
|
|
+ public:
|
|
+ PageTransitionData(Object *trans)
|
|
+ {
|
|
+ pt = new ::PageTransition(trans);
|
|
+ }
|
|
+
|
|
+ PageTransitionData(const PageTransitionData &ptd)
|
|
+ {
|
|
+ pt = new ::PageTransition(*ptd.pt);
|
|
+ }
|
|
+
|
|
+ ~PageTransitionData()
|
|
+ {
|
|
+ delete pt;
|
|
+ }
|
|
+
|
|
+ ::PageTransition *pt;
|
|
+};
|
|
+
|
|
+PageTransition::PageTransition(const PageTransitionParams ¶ms)
|
|
+{
|
|
+ data = new PageTransitionData(params.dictObj);
|
|
+}
|
|
+
|
|
+PageTransition::PageTransition(const PageTransition &pt)
|
|
+{
|
|
+ data = new PageTransitionData(*pt.data);
|
|
+}
|
|
+
|
|
+PageTransition::~PageTransition()
|
|
+{
|
|
+ delete data;
|
|
+}
|
|
+
|
|
+PageTransition::Type PageTransition::type() const
|
|
+{
|
|
+ return (Poppler::PageTransition::Type)data->pt->getType();
|
|
+}
|
|
+
|
|
+int PageTransition::duration() const
|
|
+{
|
|
+ return data->pt->getDuration();
|
|
+}
|
|
+
|
|
+double PageTransition::durationReal() const
|
|
+{
|
|
+ return data->pt->getDuration();
|
|
+}
|
|
+
|
|
+PageTransition::Alignment PageTransition::alignment() const
|
|
+{
|
|
+ return (Poppler::PageTransition::Alignment)data->pt->getAlignment();
|
|
+}
|
|
+
|
|
+PageTransition::Direction PageTransition::direction() const
|
|
+{
|
|
+ return (Poppler::PageTransition::Direction)data->pt->getDirection();
|
|
+}
|
|
+
|
|
+int PageTransition::angle() const
|
|
+{
|
|
+ return data->pt->getAngle();
|
|
+}
|
|
+
|
|
+double PageTransition::scale() const
|
|
+{
|
|
+ return data->pt->getScale();
|
|
+}
|
|
+bool PageTransition::isRectangular() const
|
|
+{
|
|
+ return data->pt->isRectangular();
|
|
+}
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-page-transition.h b/qt4/src/poppler-page-transition.h
|
|
new file mode 100644
|
|
index 00000000..e92adbd8
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-page-transition.h
|
|
@@ -0,0 +1,158 @@
|
|
+/* PageTransition.h
|
|
+ * Copyright (C) 2005, Net Integration Technologies, Inc.
|
|
+ * Copyright (C) 2005, Brad Hards <bradh@frogmouth.net>
|
|
+ * Copyright (C) 2015, Arseniy Lartsev <arseniy@alumni.chalmers.se>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef __PAGETRANSITION_X_H__
|
|
+#define __PAGETRANSITION_X_H__
|
|
+
|
|
+#include "poppler-export.h"
|
|
+
|
|
+#include <QtCore/qglobal.h>
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+class PageTransitionParams;
|
|
+class PageTransitionData;
|
|
+
|
|
+/**
|
|
+ \brief Describes how a PDF file viewer shall perform the transition
|
|
+ from one page to another
|
|
+
|
|
+ In PDF files there is a way to specify if the viewer shall use
|
|
+ certain effects to perform the transition from one page to
|
|
+ another. This feature can be used, e.g., in a PDF-based beamer
|
|
+ presentation.
|
|
+
|
|
+ This utility class represents the transition effect, and can be
|
|
+ used to extract the information from a PDF object.
|
|
+*/
|
|
+
|
|
+
|
|
+class POPPLER_QT4_EXPORT PageTransition {
|
|
+ public:
|
|
+
|
|
+ /** \brief transition effect that shall be used
|
|
+ */
|
|
+ // if changed remember to keep in sync with PageTransition.h enum
|
|
+ enum Type {
|
|
+ Replace = 0,
|
|
+ Split,
|
|
+ Blinds,
|
|
+ Box,
|
|
+ Wipe,
|
|
+ Dissolve,
|
|
+ Glitter,
|
|
+ Fly,
|
|
+ Push,
|
|
+ Cover,
|
|
+ Uncover,
|
|
+ Fade
|
|
+ };
|
|
+
|
|
+ /** \brief alignment of the transition effect that shall be used
|
|
+ */
|
|
+ // if changed remember to keep in sync with PageTransition.h enum
|
|
+ enum Alignment {
|
|
+ Horizontal = 0,
|
|
+ Vertical
|
|
+ };
|
|
+
|
|
+ /** \brief direction of the transition effect that shall be used
|
|
+ */
|
|
+ // if changed remember to keep in sync with PageTransition.h enum
|
|
+ enum Direction {
|
|
+ Inward = 0,
|
|
+ Outward
|
|
+ };
|
|
+
|
|
+ /** \brief Construct a new PageTransition object from a page dictionary.
|
|
+
|
|
+ Users of the library will rarely need to construct a
|
|
+ PageTransition object themselves. Instead, the method
|
|
+ Poppler::Page::transition() can be used to find out if a certain
|
|
+ transition effect is specified.
|
|
+
|
|
+ @warning In case or error, this method will print an error message to stderr,
|
|
+ and construct a default object.
|
|
+
|
|
+ @param params an object whose dictionary will be read and
|
|
+ parsed. This must be a valid object, whose dictionaries are
|
|
+ accessed by the constructor. The object is only accessed by this
|
|
+ constructor, and may be deleted after the constructor returns.
|
|
+ */
|
|
+ PageTransition(const PageTransitionParams ¶ms);
|
|
+
|
|
+ /** \brief copy constructor */
|
|
+ PageTransition(const PageTransition &pt);
|
|
+
|
|
+ /**
|
|
+ Destructor
|
|
+ */
|
|
+ ~PageTransition();
|
|
+
|
|
+ /**
|
|
+ \brief Get type of the transition.
|
|
+ */
|
|
+ Type type() const;
|
|
+
|
|
+ /**
|
|
+ \brief Get duration of the transition in seconds as integer
|
|
+
|
|
+ \deprecated This function is left for backward compatibility, use durationReal() instead.
|
|
+ */
|
|
+ Q_DECL_DEPRECATED int duration() const;
|
|
+
|
|
+ /**
|
|
+ \brief Get duration of the transition in seconds
|
|
+ */
|
|
+ double durationReal() const;
|
|
+
|
|
+ /**
|
|
+ \brief Get dimension in which the transition effect occurs.
|
|
+ */
|
|
+ Alignment alignment() const;
|
|
+
|
|
+ /**
|
|
+ \brief Get direction of motion of the transition effect.
|
|
+ */
|
|
+ Direction direction() const;
|
|
+
|
|
+ /**
|
|
+ \brief Get direction in which the transition effect moves.
|
|
+ */
|
|
+ int angle() const;
|
|
+
|
|
+ /**
|
|
+ \brief Get starting or ending scale.
|
|
+ */
|
|
+ double scale() const;
|
|
+
|
|
+ /**
|
|
+ \brief Returns true if the area to be flown is rectangular and
|
|
+ opaque.
|
|
+ */
|
|
+ bool isRectangular() const;
|
|
+
|
|
+ private:
|
|
+ PageTransitionData *data;
|
|
+};
|
|
+
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-page.cc b/qt4/src/poppler-page.cc
|
|
new file mode 100644
|
|
index 00000000..ffe6e99c
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-page.cc
|
|
@@ -0,0 +1,810 @@
|
|
+/* poppler-page.cc: qt interface to poppler
|
|
+ * Copyright (C) 2005, Net Integration Technologies, Inc.
|
|
+ * Copyright (C) 2005, Brad Hards <bradh@frogmouth.net>
|
|
+ * Copyright (C) 2005-2017, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2005, Stefan Kebekus <stefan.kebekus@math.uni-koeln.de>
|
|
+ * Copyright (C) 2006-2011, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org>
|
|
+ * Copyright (C) 2009 Shawn Rutledge <shawn.t.rutledge@gmail.com>
|
|
+ * Copyright (C) 2010, 2012, Guillermo Amaral <gamaral@kdab.com>
|
|
+ * Copyright (C) 2010 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
|
|
+ * Copyright (C) 2010 Matthias Fauconneau <matthias.fauconneau@gmail.com>
|
|
+ * Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
|
|
+ * Copyright (C) 2012 Tobias Koenig <tokoe@kdab.com>
|
|
+ * Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
|
|
+ * Copyright (C) 2012, 2015 Adam Reichold <adamreichold@myopera.com>
|
|
+ * Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
|
|
+ * Copyright (C) 2015 William Bader <williambader@hotmail.com>
|
|
+ * Copyright (C) 2016 Arseniy Lartsev <arseniy@alumni.chalmers.se>
|
|
+ * Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <QtCore/QHash>
|
|
+#include <QtCore/QMap>
|
|
+#include <QtCore/QVarLengthArray>
|
|
+#include <QtGui/QImage>
|
|
+#include <QtGui/QPainter>
|
|
+
|
|
+#include <config.h>
|
|
+#include <PDFDoc.h>
|
|
+#include <Catalog.h>
|
|
+#include <Form.h>
|
|
+#include <ErrorCodes.h>
|
|
+#include <TextOutputDev.h>
|
|
+#include <Annot.h>
|
|
+#include <Link.h>
|
|
+#include <ArthurOutputDev.h>
|
|
+#include <Rendition.h>
|
|
+#if defined(HAVE_SPLASH)
|
|
+#include <SplashOutputDev.h>
|
|
+#include <splash/SplashBitmap.h>
|
|
+#endif
|
|
+
|
|
+#include "poppler-private.h"
|
|
+#include "poppler-page-transition-private.h"
|
|
+#include "poppler-page-private.h"
|
|
+#include "poppler-link-extractor-private.h"
|
|
+#include "poppler-link-private.h"
|
|
+#include "poppler-annotation-private.h"
|
|
+#include "poppler-form.h"
|
|
+#include "poppler-media.h"
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+Link* PageData::convertLinkActionToLink(::LinkAction * a, const QRectF &linkArea)
|
|
+{
|
|
+ return convertLinkActionToLink(a, parentDoc, linkArea);
|
|
+}
|
|
+
|
|
+Link* PageData::convertLinkActionToLink(::LinkAction * a, DocumentData *parentDoc, const QRectF &linkArea)
|
|
+{
|
|
+ if ( !a )
|
|
+ return NULL;
|
|
+
|
|
+ Link * popplerLink = NULL;
|
|
+ switch ( a->getKind() )
|
|
+ {
|
|
+ case actionGoTo:
|
|
+ {
|
|
+ LinkGoTo * g = (LinkGoTo *) a;
|
|
+ const LinkDestinationData ldd( g->getDest(), g->getNamedDest(), parentDoc, false );
|
|
+ // create link: no ext file, namedDest, object pointer
|
|
+ popplerLink = new LinkGoto( linkArea, QString::null, LinkDestination( ldd ) );
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case actionGoToR:
|
|
+ {
|
|
+ LinkGoToR * g = (LinkGoToR *) a;
|
|
+ // copy link file
|
|
+ const QString fileName = UnicodeParsedString( g->getFileName() );
|
|
+ const LinkDestinationData ldd( g->getDest(), g->getNamedDest(), parentDoc, !fileName.isEmpty() );
|
|
+ // ceate link: fileName, namedDest, object pointer
|
|
+ popplerLink = new LinkGoto( linkArea, fileName, LinkDestination( ldd ) );
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case actionLaunch:
|
|
+ {
|
|
+ LinkLaunch * e = (LinkLaunch *)a;
|
|
+ const GooString * p = e->getParams();
|
|
+ popplerLink = new LinkExecute( linkArea, e->getFileName()->c_str(), p ? p->c_str() : 0 );
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case actionNamed:
|
|
+ {
|
|
+ const char * name = ((LinkNamed *)a)->getName()->c_str();
|
|
+ if ( !strcmp( name, "NextPage" ) )
|
|
+ popplerLink = new LinkAction( linkArea, LinkAction::PageNext );
|
|
+ else if ( !strcmp( name, "PrevPage" ) )
|
|
+ popplerLink = new LinkAction( linkArea, LinkAction::PagePrev );
|
|
+ else if ( !strcmp( name, "FirstPage" ) )
|
|
+ popplerLink = new LinkAction( linkArea, LinkAction::PageFirst );
|
|
+ else if ( !strcmp( name, "LastPage" ) )
|
|
+ popplerLink = new LinkAction( linkArea, LinkAction::PageLast );
|
|
+ else if ( !strcmp( name, "GoBack" ) )
|
|
+ popplerLink = new LinkAction( linkArea, LinkAction::HistoryBack );
|
|
+ else if ( !strcmp( name, "GoForward" ) )
|
|
+ popplerLink = new LinkAction( linkArea, LinkAction::HistoryForward );
|
|
+ else if ( !strcmp( name, "Quit" ) )
|
|
+ popplerLink = new LinkAction( linkArea, LinkAction::Quit );
|
|
+ else if ( !strcmp( name, "GoToPage" ) )
|
|
+ popplerLink = new LinkAction( linkArea, LinkAction::GoToPage );
|
|
+ else if ( !strcmp( name, "Find" ) )
|
|
+ popplerLink = new LinkAction( linkArea, LinkAction::Find );
|
|
+ else if ( !strcmp( name, "FullScreen" ) )
|
|
+ popplerLink = new LinkAction( linkArea, LinkAction::Presentation );
|
|
+ else if ( !strcmp( name, "Print" ) )
|
|
+ popplerLink = new LinkAction( linkArea, LinkAction::Print );
|
|
+ else if ( !strcmp( name, "Close" ) )
|
|
+ {
|
|
+ // acroread closes the document always, doesnt care whether
|
|
+ // its presentation mode or not
|
|
+ // popplerLink = new LinkAction( linkArea, LinkAction::EndPresentation );
|
|
+ popplerLink = new LinkAction( linkArea, LinkAction::Close );
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ // TODO
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case actionURI:
|
|
+ {
|
|
+ popplerLink = new LinkBrowse( linkArea, ((LinkURI *)a)->getURI()->c_str() );
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case actionSound:
|
|
+ {
|
|
+ ::LinkSound *ls = (::LinkSound *)a;
|
|
+ popplerLink = new LinkSound( linkArea, ls->getVolume(), ls->getSynchronous(), ls->getRepeat(), ls->getMix(), new SoundObject( ls->getSound() ) );
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case actionJavaScript:
|
|
+ {
|
|
+ ::LinkJavaScript *ljs = (::LinkJavaScript *)a;
|
|
+ popplerLink = new LinkJavaScript( linkArea, UnicodeParsedString(ljs->getScript()) );
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case actionMovie:
|
|
+ {
|
|
+ ::LinkMovie *lm = (::LinkMovie *)a;
|
|
+
|
|
+ const QString title = ( lm->hasAnnotTitle() ? UnicodeParsedString( lm->getAnnotTitle() ) : QString() );
|
|
+
|
|
+ Ref reference;
|
|
+ reference.num = reference.gen = -1;
|
|
+ if ( lm->hasAnnotRef() )
|
|
+ reference = *lm->getAnnotRef();
|
|
+
|
|
+ LinkMovie::Operation operation = LinkMovie::Play;
|
|
+ switch ( lm->getOperation() )
|
|
+ {
|
|
+ case ::LinkMovie::operationTypePlay:
|
|
+ operation = LinkMovie::Play;
|
|
+ break;
|
|
+ case ::LinkMovie::operationTypePause:
|
|
+ operation = LinkMovie::Pause;
|
|
+ break;
|
|
+ case ::LinkMovie::operationTypeResume:
|
|
+ operation = LinkMovie::Resume;
|
|
+ break;
|
|
+ case ::LinkMovie::operationTypeStop:
|
|
+ operation = LinkMovie::Stop;
|
|
+ break;
|
|
+ };
|
|
+
|
|
+ popplerLink = new LinkMovie( linkArea, operation, title, reference );
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case actionRendition:
|
|
+ {
|
|
+ ::LinkRendition *lrn = (::LinkRendition *)a;
|
|
+
|
|
+ Ref reference;
|
|
+ reference.num = reference.gen = -1;
|
|
+ if ( lrn->hasScreenAnnot() )
|
|
+ reference = lrn->getScreenAnnot();
|
|
+
|
|
+ popplerLink = new LinkRendition( linkArea, lrn->getMedia() ? lrn->getMedia()->copy() : NULL, lrn->getOperation(), UnicodeParsedString( lrn->getScript() ), reference );
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case actionOCGState:
|
|
+ {
|
|
+ ::LinkOCGState *plocg = (::LinkOCGState *)a;
|
|
+
|
|
+ LinkOCGStatePrivate *locgp = new LinkOCGStatePrivate( linkArea, plocg );
|
|
+ popplerLink = new LinkOCGState( locgp );
|
|
+ }
|
|
+
|
|
+ case actionUnknown:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return popplerLink;
|
|
+}
|
|
+
|
|
+inline TextPage *PageData::prepareTextSearch(const QString &text, Page::Rotation rotate, QVector<Unicode> *u)
|
|
+{
|
|
+ const QChar * str = text.unicode();
|
|
+ const int len = text.length();
|
|
+ u->resize(len);
|
|
+ for (int i = 0; i < len; ++i) (*u)[i] = str[i].unicode();
|
|
+
|
|
+ const int rotation = (int)rotate * 90;
|
|
+
|
|
+ // fetch ourselves a textpage
|
|
+ TextOutputDev td(NULL, true, 0, false, false);
|
|
+ parentDoc->doc->displayPage( &td, index + 1, 72, 72, rotation, false, true, false,
|
|
+ NULL, NULL, NULL, NULL, true);
|
|
+ TextPage *textPage=td.takeText();
|
|
+
|
|
+ return textPage;
|
|
+}
|
|
+
|
|
+inline bool PageData::performSingleTextSearch(TextPage* textPage, QVector<Unicode> &u, double &sLeft, double &sTop, double &sRight, double &sBottom, Page::SearchDirection direction, bool sCase, bool sWords)
|
|
+{
|
|
+ if (direction == Page::FromTop)
|
|
+ return textPage->findText( u.data(), u.size(),
|
|
+ true, true, false, false, sCase, false, sWords, &sLeft, &sTop, &sRight, &sBottom );
|
|
+ else if ( direction == Page::NextResult )
|
|
+ return textPage->findText( u.data(), u.size(),
|
|
+ false, true, true, false, sCase, false, sWords, &sLeft, &sTop, &sRight, &sBottom );
|
|
+ else if ( direction == Page::PreviousResult )
|
|
+ return textPage->findText( u.data(), u.size(),
|
|
+ false, true, true, false, sCase, true, sWords, &sLeft, &sTop, &sRight, &sBottom );
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+inline QList<QRectF> PageData::performMultipleTextSearch(TextPage* textPage, QVector<Unicode> &u, bool sCase, bool sWords)
|
|
+{
|
|
+ QList<QRectF> results;
|
|
+ double sLeft = 0.0, sTop = 0.0, sRight = 0.0, sBottom = 0.0;
|
|
+
|
|
+ while(textPage->findText( u.data(), u.size(),
|
|
+ false, true, true, false, sCase, false, sWords, &sLeft, &sTop, &sRight, &sBottom ))
|
|
+ {
|
|
+ QRectF result;
|
|
+
|
|
+ result.setLeft(sLeft);
|
|
+ result.setTop(sTop);
|
|
+ result.setRight(sRight);
|
|
+ result.setBottom(sBottom);
|
|
+
|
|
+ results.append(result);
|
|
+ }
|
|
+
|
|
+ return results;
|
|
+}
|
|
+
|
|
+Page::Page(DocumentData *doc, int index) {
|
|
+ m_page = new PageData();
|
|
+ m_page->index = index;
|
|
+ m_page->parentDoc = doc;
|
|
+ m_page->page = doc->doc->getPage(m_page->index + 1);
|
|
+ m_page->transition = 0;
|
|
+}
|
|
+
|
|
+Page::~Page()
|
|
+{
|
|
+ delete m_page->transition;
|
|
+ delete m_page;
|
|
+}
|
|
+
|
|
+QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h, Rotation rotate) const
|
|
+{
|
|
+ int rotation = (int)rotate * 90;
|
|
+ QImage img;
|
|
+ switch(m_page->parentDoc->m_backend)
|
|
+ {
|
|
+ case Poppler::Document::SplashBackend:
|
|
+ {
|
|
+#if defined(HAVE_SPLASH)
|
|
+ SplashColor bgColor;
|
|
+ bool overprintPreview = false;
|
|
+#ifdef SPLASH_CMYK
|
|
+ overprintPreview = m_page->parentDoc->m_hints & Document::OverprintPreview ? true : false;
|
|
+ if (overprintPreview)
|
|
+ {
|
|
+ Guchar c, m, y, k;
|
|
+
|
|
+ c = 255 - m_page->parentDoc->paperColor.blue();
|
|
+ m = 255 - m_page->parentDoc->paperColor.red();
|
|
+ y = 255 - m_page->parentDoc->paperColor.green();
|
|
+ k = c;
|
|
+ if (m < k) {
|
|
+ k = m;
|
|
+ }
|
|
+ if (y < k) {
|
|
+ k = y;
|
|
+ }
|
|
+ bgColor[0] = c - k;
|
|
+ bgColor[1] = m - k;
|
|
+ bgColor[2] = y - k;
|
|
+ bgColor[3] = k;
|
|
+ for (int i = 4; i < SPOT_NCOMPS + 4; i++) {
|
|
+ bgColor[i] = 0;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+#endif
|
|
+ {
|
|
+ bgColor[0] = m_page->parentDoc->paperColor.blue();
|
|
+ bgColor[1] = m_page->parentDoc->paperColor.green();
|
|
+ bgColor[2] = m_page->parentDoc->paperColor.red();
|
|
+ }
|
|
+
|
|
+ SplashColorMode colorMode = splashModeXBGR8;
|
|
+#ifdef SPLASH_CMYK
|
|
+ if (overprintPreview) colorMode = splashModeDeviceN8;
|
|
+#endif
|
|
+
|
|
+ SplashThinLineMode thinLineMode = splashThinLineDefault;
|
|
+ if (m_page->parentDoc->m_hints & Document::ThinLineShape) thinLineMode = splashThinLineShape;
|
|
+ if (m_page->parentDoc->m_hints & Document::ThinLineSolid) thinLineMode = splashThinLineSolid;
|
|
+
|
|
+ const bool ignorePaperColor = m_page->parentDoc->m_hints & Document::IgnorePaperColor;
|
|
+
|
|
+ SplashOutputDev splash_output(
|
|
+ colorMode, 4,
|
|
+ false,
|
|
+ ignorePaperColor ? NULL : bgColor,
|
|
+ true,
|
|
+ thinLineMode,
|
|
+ overprintPreview);
|
|
+
|
|
+ splash_output.setFontAntialias(m_page->parentDoc->m_hints & Document::TextAntialiasing ? true : false);
|
|
+ splash_output.setVectorAntialias(m_page->parentDoc->m_hints & Document::Antialiasing ? true : false);
|
|
+ splash_output.setFreeTypeHinting(m_page->parentDoc->m_hints & Document::TextHinting ? true : false,
|
|
+ m_page->parentDoc->m_hints & Document::TextSlightHinting ? true : false);
|
|
+
|
|
+ splash_output.startDoc(m_page->parentDoc->doc);
|
|
+
|
|
+ m_page->parentDoc->doc->displayPageSlice(&splash_output, m_page->index + 1, xres, yres,
|
|
+ rotation, false, true, false, x, y, w, h,
|
|
+ NULL, NULL, NULL, NULL, true);
|
|
+
|
|
+ SplashBitmap *bitmap = splash_output.getBitmap();
|
|
+
|
|
+ const int bw = bitmap->getWidth();
|
|
+ const int bh = bitmap->getHeight();
|
|
+ const int brs = bitmap->getRowSize();
|
|
+
|
|
+ // If we use DeviceN8, convert to XBGR8.
|
|
+ // If requested, also transfer Splash's internal alpha channel.
|
|
+ const SplashBitmap::ConversionMode mode = ignorePaperColor
|
|
+ ? SplashBitmap::conversionAlphaPremultiplied
|
|
+ : SplashBitmap::conversionOpaque;
|
|
+
|
|
+ const QImage::Format format = ignorePaperColor
|
|
+ ? QImage::Format_ARGB32_Premultiplied
|
|
+ : QImage::Format_RGB32;
|
|
+
|
|
+ if (bitmap->convertToXBGR(mode)) {
|
|
+ SplashColorPtr data = bitmap->getDataPtr();
|
|
+
|
|
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
|
|
+ // Convert byte order from RGBX to XBGR.
|
|
+ for (int i = 0; i < bh; ++i) {
|
|
+ for (int j = 0; j < bw; ++j) {
|
|
+ SplashColorPtr pixel = &data[i * brs + j];
|
|
+
|
|
+ qSwap(pixel[0], pixel[3]);
|
|
+ qSwap(pixel[1], pixel[2]);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Construct a Qt image sharing the raw bitmap data.
|
|
+ img = QImage(data, bw, bh, brs, format).copy();
|
|
+ }
|
|
+#endif
|
|
+ break;
|
|
+ }
|
|
+ case Poppler::Document::ArthurBackend:
|
|
+ {
|
|
+ QSize size = pageSize();
|
|
+ QImage tmpimg(w == -1 ? qRound( size.width() * xres / 72.0 ) : w, h == -1 ? qRound( size.height() * yres / 72.0 ) : h, QImage::Format_ARGB32);
|
|
+
|
|
+ QPainter painter(&tmpimg);
|
|
+ renderToPainter(&painter, xres, yres, x, y, w, h, rotate, DontSaveAndRestore);
|
|
+ painter.end();
|
|
+ img = tmpimg;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return img;
|
|
+}
|
|
+
|
|
+bool Page::renderToPainter(QPainter* painter, double xres, double yres, int x, int y, int w, int h, Rotation rotate, PainterFlags flags) const
|
|
+{
|
|
+ if (!painter)
|
|
+ return false;
|
|
+
|
|
+ switch(m_page->parentDoc->m_backend)
|
|
+ {
|
|
+ case Poppler::Document::SplashBackend:
|
|
+ return false;
|
|
+ case Poppler::Document::ArthurBackend:
|
|
+ {
|
|
+ const bool savePainter = !(flags & DontSaveAndRestore);
|
|
+ if (savePainter)
|
|
+ painter->save();
|
|
+ if (m_page->parentDoc->m_hints & Document::Antialiasing)
|
|
+ painter->setRenderHint(QPainter::Antialiasing);
|
|
+ if (m_page->parentDoc->m_hints & Document::TextAntialiasing)
|
|
+ painter->setRenderHint(QPainter::TextAntialiasing);
|
|
+ painter->translate(x == -1 ? 0 : -x, y == -1 ? 0 : -y);
|
|
+ ArthurOutputDev arthur_output(painter);
|
|
+ arthur_output.startDoc(m_page->parentDoc->doc->getXRef());
|
|
+ m_page->parentDoc->doc->displayPageSlice(&arthur_output,
|
|
+ m_page->index + 1,
|
|
+ xres,
|
|
+ yres,
|
|
+ (int)rotate * 90,
|
|
+ false,
|
|
+ true,
|
|
+ false,
|
|
+ x,
|
|
+ y,
|
|
+ w,
|
|
+ h);
|
|
+ if (savePainter)
|
|
+ painter->restore();
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+QImage Page::thumbnail() const
|
|
+{
|
|
+ unsigned char* data = 0;
|
|
+ int w = 0;
|
|
+ int h = 0;
|
|
+ int rowstride = 0;
|
|
+ bool r = m_page->page->loadThumb(&data, &w, &h, &rowstride);
|
|
+ QImage ret;
|
|
+ if (r)
|
|
+ {
|
|
+ // first construct a temporary image with the data got,
|
|
+ // then force a copy of it so we can free the raw thumbnail data
|
|
+ ret = QImage(data, w, h, rowstride, QImage::Format_RGB888).copy();
|
|
+ gfree(data);
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+QString Page::text(const QRectF &r, TextLayout textLayout) const
|
|
+{
|
|
+ TextOutputDev *output_dev;
|
|
+ GooString *s;
|
|
+ const PDFRectangle *rect;
|
|
+ QString result;
|
|
+
|
|
+ const bool rawOrder = textLayout == RawOrderLayout;
|
|
+ output_dev = new TextOutputDev(0, false, 0, rawOrder, false);
|
|
+ m_page->parentDoc->doc->displayPageSlice(output_dev, m_page->index + 1, 72, 72,
|
|
+ 0, false, true, false, -1, -1, -1, -1,
|
|
+ NULL, NULL, NULL, NULL, true);
|
|
+ if (r.isNull())
|
|
+ {
|
|
+ rect = m_page->page->getCropBox();
|
|
+ s = output_dev->getText(rect->x1, rect->y1, rect->x2, rect->y2);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ s = output_dev->getText(r.left(), r.top(), r.right(), r.bottom());
|
|
+ }
|
|
+
|
|
+ result = QString::fromUtf8(s->c_str());
|
|
+
|
|
+ delete output_dev;
|
|
+ delete s;
|
|
+ return result;
|
|
+}
|
|
+
|
|
+QString Page::text(const QRectF &r) const
|
|
+{
|
|
+ return text(r, PhysicalLayout);
|
|
+}
|
|
+
|
|
+bool Page::search(const QString &text, double &sLeft, double &sTop, double &sRight, double &sBottom, SearchDirection direction, SearchMode caseSensitive, Rotation rotate) const
|
|
+{
|
|
+ const bool sCase = caseSensitive == Page::CaseSensitive ? true : false;
|
|
+
|
|
+ QVector<Unicode> u;
|
|
+ TextPage *textPage = m_page->prepareTextSearch(text, rotate, &u);
|
|
+
|
|
+ const bool found = m_page->performSingleTextSearch(textPage, u, sLeft, sTop, sRight, sBottom, direction, sCase, false);
|
|
+
|
|
+ textPage->decRefCnt();
|
|
+
|
|
+ return found;
|
|
+}
|
|
+
|
|
+bool Page::search(const QString &text, double &sLeft, double &sTop, double &sRight, double &sBottom, SearchDirection direction, SearchFlags flags, Rotation rotate) const
|
|
+{
|
|
+ const bool sCase = flags.testFlag(IgnoreCase) ? false : true;
|
|
+ const bool sWords = flags.testFlag(WholeWords) ? true : false;
|
|
+
|
|
+ QVector<Unicode> u;
|
|
+ TextPage *textPage = m_page->prepareTextSearch(text, rotate, &u);
|
|
+
|
|
+ const bool found = m_page->performSingleTextSearch(textPage, u, sLeft, sTop, sRight, sBottom, direction, sCase, sWords);
|
|
+
|
|
+ textPage->decRefCnt();
|
|
+
|
|
+ return found;
|
|
+}
|
|
+
|
|
+bool Page::search(const QString &text, QRectF &rect, SearchDirection direction, SearchMode caseSensitive, Rotation rotate) const
|
|
+{
|
|
+ double sLeft, sTop, sRight, sBottom;
|
|
+ sLeft = rect.left();
|
|
+ sTop = rect.top();
|
|
+ sRight = rect.right();
|
|
+ sBottom = rect.bottom();
|
|
+
|
|
+ bool found = search(text, sLeft, sTop, sRight, sBottom, direction, caseSensitive, rotate);
|
|
+
|
|
+ rect.setLeft( sLeft );
|
|
+ rect.setTop( sTop );
|
|
+ rect.setRight( sRight );
|
|
+ rect.setBottom( sBottom );
|
|
+
|
|
+ return found;
|
|
+}
|
|
+
|
|
+QList<QRectF> Page::search(const QString &text, SearchMode caseSensitive, Rotation rotate) const
|
|
+{
|
|
+ const bool sCase = caseSensitive == Page::CaseSensitive ? true : false;
|
|
+
|
|
+ QVector<Unicode> u;
|
|
+ TextPage *textPage = m_page->prepareTextSearch(text, rotate, &u);
|
|
+
|
|
+ const QList<QRectF> results = m_page->performMultipleTextSearch(textPage, u, sCase, false);
|
|
+
|
|
+ textPage->decRefCnt();
|
|
+
|
|
+ return results;
|
|
+}
|
|
+
|
|
+QList<QRectF> Page::search(const QString &text, SearchFlags flags, Rotation rotate) const
|
|
+{
|
|
+ const bool sCase = flags.testFlag(IgnoreCase) ? false : true;
|
|
+ const bool sWords = flags.testFlag(WholeWords) ? true : false;
|
|
+
|
|
+ QVector<Unicode> u;
|
|
+ TextPage *textPage = m_page->prepareTextSearch(text, rotate, &u);
|
|
+
|
|
+ const QList<QRectF> results = m_page->performMultipleTextSearch(textPage, u, sCase, sWords);
|
|
+
|
|
+ textPage->decRefCnt();
|
|
+
|
|
+ return results;
|
|
+}
|
|
+
|
|
+QList<TextBox*> Page::textList(Rotation rotate) const
|
|
+{
|
|
+ TextOutputDev *output_dev;
|
|
+
|
|
+ QList<TextBox*> output_list;
|
|
+
|
|
+ output_dev = new TextOutputDev(0, false, 0, false, false);
|
|
+
|
|
+ int rotation = (int)rotate * 90;
|
|
+
|
|
+ m_page->parentDoc->doc->displayPageSlice(output_dev, m_page->index + 1, 72, 72,
|
|
+ rotation, false, false, false, -1, -1, -1, -1,
|
|
+ NULL, NULL, NULL, NULL, true);
|
|
+
|
|
+ TextWordList *word_list = output_dev->makeWordList();
|
|
+
|
|
+ if (!word_list) {
|
|
+ delete output_dev;
|
|
+ return output_list;
|
|
+ }
|
|
+
|
|
+ QHash<const TextWord *, TextBox*> wordBoxMap;
|
|
+
|
|
+ output_list.reserve(word_list->getLength());
|
|
+ for (int i = 0; i < word_list->getLength(); i++) {
|
|
+ TextWord *word = word_list->get(i);
|
|
+ GooString *gooWord = word->getText();
|
|
+ QString string = QString::fromUtf8(gooWord->c_str());
|
|
+ delete gooWord;
|
|
+ double xMin, yMin, xMax, yMax;
|
|
+ word->getBBox(&xMin, &yMin, &xMax, &yMax);
|
|
+
|
|
+ TextBox* text_box = new TextBox(string, QRectF(xMin, yMin, xMax-xMin, yMax-yMin));
|
|
+ text_box->m_data->hasSpaceAfter = word->hasSpaceAfter() == true;
|
|
+ text_box->m_data->charBBoxes.reserve(word->getLength());
|
|
+ for (int j = 0; j < word->getLength(); ++j)
|
|
+ {
|
|
+ word->getCharBBox(j, &xMin, &yMin, &xMax, &yMax);
|
|
+ text_box->m_data->charBBoxes.append(QRectF(xMin, yMin, xMax-xMin, yMax-yMin));
|
|
+ }
|
|
+
|
|
+ wordBoxMap.insert(word, text_box);
|
|
+
|
|
+ output_list.append(text_box);
|
|
+ }
|
|
+
|
|
+ for (int i = 0; i < word_list->getLength(); i++) {
|
|
+ TextWord *word = word_list->get(i);
|
|
+ TextBox* text_box = wordBoxMap.value(word);
|
|
+ text_box->m_data->nextWord = wordBoxMap.value(word->nextWord());
|
|
+ }
|
|
+
|
|
+ delete word_list;
|
|
+ delete output_dev;
|
|
+
|
|
+ return output_list;
|
|
+}
|
|
+
|
|
+PageTransition *Page::transition() const
|
|
+{
|
|
+ if (!m_page->transition) {
|
|
+ PageTransitionParams params;
|
|
+ Object o = m_page->page->getTrans();
|
|
+ params.dictObj = &o;
|
|
+ if (o.isDict()) m_page->transition = new PageTransition(params);
|
|
+ }
|
|
+ return m_page->transition;
|
|
+}
|
|
+
|
|
+Link *Page::action( PageAction act ) const
|
|
+{
|
|
+ if ( act == Page::Opening || act == Page::Closing )
|
|
+ {
|
|
+ Object o = m_page->page->getActions();
|
|
+ if (!o.isDict())
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
+ Dict *dict = o.getDict();
|
|
+ const char *key = act == Page::Opening ? "O" : "C";
|
|
+ Object o2 = dict->lookup((char*)key);
|
|
+ ::LinkAction *lact = ::LinkAction::parseAction(&o2, m_page->parentDoc->doc->getCatalog()->getBaseURI() );
|
|
+ Link *popplerLink = NULL;
|
|
+ if (lact != NULL)
|
|
+ {
|
|
+ popplerLink = m_page->convertLinkActionToLink(lact, QRectF());
|
|
+ delete lact;
|
|
+ }
|
|
+ return popplerLink;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+QSizeF Page::pageSizeF() const
|
|
+{
|
|
+ Page::Orientation orient = orientation();
|
|
+ if ( ( Page::Landscape == orient ) || (Page::Seascape == orient ) ) {
|
|
+ return QSizeF( m_page->page->getCropHeight(), m_page->page->getCropWidth() );
|
|
+ } else {
|
|
+ return QSizeF( m_page->page->getCropWidth(), m_page->page->getCropHeight() );
|
|
+ }
|
|
+}
|
|
+
|
|
+QSize Page::pageSize() const
|
|
+{
|
|
+ return pageSizeF().toSize();
|
|
+}
|
|
+
|
|
+Page::Orientation Page::orientation() const
|
|
+{
|
|
+ const int rotation = m_page->page->getRotate();
|
|
+ switch (rotation) {
|
|
+ case 90:
|
|
+ return Page::Landscape;
|
|
+ break;
|
|
+ case 180:
|
|
+ return Page::UpsideDown;
|
|
+ break;
|
|
+ case 270:
|
|
+ return Page::Seascape;
|
|
+ break;
|
|
+ default:
|
|
+ return Page::Portrait;
|
|
+ }
|
|
+}
|
|
+
|
|
+void Page::defaultCTM(double *CTM, double dpiX, double dpiY, int rotate, bool upsideDown)
|
|
+{
|
|
+ m_page->page->getDefaultCTM(CTM, dpiX, dpiY, rotate, false, upsideDown);
|
|
+}
|
|
+
|
|
+QList<Link*> Page::links() const
|
|
+{
|
|
+ LinkExtractorOutputDev link_dev(m_page);
|
|
+ m_page->parentDoc->doc->processLinks(&link_dev, m_page->index + 1);
|
|
+ QList<Link*> popplerLinks = link_dev.links();
|
|
+
|
|
+ return popplerLinks;
|
|
+}
|
|
+
|
|
+QList<Annotation*> Page::annotations() const
|
|
+{
|
|
+ return AnnotationPrivate::findAnnotations(m_page->page, m_page->parentDoc, QSet<Annotation::SubType>());
|
|
+}
|
|
+
|
|
+QList<Annotation*> Page::annotations(const QSet<Annotation::SubType> &subtypes) const
|
|
+{
|
|
+ return AnnotationPrivate::findAnnotations(m_page->page, m_page->parentDoc, subtypes);
|
|
+}
|
|
+
|
|
+void Page::addAnnotation( const Annotation *ann )
|
|
+{
|
|
+ AnnotationPrivate::addAnnotationToPage(m_page->page, m_page->parentDoc, ann);
|
|
+}
|
|
+
|
|
+void Page::removeAnnotation( const Annotation *ann )
|
|
+{
|
|
+ AnnotationPrivate::removeAnnotationFromPage(m_page->page, ann);
|
|
+}
|
|
+
|
|
+QList<FormField*> Page::formFields() const
|
|
+{
|
|
+ QList<FormField*> fields;
|
|
+ ::Page *p = m_page->page;
|
|
+ ::FormPageWidgets * form = p->getFormWidgets();
|
|
+ int formcount = form->getNumWidgets();
|
|
+ for (int i = 0; i < formcount; ++i)
|
|
+ {
|
|
+ ::FormWidget *fm = form->getWidget(i);
|
|
+ FormField * ff = NULL;
|
|
+ switch (fm->getType())
|
|
+ {
|
|
+ case formButton:
|
|
+ {
|
|
+ ff = new FormFieldButton(m_page->parentDoc, p, static_cast<FormWidgetButton*>(fm));
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case formText:
|
|
+ {
|
|
+ ff = new FormFieldText(m_page->parentDoc, p, static_cast<FormWidgetText*>(fm));
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case formChoice:
|
|
+ {
|
|
+ ff = new FormFieldChoice(m_page->parentDoc, p, static_cast<FormWidgetChoice*>(fm));
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ default: ;
|
|
+ }
|
|
+
|
|
+ if (ff)
|
|
+ fields.append(ff);
|
|
+ }
|
|
+
|
|
+ delete form;
|
|
+
|
|
+ return fields;
|
|
+}
|
|
+
|
|
+double Page::duration() const
|
|
+{
|
|
+ return m_page->page->getDuration();
|
|
+}
|
|
+
|
|
+QString Page::label() const
|
|
+{
|
|
+ GooString goo;
|
|
+ if (!m_page->parentDoc->doc->getCatalog()->indexToLabel(m_page->index, &goo))
|
|
+ return QString();
|
|
+
|
|
+ return UnicodeParsedString(&goo);
|
|
+}
|
|
+
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-pdf-converter.cc b/qt4/src/poppler-pdf-converter.cc
|
|
new file mode 100644
|
|
index 00000000..9699b75b
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-pdf-converter.cc
|
|
@@ -0,0 +1,115 @@
|
|
+/* poppler-pdf-converter.cc: qt4 interface to poppler
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2008, 2009, Albert Astals Cid <aacid@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-qt4.h"
|
|
+
|
|
+#include "poppler-private.h"
|
|
+#include "poppler-converter-private.h"
|
|
+#include "poppler-qiodeviceoutstream-private.h"
|
|
+
|
|
+#include <QtCore/QFile>
|
|
+
|
|
+#include <ErrorCodes.h>
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+class PDFConverterPrivate : public BaseConverterPrivate
|
|
+{
|
|
+ public:
|
|
+ PDFConverterPrivate();
|
|
+
|
|
+ PDFConverter::PDFOptions opts;
|
|
+};
|
|
+
|
|
+PDFConverterPrivate::PDFConverterPrivate()
|
|
+ : BaseConverterPrivate(), opts(0)
|
|
+{
|
|
+}
|
|
+
|
|
+
|
|
+PDFConverter::PDFConverter(DocumentData *document)
|
|
+ : BaseConverter(*new PDFConverterPrivate())
|
|
+{
|
|
+ Q_D(PDFConverter);
|
|
+ d->document = document;
|
|
+}
|
|
+
|
|
+PDFConverter::~PDFConverter()
|
|
+{
|
|
+}
|
|
+
|
|
+void PDFConverter::setPDFOptions(PDFConverter::PDFOptions options)
|
|
+{
|
|
+ Q_D(PDFConverter);
|
|
+ d->opts = options;
|
|
+}
|
|
+
|
|
+PDFConverter::PDFOptions PDFConverter::pdfOptions() const
|
|
+{
|
|
+ Q_D(const PDFConverter);
|
|
+ return d->opts;
|
|
+}
|
|
+
|
|
+bool PDFConverter::convert()
|
|
+{
|
|
+ Q_D(PDFConverter);
|
|
+ d->lastError = NoError;
|
|
+
|
|
+ if (d->document->locked)
|
|
+ {
|
|
+ d->lastError = FileLockedError;
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ QIODevice *dev = d->openDevice();
|
|
+ if (!dev)
|
|
+ {
|
|
+ d->lastError = OpenOutputError;
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ bool deleteFile = false;
|
|
+ if (QFile *file = qobject_cast<QFile*>(dev))
|
|
+ deleteFile = !file->exists();
|
|
+
|
|
+ int errorCode = errNone;
|
|
+ QIODeviceOutStream stream(dev);
|
|
+ if (d->opts & WithChanges)
|
|
+ {
|
|
+ errorCode = d->document->doc->saveAs(&stream);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ errorCode = d->document->doc->saveWithoutChangesAs(&stream);
|
|
+ }
|
|
+ d->closeDevice();
|
|
+ if (errorCode != errNone)
|
|
+ {
|
|
+ if (deleteFile)
|
|
+ {
|
|
+ qobject_cast<QFile*>(dev)->remove();
|
|
+ }
|
|
+ if (errorCode == errOpenFile) d->lastError = OpenOutputError;
|
|
+ else d->lastError = NotSupportedInputFileError;
|
|
+ }
|
|
+
|
|
+ return (errorCode == errNone);
|
|
+}
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-private.cc b/qt4/src/poppler-private.cc
|
|
new file mode 100644
|
|
index 00000000..1338a185
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-private.cc
|
|
@@ -0,0 +1,296 @@
|
|
+/* poppler-private.cc: qt interface to poppler
|
|
+ * Copyright (C) 2005, Net Integration Technologies, Inc.
|
|
+ * Copyright (C) 2006, 2011, 2015, 2017 by Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2008, 2010, 2011 by Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2013 by Thomas Freitag <Thomas.Freitag@alfa.de>
|
|
+ * Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
|
|
+ * Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com>
|
|
+ * Inspired on code by
|
|
+ * Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es>
|
|
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-private.h"
|
|
+
|
|
+#include <QtCore/QByteArray>
|
|
+#include <QtCore/QDebug>
|
|
+#include <QtCore/QVariant>
|
|
+
|
|
+#include <Link.h>
|
|
+#include <Outline.h>
|
|
+#include <PDFDocEncoding.h>
|
|
+#include <UnicodeMap.h>
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+namespace Debug {
|
|
+
|
|
+ static void qDebugDebugFunction(const QString &message, const QVariant & /*closure*/)
|
|
+ {
|
|
+ qDebug() << message;
|
|
+ }
|
|
+
|
|
+ PopplerDebugFunc debugFunction = qDebugDebugFunction;
|
|
+ QVariant debugClosure;
|
|
+
|
|
+}
|
|
+
|
|
+ static UnicodeMap *utf8Map = 0;
|
|
+
|
|
+ void setDebugErrorFunction(PopplerDebugFunc function, const QVariant &closure)
|
|
+ {
|
|
+ Debug::debugFunction = function ? function : Debug::qDebugDebugFunction;
|
|
+ Debug::debugClosure = closure;
|
|
+ }
|
|
+
|
|
+ static void qt4ErrorFunction(void * /*data*/, ErrorCategory /*category*/, Goffset pos, const char *msg)
|
|
+ {
|
|
+ QString emsg;
|
|
+
|
|
+ if (pos >= 0)
|
|
+ {
|
|
+ emsg = QString::fromLatin1("Error (%1): ").arg(pos);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ emsg = QString::fromLatin1("Error: ");
|
|
+ }
|
|
+ emsg += QString::fromAscii(msg);
|
|
+ (*Debug::debugFunction)(emsg, Debug::debugClosure);
|
|
+ }
|
|
+
|
|
+ QString unicodeToQString(const Unicode* u, int len) {
|
|
+ if (!utf8Map)
|
|
+ {
|
|
+ GooString enc("UTF-8");
|
|
+ utf8Map = globalParams->getUnicodeMap(&enc);
|
|
+ utf8Map->incRefCnt();
|
|
+ }
|
|
+
|
|
+ // ignore the last character if it is 0x0
|
|
+ if ((len > 0) && (u[len - 1] == 0))
|
|
+ {
|
|
+ --len;
|
|
+ }
|
|
+
|
|
+ GooString convertedStr;
|
|
+ for (int i = 0; i < len; ++i)
|
|
+ {
|
|
+ char buf[8];
|
|
+ const int n = utf8Map->mapUnicode(u[i], buf, sizeof(buf));
|
|
+ convertedStr.append(buf, n);
|
|
+ }
|
|
+
|
|
+ return QString::fromUtf8(convertedStr.c_str(), convertedStr.getLength());
|
|
+ }
|
|
+
|
|
+ QString UnicodeParsedString(const GooString *s1) {
|
|
+ if ( !s1 || s1->getLength() == 0 )
|
|
+ return QString();
|
|
+
|
|
+ const char *cString;
|
|
+ int stringLength;
|
|
+ bool deleteCString;
|
|
+ if ( ( s1->getChar(0) & 0xff ) == 0xfe && ( s1->getLength() > 1 && ( s1->getChar(1) & 0xff ) == 0xff ) )
|
|
+ {
|
|
+ cString = s1->c_str();
|
|
+ stringLength = s1->getLength();
|
|
+ deleteCString = false;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ cString = pdfDocEncodingToUTF16(s1, &stringLength);
|
|
+ deleteCString = true;
|
|
+ }
|
|
+
|
|
+ QString result;
|
|
+ // i = 2 to skip the unicode marker
|
|
+ for ( int i = 2; i < stringLength; i += 2 )
|
|
+ {
|
|
+ const Unicode u = ( ( cString[i] & 0xff ) << 8 ) | ( cString[i+1] & 0xff );
|
|
+ result += QChar( u );
|
|
+ }
|
|
+ if (deleteCString)
|
|
+ delete[] cString;
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ GooString *QStringToUnicodeGooString(const QString &s) {
|
|
+ int len = s.length() * 2 + 2;
|
|
+ char *cstring = (char *)gmallocn(len, sizeof(char));
|
|
+ cstring[0] = (char)0xfe;
|
|
+ cstring[1] = (char)0xff;
|
|
+ for (int i = 0; i < s.length(); ++i)
|
|
+ {
|
|
+ cstring[2+i*2] = s.at(i).row();
|
|
+ cstring[3+i*2] = s.at(i).cell();
|
|
+ }
|
|
+ GooString *ret = new GooString(cstring, len);
|
|
+ gfree(cstring);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ GooString *QStringToGooString(const QString &s) {
|
|
+ int len = s.length();
|
|
+ char *cstring = (char *)gmallocn(s.length(), sizeof(char));
|
|
+ for (int i = 0; i < len; ++i)
|
|
+ cstring[i] = s.at(i).unicode();
|
|
+ GooString *ret = new GooString(cstring, len);
|
|
+ gfree(cstring);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ GooString *QDateTimeToUnicodeGooString(const QDateTime &dt) {
|
|
+ if (!dt.isValid()) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return QStringToUnicodeGooString(dt.toUTC().toString("yyyyMMddhhmmss+00'00'"));
|
|
+ }
|
|
+
|
|
+ static void linkActionToTocItem( const ::LinkAction * a, DocumentData * doc, QDomElement * e )
|
|
+ {
|
|
+ if ( !a || !e )
|
|
+ return;
|
|
+
|
|
+ switch ( a->getKind() )
|
|
+ {
|
|
+ case actionGoTo:
|
|
+ {
|
|
+ // page number is contained/referenced in a LinkGoTo
|
|
+ const LinkGoTo * g = static_cast< const LinkGoTo * >( a );
|
|
+ const LinkDest * destination = g->getDest();
|
|
+ if ( !destination && g->getNamedDest() )
|
|
+ {
|
|
+ // no 'destination' but an internal 'named reference'. we could
|
|
+ // get the destination for the page now, but it's VERY time consuming,
|
|
+ // so better storing the reference and provide the viewport on demand
|
|
+ const GooString *s = g->getNamedDest();
|
|
+ QChar *charArray = new QChar[s->getLength()];
|
|
+ for (int i = 0; i < s->getLength(); ++i) charArray[i] = QChar(s->c_str()[i]);
|
|
+ QString aux(charArray, s->getLength());
|
|
+ e->setAttribute( "DestinationName", aux );
|
|
+ delete[] charArray;
|
|
+ }
|
|
+ else if ( destination && destination->isOk() )
|
|
+ {
|
|
+ LinkDestinationData ldd(destination, NULL, doc, false);
|
|
+ e->setAttribute( "Destination", LinkDestination(ldd).toString() );
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ case actionGoToR:
|
|
+ {
|
|
+ // page number is contained/referenced in a LinkGoToR
|
|
+ const LinkGoToR * g = static_cast< const LinkGoToR * >( a );
|
|
+ const LinkDest * destination = g->getDest();
|
|
+ if ( !destination && g->getNamedDest() )
|
|
+ {
|
|
+ // no 'destination' but an internal 'named reference'. we could
|
|
+ // get the destination for the page now, but it's VERY time consuming,
|
|
+ // so better storing the reference and provide the viewport on demand
|
|
+ const GooString *s = g->getNamedDest();
|
|
+ QChar *charArray = new QChar[s->getLength()];
|
|
+ for (int i = 0; i < s->getLength(); ++i) charArray[i] = QChar(s->c_str()[i]);
|
|
+ QString aux(charArray, s->getLength());
|
|
+ e->setAttribute( "DestinationName", aux );
|
|
+ delete[] charArray;
|
|
+ }
|
|
+ else if ( destination && destination->isOk() )
|
|
+ {
|
|
+ LinkDestinationData ldd(destination, NULL, doc, g->getFileName() != 0);
|
|
+ e->setAttribute( "Destination", LinkDestination(ldd).toString() );
|
|
+ }
|
|
+ e->setAttribute( "ExternalFileName", g->getFileName()->c_str() );
|
|
+ break;
|
|
+ }
|
|
+ case actionURI:
|
|
+ {
|
|
+ const LinkURI * u = static_cast< const LinkURI * >( a );
|
|
+ e->setAttribute( "DestinationURI", u->getURI()->c_str() );
|
|
+ }
|
|
+ default: ;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ DocumentData::~DocumentData()
|
|
+ {
|
|
+ qDeleteAll(m_embeddedFiles);
|
|
+ delete (OptContentModel *)m_optContentModel;
|
|
+ delete doc;
|
|
+ delete m_fontInfoIterator;
|
|
+
|
|
+ count --;
|
|
+ if ( count == 0 )
|
|
+ {
|
|
+ utf8Map = nullptr;
|
|
+ globalParams.reset();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ void DocumentData::init()
|
|
+ {
|
|
+ m_fontInfoIterator = 0;
|
|
+ m_backend = Document::SplashBackend;
|
|
+ paperColor = Qt::white;
|
|
+ m_hints = 0;
|
|
+ m_optContentModel = 0;
|
|
+
|
|
+ if ( count == 0 )
|
|
+ {
|
|
+ utf8Map = nullptr;
|
|
+ globalParams = std::make_unique<GlobalParams>();
|
|
+ setErrorCallback(qt4ErrorFunction, nullptr);
|
|
+ }
|
|
+ count ++;
|
|
+ }
|
|
+
|
|
+
|
|
+ void DocumentData::addTocChildren( QDomDocument * docSyn, QDomNode * parent, const std::vector<::OutlineItem*> * items )
|
|
+ {
|
|
+
|
|
+ for ( ::OutlineItem * outlineItem : *items )
|
|
+ {
|
|
+ // iterate over every object in 'items'
|
|
+
|
|
+
|
|
+ // 1. create element using outlineItem's title as tagName
|
|
+ QString name;
|
|
+ const Unicode * uniChar = outlineItem->getTitle();
|
|
+ int titleLength = outlineItem->getTitleLength();
|
|
+ name = unicodeToQString(uniChar, titleLength);
|
|
+ if ( name.isEmpty() )
|
|
+ continue;
|
|
+
|
|
+ QDomElement item = docSyn->createElement( name );
|
|
+ parent->appendChild( item );
|
|
+
|
|
+ // 2. find the page the link refers to
|
|
+ const ::LinkAction * a = outlineItem->getAction();
|
|
+ linkActionToTocItem( a, this, &item );
|
|
+
|
|
+ item.setAttribute( "Open", QVariant( (bool)outlineItem->isOpen() ).toString() );
|
|
+
|
|
+ // 3. recursively descend over children
|
|
+ outlineItem->open();
|
|
+ const std::vector<::OutlineItem*> * children = outlineItem->getKids();
|
|
+ if ( children )
|
|
+ addTocChildren( docSyn, &item, children );
|
|
+ }
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-private.h b/qt4/src/poppler-private.h
|
|
new file mode 100644
|
|
index 00000000..a5ad3f3e
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-private.h
|
|
@@ -0,0 +1,242 @@
|
|
+/* poppler-private.h: qt interface to poppler
|
|
+ * Copyright (C) 2005, Net Integration Technologies, Inc.
|
|
+ * Copyright (C) 2005, 2008, Brad Hards <bradh@frogmouth.net>
|
|
+ * Copyright (C) 2006-2009, 2011, 2012, 2017 by Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2007-2009, 2011 by Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
|
|
+ * Copyright (C) 2011 Hib Eris <hib@hiberis.nl>
|
|
+ * Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
|
|
+ * Copyright (C) 2013 Julien Nabet <serval2412@yahoo.fr>
|
|
+ * Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com>
|
|
+ * Inspired on code by
|
|
+ * Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es>
|
|
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef _POPPLER_PRIVATE_H_
|
|
+#define _POPPLER_PRIVATE_H_
|
|
+
|
|
+#include <QtCore/QFile>
|
|
+#include <QtCore/QPointer>
|
|
+#include <QtCore/QVector>
|
|
+
|
|
+#include <config.h>
|
|
+#include <GfxState.h>
|
|
+#include <GlobalParams.h>
|
|
+#include <PDFDoc.h>
|
|
+#include <FontInfo.h>
|
|
+#include <OutputDev.h>
|
|
+#include <Error.h>
|
|
+#include <Outline.h>
|
|
+#if defined(HAVE_SPLASH)
|
|
+#include <SplashOutputDev.h>
|
|
+#endif
|
|
+
|
|
+#include "poppler-qt4.h"
|
|
+#include "poppler-embeddedfile-private.h"
|
|
+
|
|
+class LinkDest;
|
|
+class FormWidget;
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+ /* borrowed from kpdf */
|
|
+ QString unicodeToQString(Unicode* u, int len);
|
|
+
|
|
+ QString UnicodeParsedString(GooString *s1);
|
|
+
|
|
+ GooString *QStringToUnicodeGooString(const QString &s);
|
|
+
|
|
+ GooString *QStringToGooString(const QString &s);
|
|
+
|
|
+ GooString *QDateTimeToUnicodeGooString(const QDateTime &dt);
|
|
+
|
|
+ void qt4ErrorFunction(int pos, char *msg, va_list args);
|
|
+
|
|
+ class LinkDestinationData
|
|
+ {
|
|
+ public:
|
|
+ LinkDestinationData( LinkDest *l, GooString *nd, Poppler::DocumentData *pdfdoc, bool external )
|
|
+ : ld(l), namedDest(nd), doc(pdfdoc), externalDest(external)
|
|
+ {
|
|
+ }
|
|
+
|
|
+ LinkDest *ld;
|
|
+ GooString *namedDest;
|
|
+ Poppler::DocumentData *doc;
|
|
+ bool externalDest;
|
|
+ };
|
|
+
|
|
+ class DocumentData {
|
|
+ public:
|
|
+ DocumentData(const QString &filePath, GooString *ownerPassword, GooString *userPassword)
|
|
+ {
|
|
+ init();
|
|
+ m_filePath = filePath;
|
|
+
|
|
+#if defined(_WIN32)
|
|
+ wchar_t *fileName = new WCHAR[filePath.length()];
|
|
+ int length = filePath.toWCharArray(fileName);
|
|
+ doc = new PDFDoc(fileName, length, ownerPassword, userPassword);
|
|
+ delete[] fileName;
|
|
+#else
|
|
+ GooString *fileName = new GooString(QFile::encodeName(filePath));
|
|
+ doc = new PDFDoc(fileName, ownerPassword, userPassword);
|
|
+#endif
|
|
+
|
|
+ delete ownerPassword;
|
|
+ delete userPassword;
|
|
+ }
|
|
+
|
|
+ DocumentData(const QByteArray &data, GooString *ownerPassword, GooString *userPassword)
|
|
+ {
|
|
+ fileContents = data;
|
|
+ MemStream *str = new MemStream((char*)fileContents.data(), 0, fileContents.length(), Object(objNull));
|
|
+ init();
|
|
+ doc = new PDFDoc(str, ownerPassword, userPassword);
|
|
+ delete ownerPassword;
|
|
+ delete userPassword;
|
|
+ }
|
|
+
|
|
+ void init();
|
|
+
|
|
+ ~DocumentData();
|
|
+
|
|
+ void addTocChildren( QDomDocument * docSyn, QDomNode * parent, const std::vector<OutlineItem*> * items );
|
|
+
|
|
+ void setPaperColor(const QColor &color)
|
|
+ {
|
|
+ paperColor = color;
|
|
+ }
|
|
+
|
|
+ void fillMembers()
|
|
+ {
|
|
+ m_fontInfoIterator = new FontIterator(0, this);
|
|
+ int numEmb = doc->getCatalog()->numEmbeddedFiles();
|
|
+ if (!(0 == numEmb)) {
|
|
+ // we have some embedded documents, build the list
|
|
+ for (int yalv = 0; yalv < numEmb; ++yalv) {
|
|
+ FileSpec *fs = doc->getCatalog()->embeddedFile(yalv);
|
|
+ m_embeddedFiles.append(new EmbeddedFile(*new EmbeddedFileData(fs)));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ static Document *checkDocument(DocumentData *doc);
|
|
+
|
|
+ PDFDoc *doc;
|
|
+ QString m_filePath;
|
|
+ QByteArray fileContents;
|
|
+ bool locked;
|
|
+ FontIterator *m_fontInfoIterator;
|
|
+ Document::RenderBackend m_backend;
|
|
+ QList<EmbeddedFile*> m_embeddedFiles;
|
|
+ QPointer<OptContentModel> m_optContentModel;
|
|
+ QColor paperColor;
|
|
+ int m_hints;
|
|
+ static int count;
|
|
+ };
|
|
+
|
|
+ class FontInfoData
|
|
+ {
|
|
+ public:
|
|
+ FontInfoData()
|
|
+ {
|
|
+ isEmbedded = false;
|
|
+ isSubset = false;
|
|
+ type = FontInfo::unknown;
|
|
+ }
|
|
+
|
|
+ FontInfoData( const FontInfoData &fid )
|
|
+ {
|
|
+ fontName = fid.fontName;
|
|
+ fontFile = fid.fontFile;
|
|
+ isEmbedded = fid.isEmbedded;
|
|
+ isSubset = fid.isSubset;
|
|
+ type = fid.type;
|
|
+ embRef = fid.embRef;
|
|
+ }
|
|
+
|
|
+ FontInfoData( ::FontInfo* fi )
|
|
+ {
|
|
+ if (fi->getName()) fontName = fi->getName()->c_str();
|
|
+ if (fi->getFile()) fontFile = fi->getFile()->c_str();
|
|
+ isEmbedded = fi->getEmbedded();
|
|
+ isSubset = fi->getSubset();
|
|
+ type = (Poppler::FontInfo::Type)fi->getType();
|
|
+ embRef = fi->getEmbRef();
|
|
+ }
|
|
+
|
|
+ QString fontName;
|
|
+ QString fontFile;
|
|
+ bool isEmbedded : 1;
|
|
+ bool isSubset : 1;
|
|
+ FontInfo::Type type;
|
|
+ Ref embRef;
|
|
+ };
|
|
+
|
|
+ class FontIteratorData
|
|
+ {
|
|
+ public:
|
|
+ FontIteratorData( int startPage, DocumentData *dd )
|
|
+ : fontInfoScanner( dd->doc, startPage )
|
|
+ , totalPages( dd->doc->getNumPages() )
|
|
+ , currentPage( qMax( startPage, 0 ) - 1 )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ ~FontIteratorData()
|
|
+ {
|
|
+ }
|
|
+
|
|
+ FontInfoScanner fontInfoScanner;
|
|
+ int totalPages;
|
|
+ int currentPage;
|
|
+ };
|
|
+
|
|
+ class TextBoxData
|
|
+ {
|
|
+ public:
|
|
+ TextBoxData()
|
|
+ : nextWord(0), hasSpaceAfter(false)
|
|
+ {
|
|
+ }
|
|
+
|
|
+ QString text;
|
|
+ QRectF bBox;
|
|
+ TextBox *nextWord;
|
|
+ QVector<QRectF> charBBoxes; // the boundingRect of each character
|
|
+ bool hasSpaceAfter;
|
|
+ };
|
|
+
|
|
+ class FormFieldData
|
|
+ {
|
|
+ public:
|
|
+ FormFieldData(DocumentData *_doc, ::Page *p, ::FormWidget *w) :
|
|
+ doc(_doc), page(p), fm(w)
|
|
+ {
|
|
+ }
|
|
+
|
|
+ DocumentData *doc;
|
|
+ ::Page *page;
|
|
+ ::FormWidget *fm;
|
|
+ QRectF box;
|
|
+ };
|
|
+
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-ps-converter.cc b/qt4/src/poppler-ps-converter.cc
|
|
new file mode 100644
|
|
index 00000000..4b43d8ec
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-ps-converter.cc
|
|
@@ -0,0 +1,280 @@
|
|
+/* poppler-ps-converter.cc: qt interface to poppler
|
|
+ * Copyright (C) 2007, 2009, 2010, 2015, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
|
|
+ * Copyright (C) 2011 Glad Deschrijver <glad.deschrijver@gmail.com>
|
|
+ * Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
|
|
+ * Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
|
|
+ * Copyright (C) 2014 Adrian Johnson <ajohnson@redneon.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-qt4.h"
|
|
+
|
|
+#include "poppler-private.h"
|
|
+#include "poppler-converter-private.h"
|
|
+
|
|
+#include "PSOutputDev.h"
|
|
+
|
|
+static void outputToQIODevice(void *stream, const char *data, int len)
|
|
+{
|
|
+ static_cast<QIODevice*>(stream)->write(data, len);
|
|
+}
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+class PSConverterPrivate : public BaseConverterPrivate
|
|
+{
|
|
+ public:
|
|
+ PSConverterPrivate();
|
|
+
|
|
+ QList<int> pageList;
|
|
+ QString title;
|
|
+ double hDPI;
|
|
+ double vDPI;
|
|
+ int rotate;
|
|
+ int paperWidth;
|
|
+ int paperHeight;
|
|
+ int marginRight;
|
|
+ int marginBottom;
|
|
+ int marginLeft;
|
|
+ int marginTop;
|
|
+ PSConverter::PSOptions opts;
|
|
+ void (* pageConvertedCallback)(int page, void *payload);
|
|
+ void *pageConvertedPayload;
|
|
+};
|
|
+
|
|
+PSConverterPrivate::PSConverterPrivate()
|
|
+ : BaseConverterPrivate(),
|
|
+ hDPI(72), vDPI(72), rotate(0), paperWidth(-1), paperHeight(-1),
|
|
+ marginRight(0), marginBottom(0), marginLeft(0), marginTop(0),
|
|
+ opts(PSConverter::Printing), pageConvertedCallback(0),
|
|
+ pageConvertedPayload(0)
|
|
+{
|
|
+}
|
|
+
|
|
+
|
|
+PSConverter::PSConverter(DocumentData *document)
|
|
+ : BaseConverter(*new PSConverterPrivate())
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->document = document;
|
|
+}
|
|
+
|
|
+PSConverter::~PSConverter()
|
|
+{
|
|
+}
|
|
+
|
|
+void PSConverter::setPageList(const QList<int> &pageList)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->pageList = pageList;
|
|
+}
|
|
+
|
|
+void PSConverter::setTitle(const QString &title)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->title = title;
|
|
+}
|
|
+
|
|
+void PSConverter::setHDPI(double hDPI)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->hDPI = hDPI;
|
|
+}
|
|
+
|
|
+void PSConverter::setVDPI(double vDPI)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->vDPI = vDPI;
|
|
+}
|
|
+
|
|
+void PSConverter::setRotate(int rotate)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->rotate = rotate;
|
|
+}
|
|
+
|
|
+void PSConverter::setPaperWidth(int paperWidth)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->paperWidth = paperWidth;
|
|
+}
|
|
+
|
|
+void PSConverter::setPaperHeight(int paperHeight)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->paperHeight = paperHeight;
|
|
+}
|
|
+
|
|
+void PSConverter::setRightMargin(int marginRight)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->marginRight = marginRight;
|
|
+}
|
|
+
|
|
+void PSConverter::setBottomMargin(int marginBottom)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->marginBottom = marginBottom;
|
|
+}
|
|
+
|
|
+void PSConverter::setLeftMargin(int marginLeft)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->marginLeft = marginLeft;
|
|
+}
|
|
+
|
|
+void PSConverter::setTopMargin(int marginTop)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->marginTop = marginTop;
|
|
+}
|
|
+
|
|
+void PSConverter::setStrictMargins(bool strictMargins)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ if (strictMargins)
|
|
+ d->opts |= StrictMargins;
|
|
+ else
|
|
+ d->opts &= ~StrictMargins;
|
|
+}
|
|
+
|
|
+void PSConverter::setForceRasterize(bool forceRasterize)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ if (forceRasterize)
|
|
+ d->opts |= ForceRasterization;
|
|
+ else
|
|
+ d->opts &= ~ForceRasterization;
|
|
+}
|
|
+
|
|
+void PSConverter::setPSOptions(PSConverter::PSOptions options)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->opts = options;
|
|
+}
|
|
+
|
|
+PSConverter::PSOptions PSConverter::psOptions() const
|
|
+{
|
|
+ Q_D(const PSConverter);
|
|
+ return d->opts;
|
|
+}
|
|
+
|
|
+void PSConverter::setPageConvertedCallback(void (* callback)(int page, void *payload), void *payload)
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->pageConvertedCallback = callback;
|
|
+ d->pageConvertedPayload = payload;
|
|
+}
|
|
+
|
|
+static bool annotDisplayDecideCbk(Annot *annot, void *user_data)
|
|
+{
|
|
+ if (annot->getType() == Annot::typeWidget)
|
|
+ return true; // Never hide forms
|
|
+ else
|
|
+ return *(bool*)user_data;
|
|
+}
|
|
+
|
|
+bool PSConverter::convert()
|
|
+{
|
|
+ Q_D(PSConverter);
|
|
+ d->lastError = NoError;
|
|
+
|
|
+ Q_ASSERT(!d->pageList.isEmpty());
|
|
+ Q_ASSERT(d->paperWidth != -1);
|
|
+ Q_ASSERT(d->paperHeight != -1);
|
|
+
|
|
+ if (d->document->locked)
|
|
+ {
|
|
+ d->lastError = FileLockedError;
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ QIODevice *dev = d->openDevice();
|
|
+ if (!dev)
|
|
+ {
|
|
+ d->lastError = OpenOutputError;
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ QByteArray pstitle8Bit = d->title.toLocal8Bit();
|
|
+ char* pstitlechar;
|
|
+ if (!d->title.isEmpty()) pstitlechar = pstitle8Bit.data();
|
|
+ else pstitlechar = 0;
|
|
+
|
|
+ std::vector<int> pages;
|
|
+ foreach(int page, d->pageList)
|
|
+ {
|
|
+ pages.push_back(page);
|
|
+ }
|
|
+
|
|
+ PSOutputDev *psOut = new PSOutputDev(outputToQIODevice, dev,
|
|
+ pstitlechar,
|
|
+ d->document->doc,
|
|
+ pages,
|
|
+ (d->opts & PrintToEPS) ? psModeEPS : psModePS,
|
|
+ d->paperWidth,
|
|
+ d->paperHeight,
|
|
+ false,
|
|
+ false,
|
|
+ d->marginLeft,
|
|
+ d->marginBottom,
|
|
+ d->paperWidth - d->marginRight,
|
|
+ d->paperHeight - d->marginTop,
|
|
+ (d->opts & ForceRasterization));
|
|
+
|
|
+ if (d->opts & StrictMargins)
|
|
+ {
|
|
+ double xScale = ((double)d->paperWidth - (double)d->marginLeft - (double)d->marginRight) / (double)d->paperWidth;
|
|
+ double yScale = ((double)d->paperHeight - (double)d->marginBottom - (double)d->marginTop) / (double)d->paperHeight;
|
|
+ psOut->setScale(xScale, yScale);
|
|
+ }
|
|
+
|
|
+ if (psOut->isOk())
|
|
+ {
|
|
+ bool isPrinting = (d->opts & Printing) ? true : false;
|
|
+ bool showAnnotations = (d->opts & HideAnnotations) ? false : true;
|
|
+ foreach(int page, d->pageList)
|
|
+ {
|
|
+ d->document->doc->displayPage(psOut,
|
|
+ page,
|
|
+ d->hDPI,
|
|
+ d->vDPI,
|
|
+ d->rotate,
|
|
+ false,
|
|
+ true,
|
|
+ isPrinting,
|
|
+ NULL,
|
|
+ NULL,
|
|
+ annotDisplayDecideCbk,
|
|
+ &showAnnotations, true);
|
|
+ if (d->pageConvertedCallback)
|
|
+ (*d->pageConvertedCallback)(page, d->pageConvertedPayload);
|
|
+ }
|
|
+ delete psOut;
|
|
+ d->closeDevice();
|
|
+ return true;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ delete psOut;
|
|
+ d->closeDevice();
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-qiodeviceoutstream-private.h b/qt4/src/poppler-qiodeviceoutstream-private.h
|
|
new file mode 100644
|
|
index 00000000..d0d20073
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-qiodeviceoutstream-private.h
|
|
@@ -0,0 +1,47 @@
|
|
+/* poppler-qiodevicestream-private.h: Qt4 interface to poppler
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef POPPLER_QIODEVICESTREAM_PRIVATE_H
|
|
+#define POPPLER_QIODEVICESTREAM_PRIVATE_H
|
|
+
|
|
+#include "Object.h"
|
|
+#include "Stream.h"
|
|
+
|
|
+class QIODevice;
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+class QIODeviceOutStream : public OutStream
|
|
+{
|
|
+ public:
|
|
+ QIODeviceOutStream(QIODevice* device);
|
|
+ virtual ~QIODeviceOutStream();
|
|
+
|
|
+ virtual void close();
|
|
+ virtual Goffset getPos();
|
|
+ virtual void put(char c);
|
|
+ virtual void printf(const char *format, ...);
|
|
+
|
|
+ private:
|
|
+ QIODevice *m_device;
|
|
+};
|
|
+
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-qiodeviceoutstream.cc b/qt4/src/poppler-qiodeviceoutstream.cc
|
|
new file mode 100644
|
|
index 00000000..e3e9f895
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-qiodeviceoutstream.cc
|
|
@@ -0,0 +1,64 @@
|
|
+/* poppler-qiodevicestream.cc: Qt4 interface to poppler
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-qiodeviceoutstream-private.h"
|
|
+
|
|
+#include <QtCore/QIODevice>
|
|
+
|
|
+#include <stdio.h>
|
|
+
|
|
+#define QIODeviceOutStreamBufSize 8192
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+QIODeviceOutStream::QIODeviceOutStream(QIODevice* device)
|
|
+ : m_device(device)
|
|
+{
|
|
+}
|
|
+
|
|
+QIODeviceOutStream::~QIODeviceOutStream()
|
|
+{
|
|
+}
|
|
+
|
|
+void QIODeviceOutStream::close()
|
|
+{
|
|
+}
|
|
+
|
|
+Goffset QIODeviceOutStream::getPos()
|
|
+{
|
|
+ return m_device->pos();
|
|
+}
|
|
+
|
|
+void QIODeviceOutStream::put(char c)
|
|
+{
|
|
+ m_device->putChar(c);
|
|
+}
|
|
+
|
|
+void QIODeviceOutStream::printf(const char *format, ...)
|
|
+{
|
|
+ va_list ap;
|
|
+ va_start(ap, format);
|
|
+ char buf[QIODeviceOutStreamBufSize];
|
|
+ size_t bufsize = 0;
|
|
+ bufsize = qvsnprintf(buf, QIODeviceOutStreamBufSize - 1, format, ap);
|
|
+ va_end(ap);
|
|
+ m_device->write(buf, bufsize);
|
|
+}
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-qt4.h b/qt4/src/poppler-qt4.h
|
|
new file mode 100644
|
|
index 00000000..1b5afb2e
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-qt4.h
|
|
@@ -0,0 +1,1990 @@
|
|
+/* poppler-qt.h: qt interface to poppler
|
|
+ * Copyright (C) 2005, Net Integration Technologies, Inc.
|
|
+ * Copyright (C) 2005, 2007, Brad Hards <bradh@frogmouth.net>
|
|
+ * Copyright (C) 2005-2012, 2014, 2015, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2005, Stefan Kebekus <stefan.kebekus@math.uni-koeln.de>
|
|
+ * Copyright (C) 2006-2011, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2009 Shawn Rutledge <shawn.t.rutledge@gmail.com>
|
|
+ * Copyright (C) 2010 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
|
|
+ * Copyright (C) 2010 Matthias Fauconneau <matthias.fauconneau@gmail.com>
|
|
+ * Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
|
|
+ * Copyright (C) 2011 Glad Deschrijver <glad.deschrijver@gmail.com>
|
|
+ * Copyright (C) 2012, Guillermo A. Amaral B. <gamaral@kde.org>
|
|
+ * Copyright (C) 2012, Fabio D'Urso <fabiodurso@hotmail.it>
|
|
+ * Copyright (C) 2012, Tobias Koenig <tobias.koenig@kdab.com>
|
|
+ * Copyright (C) 2012, 2014, 2015 Adam Reichold <adamreichold@myopera.com>
|
|
+ * Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
|
|
+ * Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#ifndef __POPPLER_QT_H__
|
|
+#define __POPPLER_QT_H__
|
|
+
|
|
+#include "poppler-annotation.h"
|
|
+#include "poppler-link.h"
|
|
+#include "poppler-optcontent.h"
|
|
+#include "poppler-page-transition.h"
|
|
+
|
|
+#include <QtCore/QByteArray>
|
|
+#include <QtCore/QDateTime>
|
|
+#include <QtCore/QSet>
|
|
+#include <QtXml/QDomDocument>
|
|
+#include "poppler-export.h"
|
|
+
|
|
+class EmbFile;
|
|
+class Sound;
|
|
+class AnnotMovie;
|
|
+
|
|
+/**
|
|
+ The %Poppler Qt4 binding.
|
|
+*/
|
|
+namespace Poppler {
|
|
+
|
|
+ class Document;
|
|
+ class DocumentData;
|
|
+
|
|
+ class PageData;
|
|
+
|
|
+ class FormField;
|
|
+
|
|
+ class TextBoxData;
|
|
+
|
|
+ class PDFConverter;
|
|
+ class PSConverter;
|
|
+
|
|
+ /**
|
|
+ Debug/error function.
|
|
+
|
|
+ This function type is used for debugging & error output;
|
|
+ the first parameter is the actual message, the second is the unaltered
|
|
+ closure argument which was passed to the setDebugErrorFunction call.
|
|
+
|
|
+ \since 0.16
|
|
+ */
|
|
+ typedef void (*PopplerDebugFunc)(const QString & /*message*/, const QVariant & /*closure*/);
|
|
+
|
|
+ /**
|
|
+ Set a new debug/error output function.
|
|
+
|
|
+ If not set, by default error and debug messages will be sent to the
|
|
+ Qt \p qDebug() function.
|
|
+
|
|
+ \param debugFunction the new debug function
|
|
+ \param closure user data which will be passes as-is to the debug function
|
|
+
|
|
+ \since 0.16
|
|
+ */
|
|
+ POPPLER_QT4_EXPORT void setDebugErrorFunction(PopplerDebugFunc debugFunction, const QVariant &closure);
|
|
+
|
|
+ /**
|
|
+ Describes the physical location of text on a document page
|
|
+
|
|
+ This very simple class describes the physical location of text
|
|
+ on the page. It consists of
|
|
+ - a QString that contains the text
|
|
+ - a QRectF that gives a box that describes where on the page
|
|
+ the text is found.
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT TextBox {
|
|
+ friend class Page;
|
|
+ public:
|
|
+ /**
|
|
+ The default constructor sets the \p text and the rectangle that
|
|
+ contains the text. Coordinates for the \p bBox are in points =
|
|
+ 1/72 of an inch.
|
|
+ */
|
|
+ TextBox(const QString& text, const QRectF &bBox);
|
|
+ /**
|
|
+ Destructor.
|
|
+ */
|
|
+ ~TextBox();
|
|
+
|
|
+ /**
|
|
+ Returns the text of this text box
|
|
+ */
|
|
+ QString text() const;
|
|
+
|
|
+ /**
|
|
+ Returns the position of the text, in point, i.e., 1/72 of
|
|
+ an inch
|
|
+
|
|
+ \since 0.8
|
|
+ */
|
|
+ QRectF boundingBox() const;
|
|
+
|
|
+ /**
|
|
+ Returns the pointer to the next text box, if there is one.
|
|
+
|
|
+ Otherwise, it returns a null pointer.
|
|
+ */
|
|
+ TextBox *nextWord() const;
|
|
+
|
|
+ /**
|
|
+ Returns the bounding box of the \p i -th characted of the word.
|
|
+ */
|
|
+ QRectF charBoundingBox(int i) const;
|
|
+
|
|
+ /**
|
|
+ Returns whether there is a space character after this text box
|
|
+ */
|
|
+ bool hasSpaceAfter() const;
|
|
+
|
|
+ private:
|
|
+ Q_DISABLE_COPY(TextBox)
|
|
+
|
|
+ TextBoxData *m_data;
|
|
+ };
|
|
+
|
|
+
|
|
+ class FontInfoData;
|
|
+ /**
|
|
+ Container class for information about a font within a PDF
|
|
+ document
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT FontInfo {
|
|
+ friend class Document;
|
|
+ public:
|
|
+ /**
|
|
+ The type of font.
|
|
+ */
|
|
+ enum Type {
|
|
+ unknown,
|
|
+ Type1,
|
|
+ Type1C,
|
|
+ Type1COT,
|
|
+ Type3,
|
|
+ TrueType,
|
|
+ TrueTypeOT,
|
|
+ CIDType0,
|
|
+ CIDType0C,
|
|
+ CIDType0COT,
|
|
+ CIDTrueType,
|
|
+ CIDTrueTypeOT
|
|
+ };
|
|
+
|
|
+ /// \cond PRIVATE
|
|
+ /**
|
|
+ Create a new font information container.
|
|
+ */
|
|
+ FontInfo();
|
|
+
|
|
+ /**
|
|
+ Create a new font information container.
|
|
+ */
|
|
+ FontInfo( const FontInfoData &fid );
|
|
+ /// \endcond
|
|
+
|
|
+ /**
|
|
+ Copy constructor.
|
|
+ */
|
|
+ FontInfo( const FontInfo &fi );
|
|
+
|
|
+ /**
|
|
+ Destructor.
|
|
+ */
|
|
+ ~FontInfo();
|
|
+
|
|
+ /**
|
|
+ The name of the font. Can be QString::null if the font has no name
|
|
+ */
|
|
+ QString name() const;
|
|
+
|
|
+ /**
|
|
+ The path of the font file used to represent this font on this system,
|
|
+ or a null string is the font is embedded
|
|
+ */
|
|
+ QString file() const;
|
|
+
|
|
+ /**
|
|
+ Whether the font is embedded in the file, or not
|
|
+
|
|
+ \return true if the font is embedded
|
|
+ */
|
|
+ bool isEmbedded() const;
|
|
+
|
|
+ /**
|
|
+ Whether the font provided is only a subset of the full
|
|
+ font or not. This only has meaning if the font is embedded.
|
|
+
|
|
+ \return true if the font is only a subset
|
|
+ */
|
|
+ bool isSubset() const;
|
|
+
|
|
+ /**
|
|
+ The type of font encoding
|
|
+
|
|
+ \return a enumerated value corresponding to the font encoding used
|
|
+
|
|
+ \sa typeName for a string equivalent
|
|
+ */
|
|
+ Type type() const;
|
|
+
|
|
+ /**
|
|
+ The name of the font encoding used
|
|
+
|
|
+ \note if you are looking for the name of the font (as opposed to the
|
|
+ encoding format used), you probably want name().
|
|
+
|
|
+ \sa type for a enumeration version
|
|
+ */
|
|
+ QString typeName() const;
|
|
+
|
|
+ /**
|
|
+ Standard assignment operator
|
|
+ */
|
|
+ FontInfo& operator=( const FontInfo &fi );
|
|
+
|
|
+ private:
|
|
+ FontInfoData *m_data;
|
|
+ };
|
|
+
|
|
+
|
|
+ class FontIteratorData;
|
|
+ /**
|
|
+ Iterator for reading the fonts in a document.
|
|
+
|
|
+ FontIterator provides a Java-style iterator for reading the fonts in a
|
|
+ document.
|
|
+
|
|
+ You can use it in the following way:
|
|
+ \code
|
|
+Poppler::FontIterator* it = doc->newFontIterator();
|
|
+while (it->hasNext()) {
|
|
+ QList<Poppler::FontInfo> fonts = it->next();
|
|
+ // do something with the fonts
|
|
+}
|
|
+// after doing the job, the iterator must be freed
|
|
+delete it;
|
|
+ \endcode
|
|
+
|
|
+ \since 0.12
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT FontIterator {
|
|
+ friend class Document;
|
|
+ friend class DocumentData;
|
|
+ public:
|
|
+ /**
|
|
+ Destructor.
|
|
+ */
|
|
+ ~FontIterator();
|
|
+
|
|
+ /**
|
|
+ Returns the fonts of the current page and then advances the iterator
|
|
+ to the next page.
|
|
+ */
|
|
+ QList<FontInfo> next();
|
|
+
|
|
+ /**
|
|
+ Checks whether there is at least one more page to iterate, ie returns
|
|
+ false when the iterator is beyond the last page.
|
|
+ */
|
|
+ bool hasNext() const;
|
|
+
|
|
+ /**
|
|
+ Returns the current page where the iterator is.
|
|
+ */
|
|
+ int currentPage() const;
|
|
+
|
|
+ private:
|
|
+ Q_DISABLE_COPY( FontIterator )
|
|
+ FontIterator( int, DocumentData *dd );
|
|
+
|
|
+ FontIteratorData *d;
|
|
+ };
|
|
+
|
|
+
|
|
+ class EmbeddedFileData;
|
|
+ /**
|
|
+ Container class for an embedded file with a PDF document
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT EmbeddedFile {
|
|
+ friend class DocumentData;
|
|
+ friend class AnnotationPrivate;
|
|
+ public:
|
|
+ /// \cond PRIVATE
|
|
+ EmbeddedFile(EmbFile *embfile);
|
|
+ /// \endcond
|
|
+
|
|
+ /**
|
|
+ Destructor.
|
|
+ */
|
|
+ ~EmbeddedFile();
|
|
+
|
|
+ /**
|
|
+ The name associated with the file
|
|
+ */
|
|
+ QString name() const;
|
|
+
|
|
+ /**
|
|
+ The description associated with the file, if any.
|
|
+
|
|
+ This will return an empty QString if there is no description element
|
|
+ */
|
|
+ QString description() const;
|
|
+
|
|
+ /**
|
|
+ The size of the file.
|
|
+
|
|
+ This will return < 0 if there is no size element
|
|
+ */
|
|
+ int size() const;
|
|
+
|
|
+ /**
|
|
+ The modification date for the embedded file, if known.
|
|
+ */
|
|
+ QDateTime modDate() const;
|
|
+
|
|
+ /**
|
|
+ The creation date for the embedded file, if known.
|
|
+ */
|
|
+ QDateTime createDate() const;
|
|
+
|
|
+ /**
|
|
+ The MD5 checksum of the file.
|
|
+
|
|
+ This will return an empty QByteArray if there is no checksum element.
|
|
+ */
|
|
+ QByteArray checksum() const;
|
|
+
|
|
+ /**
|
|
+ The MIME type of the file, if known.
|
|
+
|
|
+ \since 0.8
|
|
+ */
|
|
+ QString mimeType() const;
|
|
+
|
|
+ /**
|
|
+ The data as a byte array
|
|
+ */
|
|
+ QByteArray data();
|
|
+
|
|
+ /**
|
|
+ Is the embedded file valid?
|
|
+
|
|
+ \since 0.12
|
|
+ */
|
|
+ bool isValid() const;
|
|
+
|
|
+ /**
|
|
+ A QDataStream for the actual data?
|
|
+ */
|
|
+ //QDataStream dataStream() const;
|
|
+
|
|
+ private:
|
|
+ Q_DISABLE_COPY(EmbeddedFile)
|
|
+ EmbeddedFile(EmbeddedFileData &dd);
|
|
+
|
|
+ EmbeddedFileData *m_embeddedFile;
|
|
+ };
|
|
+
|
|
+
|
|
+ /**
|
|
+ \brief A page in a document.
|
|
+
|
|
+ The Page class represents a single page within a PDF document.
|
|
+
|
|
+ You cannot construct a Page directly, but you have to use the Document
|
|
+ functions that return a new Page out of an index or a label.
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT Page {
|
|
+ friend class Document;
|
|
+ public:
|
|
+ /**
|
|
+ Destructor.
|
|
+ */
|
|
+ ~Page();
|
|
+
|
|
+ /**
|
|
+ The type of rotation to apply for an operation
|
|
+ */
|
|
+ enum Rotation { Rotate0 = 0, ///< Do not rotate
|
|
+ Rotate90 = 1, ///< Rotate 90 degrees clockwise
|
|
+ Rotate180 = 2, ///< Rotate 180 degrees
|
|
+ Rotate270 = 3 ///< Rotate 270 degrees clockwise (90 degrees counterclockwise)
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ The kinds of page actions
|
|
+ */
|
|
+ enum PageAction {
|
|
+ Opening, ///< The action when a page is "opened"
|
|
+ Closing ///< The action when a page is "closed"
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ How the text is going to be returned
|
|
+ \since 0.16
|
|
+ */
|
|
+ enum TextLayout {
|
|
+ PhysicalLayout, ///< The text is layouted to resemble the real page layout
|
|
+ RawOrderLayout ///< The text is returned without any type of processing
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ Additional flags for the renderToPainter method
|
|
+ \since 0.16
|
|
+ */
|
|
+ enum PainterFlag {
|
|
+ /**
|
|
+ Do not save/restore the caller-owned painter.
|
|
+
|
|
+ renderToPainter() by default preserves, using save() + restore(),
|
|
+ the state of the painter specified; if this is not needed, this
|
|
+ flag can avoid this job
|
|
+ */
|
|
+ DontSaveAndRestore = 0x00000001
|
|
+ };
|
|
+ Q_DECLARE_FLAGS( PainterFlags, PainterFlag )
|
|
+
|
|
+ /**
|
|
+ Render the page to a QImage using the current
|
|
+ \link Document::renderBackend() Document renderer\endlink.
|
|
+
|
|
+ If \p x = \p y = \p w = \p h = -1, the method will automatically
|
|
+ compute the size of the image from the horizontal and vertical
|
|
+ resolutions specified in \p xres and \p yres. Otherwise, the
|
|
+ method renders only a part of the page, specified by the
|
|
+ parameters (\p x, \p y, \p w, \p h) in pixel coordinates. The returned
|
|
+ QImage then has size (\p w, \p h), independent of the page
|
|
+ size.
|
|
+
|
|
+ \param x specifies the left x-coordinate of the box, in
|
|
+ pixels.
|
|
+
|
|
+ \param y specifies the top y-coordinate of the box, in
|
|
+ pixels.
|
|
+
|
|
+ \param w specifies the width of the box, in pixels.
|
|
+
|
|
+ \param h specifies the height of the box, in pixels.
|
|
+
|
|
+ \param xres horizontal resolution of the graphics device,
|
|
+ in dots per inch
|
|
+
|
|
+ \param yres vertical resolution of the graphics device, in
|
|
+ dots per inch
|
|
+
|
|
+ \param rotate how to rotate the page
|
|
+
|
|
+ \warning The parameter (\p x, \p y, \p w, \p h) are not
|
|
+ well-tested. Unusual or meaningless parameters may lead to
|
|
+ rather unexpected results.
|
|
+
|
|
+ \returns a QImage of the page, or a null image on failure.
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ QImage renderToImage(double xres=72.0, double yres=72.0, int x=-1, int y=-1, int w=-1, int h=-1, Rotation rotate = Rotate0) const;
|
|
+
|
|
+ /**
|
|
+ Render the page to the specified QPainter using the current
|
|
+ \link Document::renderBackend() Document renderer\endlink.
|
|
+
|
|
+ If \p x = \p y = \p w = \p h = -1, the method will automatically
|
|
+ compute the size of the page area from the horizontal and vertical
|
|
+ resolutions specified in \p xres and \p yres. Otherwise, the
|
|
+ method renders only a part of the page, specified by the
|
|
+ parameters (\p x, \p y, \p w, \p h) in pixel coordinates.
|
|
+
|
|
+ \param painter the painter to paint on
|
|
+
|
|
+ \param x specifies the left x-coordinate of the box, in
|
|
+ pixels.
|
|
+
|
|
+ \param y specifies the top y-coordinate of the box, in
|
|
+ pixels.
|
|
+
|
|
+ \param w specifies the width of the box, in pixels.
|
|
+
|
|
+ \param h specifies the height of the box, in pixels.
|
|
+
|
|
+ \param xres horizontal resolution of the graphics device,
|
|
+ in dots per inch
|
|
+
|
|
+ \param yres vertical resolution of the graphics device, in
|
|
+ dots per inch
|
|
+
|
|
+ \param rotate how to rotate the page
|
|
+
|
|
+ \param flags additional painter flags
|
|
+
|
|
+ \warning The parameter (\p x, \p y, \p w, \p h) are not
|
|
+ well-tested. Unusual or meaningless parameters may lead to
|
|
+ rather unexpected results.
|
|
+
|
|
+ \returns whether the painting succeeded
|
|
+
|
|
+ \note This method is only supported for Arthur
|
|
+
|
|
+ \since 0.16
|
|
+ */
|
|
+ bool renderToPainter(QPainter* painter, double xres=72.0, double yres=72.0, int x=-1, int y=-1, int w=-1, int h=-1,
|
|
+ Rotation rotate = Rotate0, PainterFlags flags = 0) const;
|
|
+
|
|
+ /**
|
|
+ Get the page thumbnail if it exists.
|
|
+
|
|
+ \return a QImage of the thumbnail, or a null image
|
|
+ if the PDF does not contain one for this page
|
|
+
|
|
+ \since 0.12
|
|
+ */
|
|
+ QImage thumbnail() const;
|
|
+
|
|
+ /**
|
|
+ Returns the text that is inside a specified rectangle
|
|
+
|
|
+ \param rect the rectangle specifying the area of interest,
|
|
+ with coordinates given in points, i.e., 1/72th of an inch.
|
|
+ If rect is null, all text on the page is given
|
|
+
|
|
+ \since 0.16
|
|
+ **/
|
|
+ QString text(const QRectF &rect, TextLayout textLayout) const;
|
|
+
|
|
+ /**
|
|
+ Returns the text that is inside a specified rectangle.
|
|
+ The text is returned using the physical layout of the page
|
|
+
|
|
+ \param rect the rectangle specifying the area of interest,
|
|
+ with coordinates given in points, i.e., 1/72th of an inch.
|
|
+ If rect is null, all text on the page is given
|
|
+ **/
|
|
+ QString text(const QRectF &rect) const;
|
|
+
|
|
+ /**
|
|
+ The starting point for a search
|
|
+ */
|
|
+ enum SearchDirection { FromTop, ///< Start sorting at the top of the document
|
|
+ NextResult, ///< Find the next result, moving "down the page"
|
|
+ PreviousResult ///< Find the previous result, moving "up the page"
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ The type of search to perform
|
|
+ */
|
|
+ enum SearchMode { CaseSensitive, ///< Case differences cause no match in searching
|
|
+ CaseInsensitive ///< Case differences are ignored in matching
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ Flags to modify the search behaviour \since 0.31
|
|
+ */
|
|
+ enum SearchFlag
|
|
+ {
|
|
+ IgnoreCase = 0x00000001, ///< Case differences are ignored
|
|
+ WholeWords = 0x00000002 ///< Only whole words are matched
|
|
+ };
|
|
+ Q_DECLARE_FLAGS( SearchFlags, SearchFlag )
|
|
+
|
|
+ /**
|
|
+ Returns true if the specified text was found.
|
|
+
|
|
+ \param text the text the search
|
|
+ \param rect in all directions is used to return where the text was found, for NextResult and PreviousResult
|
|
+ indicates where to continue searching for
|
|
+ \param direction in which direction do the search
|
|
+ \param caseSensitive be case sensitive?
|
|
+ \param rotate the rotation to apply for the search order
|
|
+ **/
|
|
+ Q_DECL_DEPRECATED bool search(const QString &text, QRectF &rect, SearchDirection direction, SearchMode caseSensitive, Rotation rotate = Rotate0) const;
|
|
+
|
|
+ /**
|
|
+ Returns true if the specified text was found.
|
|
+
|
|
+ \param text the text the search
|
|
+ \param rectXXX in all directions is used to return where the text was found, for NextResult and PreviousResult
|
|
+ indicates where to continue searching for
|
|
+ \param direction in which direction do the search
|
|
+ \param caseSensitive be case sensitive?
|
|
+ \param rotate the rotation to apply for the search order
|
|
+ \since 0.14
|
|
+ **/
|
|
+ Q_DECL_DEPRECATED bool search(const QString &text, double &rectLeft, double &rectTop, double &rectRight, double &rectBottom, SearchDirection direction, SearchMode caseSensitive, Rotation rotate = Rotate0) const;
|
|
+
|
|
+ /**
|
|
+ Returns true if the specified text was found.
|
|
+
|
|
+ \param text the text the search
|
|
+ \param rectXXX in all directions is used to return where the text was found, for NextResult and PreviousResult
|
|
+ indicates where to continue searching for
|
|
+ \param direction in which direction do the search
|
|
+ \param flags the flags to consider during matching
|
|
+ \param rotate the rotation to apply for the search order
|
|
+
|
|
+ \since 0.31
|
|
+ **/
|
|
+ bool search(const QString &text, double &rectLeft, double &rectTop, double &rectRight, double &rectBottom, SearchDirection direction, SearchFlags flags = 0, Rotation rotate = Rotate0) const;
|
|
+
|
|
+ /**
|
|
+ Returns a list of all occurrences of the specified text on the page.
|
|
+
|
|
+ \param text the text to search
|
|
+ \param caseSensitive whether to be case sensitive
|
|
+ \param rotate the rotation to apply for the search order
|
|
+
|
|
+ \warning Do not use the returned QRectF as arguments of another search call because of truncation issues if qreal is defined as float.
|
|
+
|
|
+ \since 0.22
|
|
+ **/
|
|
+ Q_DECL_DEPRECATED QList<QRectF> search(const QString &text, SearchMode caseSensitive, Rotation rotate = Rotate0) const;
|
|
+
|
|
+ /**
|
|
+ Returns a list of all occurrences of the specified text on the page.
|
|
+
|
|
+ \param text the text to search
|
|
+ \param flags the flags to consider during matching
|
|
+ \param rotate the rotation to apply for the search order
|
|
+
|
|
+ \warning Do not use the returned QRectF as arguments of another search call because of truncation issues if qreal is defined as float.
|
|
+
|
|
+ \since 0.31
|
|
+ **/
|
|
+ QList<QRectF> search(const QString &text, SearchFlags flags = 0, Rotation rotate = Rotate0) const;
|
|
+
|
|
+ /**
|
|
+ Returns a list of text of the page
|
|
+
|
|
+ This method returns a QList of TextBoxes that contain all
|
|
+ the text of the page, with roughly one text word of text
|
|
+ per TextBox item.
|
|
+
|
|
+ For text written in western languages (left-to-right and
|
|
+ up-to-down), the QList contains the text in the proper
|
|
+ order.
|
|
+
|
|
+ \note The caller owns the text boxes and they should
|
|
+ be deleted when no longer required.
|
|
+
|
|
+ \warning This method is not tested with Asian scripts
|
|
+ */
|
|
+ QList<TextBox*> textList(Rotation rotate = Rotate0) const;
|
|
+
|
|
+ /**
|
|
+ \return The dimensions (cropbox) of the page, in points (i.e. 1/72th of an inch)
|
|
+ */
|
|
+ QSizeF pageSizeF() const;
|
|
+
|
|
+ /**
|
|
+ \return The dimensions (cropbox) of the page, in points (i.e. 1/72th of an inch)
|
|
+ */
|
|
+ QSize pageSize() const;
|
|
+
|
|
+ /**
|
|
+ Returns the transition of this page
|
|
+
|
|
+ \returns a pointer to a PageTransition structure that
|
|
+ defines how transition to this page shall be performed.
|
|
+
|
|
+ \note The PageTransition structure is owned by this page, and will
|
|
+ automatically be destroyed when this page class is
|
|
+ destroyed.
|
|
+ **/
|
|
+ PageTransition *transition() const;
|
|
+
|
|
+ /**
|
|
+ Gets the page action specified, or NULL if there is no action.
|
|
+
|
|
+ \since 0.6
|
|
+ **/
|
|
+ Link *action( PageAction act ) const;
|
|
+
|
|
+ /**
|
|
+ Types of orientations that are possible
|
|
+ */
|
|
+ enum Orientation {
|
|
+ Landscape, ///< Landscape orientation (portrait, with 90 degrees clockwise rotation )
|
|
+ Portrait, ///< Normal portrait orientation
|
|
+ Seascape, ///< Seascape orientation (portrait, with 270 degrees clockwise rotation)
|
|
+ UpsideDown ///< Upside down orientation (portrait, with 180 degrees rotation)
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ The orientation of the page
|
|
+ */
|
|
+ Orientation orientation() const;
|
|
+
|
|
+ /**
|
|
+ The default CTM
|
|
+ */
|
|
+ void defaultCTM(double *CTM, double dpiX, double dpiY, int rotate, bool upsideDown);
|
|
+
|
|
+ /**
|
|
+ Gets the links of the page
|
|
+ */
|
|
+ QList<Link*> links() const;
|
|
+
|
|
+ /**
|
|
+ Returns the annotations of the page
|
|
+
|
|
+ \note If you call this method twice, you get different objects
|
|
+ pointing to the same annotations (see Annotation).
|
|
+ The caller owns the returned objects and they should be deleted
|
|
+ when no longer required.
|
|
+ */
|
|
+ QList<Annotation*> annotations() const;
|
|
+
|
|
+ /**
|
|
+ Returns the annotations of the page
|
|
+
|
|
+ \param subtypes the subtypes of annotations you are interested in
|
|
+
|
|
+ \note If you call this method twice, you get different objects
|
|
+ pointing to the same annotations (see Annotation).
|
|
+ The caller owns the returned objects and they should be deleted
|
|
+ when no longer required.
|
|
+
|
|
+ \since 0.28
|
|
+ */
|
|
+ QList<Annotation*> annotations(const QSet<Annotation::SubType> &subtypes) const;
|
|
+
|
|
+ /**
|
|
+ Adds an annotation to the page
|
|
+
|
|
+ \note Ownership of the annotation object stays with the caller, who can
|
|
+ delete it at any time.
|
|
+ \since 0.20
|
|
+ */
|
|
+ void addAnnotation( const Annotation *ann );
|
|
+
|
|
+ /**
|
|
+ Removes an annotation from the page and destroys the annotation object
|
|
+
|
|
+ \note There mustn't be other Annotation objects pointing this annotation
|
|
+ \since 0.20
|
|
+ */
|
|
+ void removeAnnotation( const Annotation *ann );
|
|
+
|
|
+ /**
|
|
+ Returns the form fields on the page
|
|
+ The caller gets the ownership of the returned objects.
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ QList<FormField*> formFields() const;
|
|
+
|
|
+ /**
|
|
+ Returns the page duration. That is the time, in seconds, that the page
|
|
+ should be displayed before the presentation automatically advances to the next page.
|
|
+ Returns < 0 if duration is not set.
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ double duration() const;
|
|
+
|
|
+ /**
|
|
+ Returns the label of the page, or a null string is the page has no label.
|
|
+
|
|
+ \since 0.6
|
|
+ **/
|
|
+ QString label() const;
|
|
+
|
|
+ private:
|
|
+ Q_DISABLE_COPY(Page)
|
|
+
|
|
+ Page(DocumentData *doc, int index);
|
|
+ PageData *m_page;
|
|
+ };
|
|
+
|
|
+/**
|
|
+ \brief PDF document.
|
|
+
|
|
+ The Document class represents a PDF document: its pages, and all the global
|
|
+ properties, metadata, etc.
|
|
+
|
|
+ \section ownership Ownership of the returned objects
|
|
+
|
|
+ All the functions that returns class pointers create new object, and the
|
|
+ responsability of those is given to the callee.
|
|
+
|
|
+ The only exception is \link Poppler::Page::transition() Page::transition()\endlink.
|
|
+
|
|
+ \section document-loading Loading
|
|
+
|
|
+ To get a Document, you have to load it via the load() & loadFromData()
|
|
+ functions.
|
|
+
|
|
+ In all the functions that have passwords as arguments, they \b must be Latin1
|
|
+ encoded. If you have a password that is a UTF-8 string, you need to use
|
|
+ QString::toLatin1() (or similar) to convert the password first.
|
|
+ If you have a UTF-8 character array, consider converting it to a QString first
|
|
+ (QString::fromUtf8(), or similar) before converting to Latin1 encoding.
|
|
+
|
|
+ \section document-rendering Rendering
|
|
+
|
|
+ To render pages of a document, you have different Document functions to set
|
|
+ various options.
|
|
+
|
|
+ \subsection document-rendering-backend Backends
|
|
+
|
|
+ %Poppler offers a different backends for rendering the pages. Currently
|
|
+ there are two backends (see #RenderBackend), but only the Splash engine works
|
|
+ well and has been tested.
|
|
+
|
|
+ The available rendering backends can be discovered via availableRenderBackends().
|
|
+ The current rendering backend can be changed using setRenderBackend().
|
|
+ Please note that setting a backend not listed in the available ones
|
|
+ will always result in null QImage's.
|
|
+
|
|
+ \section document-cms Color management support
|
|
+
|
|
+ %Poppler, if compiled with this support, provides functions to handle color
|
|
+ profiles.
|
|
+
|
|
+ To know whether the %Poppler version you are using has support for color
|
|
+ management, you can query Poppler::isCmsAvailable(). In case it is not
|
|
+ avilable, all the color management-related functions will either do nothing
|
|
+ or return null.
|
|
+*/
|
|
+ class POPPLER_QT4_EXPORT Document {
|
|
+ friend class Page;
|
|
+ friend class DocumentData;
|
|
+
|
|
+ public:
|
|
+ /**
|
|
+ The page mode
|
|
+ */
|
|
+ enum PageMode {
|
|
+ UseNone, ///< No mode - neither document outline nor thumbnail images are visible
|
|
+ UseOutlines, ///< Document outline visible
|
|
+ UseThumbs, ///< Thumbnail images visible
|
|
+ FullScreen, ///< Fullscreen mode (no menubar, windows controls etc)
|
|
+ UseOC, ///< Optional content group panel visible
|
|
+ UseAttach ///< Attachments panel visible
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ The page layout
|
|
+ */
|
|
+ enum PageLayout {
|
|
+ NoLayout, ///< Layout not specified
|
|
+ SinglePage, ///< Display a single page
|
|
+ OneColumn, ///< Display a single column of pages
|
|
+ TwoColumnLeft, ///< Display the pages in two columns, with odd-numbered pages on the left
|
|
+ TwoColumnRight, ///< Display the pages in two columns, with odd-numbered pages on the right
|
|
+ TwoPageLeft, ///< Display the pages two at a time, with odd-numbered pages on the left
|
|
+ TwoPageRight ///< Display the pages two at a time, with odd-numbered pages on the right
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ The render backends available
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ enum RenderBackend {
|
|
+ SplashBackend, ///< Splash backend
|
|
+ ArthurBackend ///< Arthur (Qt4) backend
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ The render hints available
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ enum RenderHint {
|
|
+ Antialiasing = 0x00000001, ///< Antialiasing for graphics
|
|
+ TextAntialiasing = 0x00000002, ///< Antialiasing for text
|
|
+ TextHinting = 0x00000004, ///< Hinting for text \since 0.12.1
|
|
+ TextSlightHinting = 0x00000008, ///< Lighter hinting for text when combined with TextHinting \since 0.18
|
|
+ OverprintPreview = 0x00000010, ///< Overprint preview \since 0.22
|
|
+ ThinLineSolid = 0x00000020, ///< Enhance thin lines solid \since 0.24
|
|
+ ThinLineShape = 0x00000040, ///< Enhance thin lines shape. Wins over ThinLineSolid \since 0.24
|
|
+ IgnorePaperColor = 0x00000080 ///< Do not compose with the paper color \since 0.35
|
|
+ };
|
|
+ Q_DECLARE_FLAGS( RenderHints, RenderHint )
|
|
+
|
|
+ /**
|
|
+ Form types
|
|
+
|
|
+ \since 0.22
|
|
+ */
|
|
+ enum FormType {
|
|
+ NoForm, ///< Document doesn't contain forms
|
|
+ AcroForm, ///< AcroForm
|
|
+ XfaForm ///< Adobe XML Forms Architecture (XFA), currently unsupported
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ Set a color display profile for the current document.
|
|
+
|
|
+ \param outputProfileA is a \c cmsHPROFILE of the LCMS library.
|
|
+
|
|
+ \since 0.12
|
|
+ */
|
|
+ void setColorDisplayProfile(void *outputProfileA);
|
|
+ /**
|
|
+ Set a color display profile for the current document.
|
|
+
|
|
+ \param name is the name of the display profile to set.
|
|
+
|
|
+ \since 0.12
|
|
+ */
|
|
+ void setColorDisplayProfileName(const QString &name);
|
|
+ /**
|
|
+ Return the current RGB profile.
|
|
+
|
|
+ \return a \c cmsHPROFILE of the LCMS library.
|
|
+
|
|
+ \since 0.12
|
|
+ */
|
|
+ void* colorRgbProfile() const;
|
|
+ /**
|
|
+ Return the current display profile.
|
|
+
|
|
+ \return a \c cmsHPROFILE of the LCMS library.
|
|
+
|
|
+ \since 0.12
|
|
+ */
|
|
+ void *colorDisplayProfile() const;
|
|
+
|
|
+ /**
|
|
+ Load the document from a file on disk
|
|
+
|
|
+ \param filePath the name (and path, if required) of the file to load
|
|
+ \param ownerPassword the Latin1-encoded owner password to use in
|
|
+ loading the file
|
|
+ \param userPassword the Latin1-encoded user ("open") password
|
|
+ to use in loading the file
|
|
+
|
|
+ \return the loaded document, or NULL on error
|
|
+
|
|
+ \note The caller owns the pointer to Document, and this should
|
|
+ be deleted when no longer required.
|
|
+
|
|
+ \warning The returning document may be locked if a password is required
|
|
+ to open the file, and one is not provided (as the userPassword).
|
|
+ */
|
|
+ static Document *load(const QString & filePath,
|
|
+ const QByteArray &ownerPassword=QByteArray(),
|
|
+ const QByteArray &userPassword=QByteArray());
|
|
+
|
|
+ /**
|
|
+ Load the document from memory
|
|
+
|
|
+ \param fileContents the file contents. They are copied so there is no need
|
|
+ to keep the byte array around for the full life time of
|
|
+ the document.
|
|
+ \param ownerPassword the Latin1-encoded owner password to use in
|
|
+ loading the file
|
|
+ \param userPassword the Latin1-encoded user ("open") password
|
|
+ to use in loading the file
|
|
+
|
|
+ \return the loaded document, or NULL on error
|
|
+
|
|
+ \note The caller owns the pointer to Document, and this should
|
|
+ be deleted when no longer required.
|
|
+
|
|
+ \warning The returning document may be locked if a password is required
|
|
+ to open the file, and one is not provided (as the userPassword).
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ static Document *loadFromData(const QByteArray &fileContents,
|
|
+ const QByteArray &ownerPassword=QByteArray(),
|
|
+ const QByteArray &userPassword=QByteArray());
|
|
+
|
|
+ /**
|
|
+ Get a specified Page
|
|
+
|
|
+ Note that this follows the PDF standard of being zero based - if you
|
|
+ want the first page, then you need an index of zero.
|
|
+
|
|
+ The caller gets the ownership of the returned object.
|
|
+
|
|
+ \param index the page number index
|
|
+ */
|
|
+ Page *page(int index) const;
|
|
+
|
|
+ /**
|
|
+ \overload
|
|
+
|
|
+
|
|
+ The intent is that you can pass in a label like \c "ix" and
|
|
+ get the page with that label (which might be in the table of
|
|
+ contents), or pass in \c "1" and get the page that the user
|
|
+ expects (which might not be the first page, if there is a
|
|
+ title page and a table of contents).
|
|
+
|
|
+ \param label the page label
|
|
+ */
|
|
+ Page *page(const QString &label) const;
|
|
+
|
|
+ /**
|
|
+ The number of pages in the document
|
|
+ */
|
|
+ int numPages() const;
|
|
+
|
|
+ /**
|
|
+ The type of mode that should be used by the application
|
|
+ when the document is opened. Note that while this is
|
|
+ called page mode, it is really viewer application mode.
|
|
+ */
|
|
+ PageMode pageMode() const;
|
|
+
|
|
+ /**
|
|
+ The layout that pages should be shown in when the document
|
|
+ is first opened. This basically describes how pages are
|
|
+ shown relative to each other.
|
|
+ */
|
|
+ PageLayout pageLayout() const;
|
|
+
|
|
+ /**
|
|
+ The predominant reading order for text as supplied by
|
|
+ the document's viewer preferences.
|
|
+
|
|
+ \since 0.26
|
|
+ */
|
|
+ Qt::LayoutDirection textDirection() const;
|
|
+
|
|
+ /**
|
|
+ Provide the passwords required to unlock the document
|
|
+
|
|
+ \param ownerPassword the Latin1-encoded owner password to use in
|
|
+ loading the file
|
|
+ \param userPassword the Latin1-encoded user ("open") password
|
|
+ to use in loading the file
|
|
+ */
|
|
+ bool unlock(const QByteArray &ownerPassword, const QByteArray &userPassword);
|
|
+
|
|
+ /**
|
|
+ Determine if the document is locked
|
|
+ */
|
|
+ bool isLocked() const;
|
|
+
|
|
+ /**
|
|
+ The date associated with the document
|
|
+
|
|
+ You would use this method with something like:
|
|
+ \code
|
|
+QDateTime created = m_doc->date("CreationDate");
|
|
+QDateTime modified = m_doc->date("ModDate");
|
|
+ \endcode
|
|
+
|
|
+ The available dates are:
|
|
+ - CreationDate: the date of creation of the document
|
|
+ - ModDate: the date of the last change in the document
|
|
+
|
|
+ \param data the type of date that is required
|
|
+ */
|
|
+ QDateTime date( const QString & data ) const;
|
|
+
|
|
+ /**
|
|
+ Set the Info dict date entry specified by \param key to \param val
|
|
+
|
|
+ \returns true on success, false on failure
|
|
+ */
|
|
+ bool setDate( const QString & key, const QDateTime & val );
|
|
+
|
|
+ /**
|
|
+ The date of the creation of the document
|
|
+ */
|
|
+ QDateTime creationDate() const;
|
|
+
|
|
+ /**
|
|
+ Set the creation date of the document to \param val
|
|
+
|
|
+ \returns true on success, false on failure
|
|
+ */
|
|
+ bool setCreationDate( const QDateTime & val );
|
|
+
|
|
+ /**
|
|
+ The date of the last change in the document
|
|
+ */
|
|
+ QDateTime modificationDate() const;
|
|
+
|
|
+ /**
|
|
+ Set the modification date of the document to \param val
|
|
+
|
|
+ \returns true on success, false on failure
|
|
+ */
|
|
+ bool setModificationDate( const QDateTime & val );
|
|
+
|
|
+ /**
|
|
+ Get specified information associated with the document
|
|
+
|
|
+ You would use this method with something like:
|
|
+ \code
|
|
+QString title = m_doc->info("Title");
|
|
+QString subject = m_doc->info("Subject");
|
|
+ \endcode
|
|
+
|
|
+ In addition to \c Title and \c Subject, other information that may
|
|
+ be available include \c Author, \c Keywords, \c Creator and \c Producer.
|
|
+
|
|
+ \param data the information that is required
|
|
+
|
|
+ \sa infoKeys() to get a list of the available keys
|
|
+ */
|
|
+ QString info( const QString & data ) const;
|
|
+
|
|
+ /**
|
|
+ Set the value of the document's Info dictionary entry specified by \param key to \param val
|
|
+
|
|
+ \returns true on success, false on failure
|
|
+ */
|
|
+ bool setInfo( const QString & key, const QString & val );
|
|
+
|
|
+ /**
|
|
+ The title of the document
|
|
+ */
|
|
+ QString title() const;
|
|
+
|
|
+ /**
|
|
+ Set the title of the document to \param val
|
|
+
|
|
+ \returns true on success, false on failure
|
|
+ */
|
|
+ bool setTitle( const QString & val );
|
|
+
|
|
+ /**
|
|
+ The author of the document
|
|
+ */
|
|
+ QString author() const;
|
|
+
|
|
+ /**
|
|
+ Set the author of the document to \param val
|
|
+
|
|
+ \returns true on success, false on failure
|
|
+ */
|
|
+ bool setAuthor( const QString & val );
|
|
+
|
|
+ /**
|
|
+ The subject of the document
|
|
+ */
|
|
+ QString subject() const;
|
|
+
|
|
+ /**
|
|
+ Set the subject of the document to \param val
|
|
+
|
|
+ \returns true on success, false on failure
|
|
+ */
|
|
+ bool setSubject( const QString & val );
|
|
+
|
|
+ /**
|
|
+ The keywords of the document
|
|
+ */
|
|
+ QString keywords() const;
|
|
+
|
|
+ /**
|
|
+ Set the keywords of the document to \param val
|
|
+
|
|
+ \returns true on success, false on failure
|
|
+ */
|
|
+ bool setKeywords( const QString & val );
|
|
+
|
|
+ /**
|
|
+ The creator of the document
|
|
+ */
|
|
+ QString creator() const;
|
|
+
|
|
+ /**
|
|
+ Set the creator of the document to \param val
|
|
+
|
|
+ \returns true on success, false on failure
|
|
+ */
|
|
+ bool setCreator( const QString & val );
|
|
+
|
|
+ /**
|
|
+ The producer of the document
|
|
+ */
|
|
+ QString producer() const;
|
|
+
|
|
+ /**
|
|
+ Set the producer of the document to \param val
|
|
+
|
|
+ \returns true on success, false on failure
|
|
+ */
|
|
+ bool setProducer( const QString & val );
|
|
+
|
|
+ /**
|
|
+ Remove the document's Info dictionary
|
|
+
|
|
+ \returns true on success, false on failure
|
|
+ */
|
|
+ bool removeInfo();
|
|
+
|
|
+ /**
|
|
+ Obtain a list of the available string information keys.
|
|
+ */
|
|
+ QStringList infoKeys() const;
|
|
+
|
|
+ /**
|
|
+ Test if the document is encrypted
|
|
+ */
|
|
+ bool isEncrypted() const;
|
|
+
|
|
+ /**
|
|
+ Test if the document is linearised
|
|
+
|
|
+ In some cases, this is called "fast web view", since it
|
|
+ is mostly an optimisation for viewing over the Web.
|
|
+ */
|
|
+ bool isLinearized() const;
|
|
+
|
|
+ /**
|
|
+ Test if the permissions on the document allow it to be
|
|
+ printed
|
|
+ */
|
|
+ bool okToPrint() const;
|
|
+
|
|
+ /**
|
|
+ Test if the permissions on the document allow it to be
|
|
+ printed at high resolution
|
|
+ */
|
|
+ bool okToPrintHighRes() const;
|
|
+
|
|
+ /**
|
|
+ Test if the permissions on the document allow it to be
|
|
+ changed.
|
|
+
|
|
+ \note depending on the type of change, it may be more
|
|
+ appropriate to check other properties as well.
|
|
+ */
|
|
+ bool okToChange() const;
|
|
+
|
|
+ /**
|
|
+ Test if the permissions on the document allow the
|
|
+ contents to be copied / extracted
|
|
+ */
|
|
+ bool okToCopy() const;
|
|
+
|
|
+ /**
|
|
+ Test if the permissions on the document allow annotations
|
|
+ to be added or modified, and interactive form fields (including
|
|
+ signature fields) to be completed.
|
|
+ */
|
|
+ bool okToAddNotes() const;
|
|
+
|
|
+ /**
|
|
+ Test if the permissions on the document allow interactive
|
|
+ form fields (including signature fields) to be completed.
|
|
+
|
|
+ \note this can be true even if okToAddNotes() is false - this
|
|
+ means that only form completion is permitted.
|
|
+ */
|
|
+ bool okToFillForm() const;
|
|
+
|
|
+ /**
|
|
+ Test if the permissions on the document allow interactive
|
|
+ form fields (including signature fields) to be set, created and
|
|
+ modified
|
|
+ */
|
|
+ bool okToCreateFormFields() const;
|
|
+
|
|
+ /**
|
|
+ Test if the permissions on the document allow content extraction
|
|
+ (text and perhaps other content) for accessibility usage (eg for
|
|
+ a screen reader)
|
|
+ */
|
|
+ bool okToExtractForAccessibility() const;
|
|
+
|
|
+ /**
|
|
+ Test if the permissions on the document allow it to be
|
|
+ "assembled" - insertion, rotation and deletion of pages;
|
|
+ or creation of bookmarks and thumbnail images.
|
|
+
|
|
+ \note this can be true even if okToChange() is false
|
|
+ */
|
|
+ bool okToAssemble() const;
|
|
+
|
|
+ /**
|
|
+ The version of the PDF specification that the document
|
|
+ conforms to
|
|
+
|
|
+ \deprecated use getPdfVersion and avoid float point
|
|
+ comparisons/handling
|
|
+ */
|
|
+ Q_DECL_DEPRECATED double pdfVersion() const;
|
|
+
|
|
+ /**
|
|
+ The version of the PDF specification that the document
|
|
+ conforms to
|
|
+
|
|
+ \param major an optional pointer to a variable where store the
|
|
+ "major" number of the version
|
|
+ \param minor an optional pointer to a variable where store the
|
|
+ "minor" number of the version
|
|
+
|
|
+ \since 0.12
|
|
+ */
|
|
+ void getPdfVersion(int *major, int *minor) const;
|
|
+
|
|
+ /**
|
|
+ The fonts within the PDF document.
|
|
+
|
|
+ This is a shorthand for getting all the fonts at once.
|
|
+
|
|
+ \note this can take a very long time to run with a large
|
|
+ document. You may wish to use a FontIterator if you have more
|
|
+ than say 20 pages
|
|
+
|
|
+ \see newFontIterator()
|
|
+ */
|
|
+ QList<FontInfo> fonts() const;
|
|
+
|
|
+ /**
|
|
+ Scans for fonts within the PDF document.
|
|
+
|
|
+ \param numPages the number of pages to scan
|
|
+ \param fontList pointer to the list where the font information
|
|
+ should be placed
|
|
+
|
|
+ \note with this method you can scan for fonts only \em once for each
|
|
+ document; once the end is reached, no more scanning with this method
|
|
+ can be done
|
|
+
|
|
+ \return false if the end of the document has been reached
|
|
+
|
|
+ \deprecated this function is quite limited in its job (see note),
|
|
+ better use fonts() or newFontIterator()
|
|
+
|
|
+ \see fonts(), newFontIterator()
|
|
+ */
|
|
+ Q_DECL_DEPRECATED bool scanForFonts( int numPages, QList<FontInfo> *fontList ) const;
|
|
+
|
|
+ /**
|
|
+ Creates a new FontIterator object for font scanning.
|
|
+
|
|
+ The new iterator can be used for reading the font information of the
|
|
+ document, reading page by page.
|
|
+
|
|
+ The caller is responsible for the returned object, ie it should freed
|
|
+ it when no more useful.
|
|
+
|
|
+ \param startPage the initial page from which start reading fonts
|
|
+
|
|
+ \see fonts()
|
|
+
|
|
+ \since 0.12
|
|
+ */
|
|
+ FontIterator* newFontIterator( int startPage = 0 ) const;
|
|
+
|
|
+ /**
|
|
+ The font data if the font is an embedded one.
|
|
+
|
|
+ \since 0.10
|
|
+ */
|
|
+ QByteArray fontData(const FontInfo &font) const;
|
|
+
|
|
+ /**
|
|
+ The documents embedded within the PDF document.
|
|
+
|
|
+ \note there are two types of embedded document - this call
|
|
+ only accesses documents that are embedded at the document level.
|
|
+ */
|
|
+ QList<EmbeddedFile*> embeddedFiles() const;
|
|
+
|
|
+ /**
|
|
+ Whether there are any documents embedded in this PDF document.
|
|
+ */
|
|
+ bool hasEmbeddedFiles() const;
|
|
+
|
|
+ /**
|
|
+ Gets the table of contents (TOC) of the Document.
|
|
+
|
|
+ The caller is responsable for the returned object.
|
|
+
|
|
+ In the tree the tag name is the 'screen' name of the entry. A tag can have
|
|
+ attributes. Here follows the list of tag attributes with meaning:
|
|
+ - Destination: A string description of the referred destination
|
|
+ - DestinationName: A 'named reference' to the viewport
|
|
+ - ExternalFileName: A link to a external filename
|
|
+ - Open: A bool value that tells whether the subbranch of the item is open or not
|
|
+
|
|
+ Resolving the final destination for each item can be done in the following way:
|
|
+ - first, checking for 'Destination': if not empty, then a LinkDestination
|
|
+ can be constructed straight with it
|
|
+ - as second step, if the 'DestinationName' is not empty, then the destination
|
|
+ can be resolved using linkDestination()
|
|
+
|
|
+ Note also that if 'ExternalFileName' is not emtpy, then the destination refers
|
|
+ to that document (and not to the current one).
|
|
+
|
|
+ \returns the TOC, or NULL if the Document does not have one
|
|
+ */
|
|
+ QDomDocument *toc() const;
|
|
+
|
|
+ /**
|
|
+ Tries to resolve the named destination \p name.
|
|
+
|
|
+ \note this operation starts a search through the whole document
|
|
+
|
|
+ \returns a new LinkDestination object if the named destination was
|
|
+ actually found, or NULL otherwise
|
|
+ */
|
|
+ LinkDestination *linkDestination( const QString &name );
|
|
+
|
|
+ /**
|
|
+ Sets the paper color
|
|
+
|
|
+ \param color the new paper color
|
|
+ */
|
|
+ void setPaperColor(const QColor &color);
|
|
+ /**
|
|
+ The paper color
|
|
+
|
|
+ The default color is white.
|
|
+ */
|
|
+ QColor paperColor() const;
|
|
+
|
|
+ /**
|
|
+ Sets the backend used to render the pages.
|
|
+
|
|
+ \param backend the new rendering backend
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ void setRenderBackend( RenderBackend backend );
|
|
+ /**
|
|
+ The currently set render backend
|
|
+
|
|
+ The default backend is \ref SplashBackend
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ RenderBackend renderBackend() const;
|
|
+
|
|
+ /**
|
|
+ The available rendering backends.
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ static QSet<RenderBackend> availableRenderBackends();
|
|
+
|
|
+ /**
|
|
+ Sets the render \p hint .
|
|
+
|
|
+ \note some hints may not be supported by some rendering backends.
|
|
+
|
|
+ \param on whether the flag should be added or removed.
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ void setRenderHint( RenderHint hint, bool on = true );
|
|
+ /**
|
|
+ The currently set render hints.
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ RenderHints renderHints() const;
|
|
+
|
|
+ /**
|
|
+ Gets a new PS converter for this document.
|
|
+
|
|
+ The caller gets the ownership of the returned converter.
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ PSConverter *psConverter() const;
|
|
+
|
|
+ /**
|
|
+ Gets a new PDF converter for this document.
|
|
+
|
|
+ The caller gets the ownership of the returned converter.
|
|
+
|
|
+ \since 0.8
|
|
+ */
|
|
+ PDFConverter *pdfConverter() const;
|
|
+
|
|
+ /**
|
|
+ Gets the metadata stream contents
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ QString metadata() const;
|
|
+
|
|
+ /**
|
|
+ Test whether this document has "optional content".
|
|
+
|
|
+ Optional content is used to optionally turn on (display)
|
|
+ and turn off (not display) some elements of the document.
|
|
+ The most common use of this is for layers in design
|
|
+ applications, but it can be used for a range of things,
|
|
+ such as not including some content in printing, and
|
|
+ displaying content in the appropriate language.
|
|
+
|
|
+ \since 0.8
|
|
+ */
|
|
+ bool hasOptionalContent() const;
|
|
+
|
|
+ /**
|
|
+ Itemviews model for optional content.
|
|
+
|
|
+ The model is owned by the document.
|
|
+
|
|
+ \since 0.8
|
|
+ */
|
|
+ OptContentModel *optionalContentModel();
|
|
+
|
|
+ /**
|
|
+ Document-level JavaScript scripts.
|
|
+
|
|
+ Returns the list of document level JavaScript scripts to be always
|
|
+ executed before any other script.
|
|
+
|
|
+ \since 0.10
|
|
+ */
|
|
+ QStringList scripts() const;
|
|
+
|
|
+ /**
|
|
+ The PDF identifiers.
|
|
+
|
|
+ \param permanentId an optional pointer to a variable where store the
|
|
+ permanent ID of the document
|
|
+ \param updateId an optional pointer to a variable where store the
|
|
+ update ID of the document
|
|
+
|
|
+ \return whether the document has the IDs
|
|
+
|
|
+ \since 0.16
|
|
+ */
|
|
+ bool getPdfId(QByteArray *permanentId, QByteArray *updateId) const;
|
|
+
|
|
+ /**
|
|
+ Returns the type of forms contained in the document
|
|
+
|
|
+ \since 0.22
|
|
+ */
|
|
+ FormType formType() const;
|
|
+
|
|
+ /**
|
|
+ Destructor.
|
|
+ */
|
|
+ ~Document();
|
|
+
|
|
+ private:
|
|
+ Q_DISABLE_COPY(Document)
|
|
+
|
|
+ DocumentData *m_doc;
|
|
+
|
|
+ Document(DocumentData *dataA);
|
|
+ };
|
|
+
|
|
+ class BaseConverterPrivate;
|
|
+ class PSConverterPrivate;
|
|
+ class PDFConverterPrivate;
|
|
+ /**
|
|
+ \brief Base converter.
|
|
+
|
|
+ This is the base class for the converters.
|
|
+
|
|
+ \since 0.8
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT BaseConverter
|
|
+ {
|
|
+ friend class Document;
|
|
+ public:
|
|
+ /**
|
|
+ Destructor.
|
|
+ */
|
|
+ virtual ~BaseConverter();
|
|
+
|
|
+ /** Sets the output file name. You must set this or the output device. */
|
|
+ void setOutputFileName(const QString &outputFileName);
|
|
+
|
|
+ /**
|
|
+ * Sets the output device. You must set this or the output file name.
|
|
+ *
|
|
+ * \since 0.8
|
|
+ */
|
|
+ void setOutputDevice(QIODevice *device);
|
|
+
|
|
+ /**
|
|
+ Does the conversion.
|
|
+
|
|
+ \return whether the conversion succeeded
|
|
+ */
|
|
+ virtual bool convert() = 0;
|
|
+
|
|
+ enum Error
|
|
+ {
|
|
+ NoError,
|
|
+ FileLockedError,
|
|
+ OpenOutputError,
|
|
+ NotSupportedInputFileError
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ Returns the last error
|
|
+ \since 0.12.1
|
|
+ */
|
|
+ Error lastError() const;
|
|
+
|
|
+ protected:
|
|
+ /// \cond PRIVATE
|
|
+ BaseConverter(BaseConverterPrivate &dd);
|
|
+ Q_DECLARE_PRIVATE(BaseConverter)
|
|
+ BaseConverterPrivate *d_ptr;
|
|
+ /// \endcond
|
|
+
|
|
+ private:
|
|
+ Q_DISABLE_COPY(BaseConverter)
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ Converts a PDF to PS
|
|
+
|
|
+ Sizes have to be in Points (1/72 inch)
|
|
+
|
|
+ If you are using QPrinter you can get paper size by doing:
|
|
+ \code
|
|
+QPrinter dummy(QPrinter::PrinterResolution);
|
|
+dummy.setFullPage(true);
|
|
+dummy.setPageSize(myPageSize);
|
|
+width = dummy.width();
|
|
+height = dummy.height();
|
|
+ \endcode
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT PSConverter : public BaseConverter
|
|
+ {
|
|
+ friend class Document;
|
|
+ public:
|
|
+ /**
|
|
+ Options for the PS export.
|
|
+
|
|
+ \since 0.10
|
|
+ */
|
|
+ enum PSOption {
|
|
+ Printing = 0x00000001, ///< The PS is generated for printing purposes
|
|
+ StrictMargins = 0x00000002,
|
|
+ ForceRasterization = 0x00000004,
|
|
+ PrintToEPS = 0x00000008, ///< Output EPS instead of PS \since 0.20
|
|
+ HideAnnotations = 0x00000010 ///< Don't print annotations \since 0.20
|
|
+ };
|
|
+ Q_DECLARE_FLAGS( PSOptions, PSOption )
|
|
+
|
|
+ /**
|
|
+ Destructor.
|
|
+ */
|
|
+ ~PSConverter();
|
|
+
|
|
+ /** Sets the list of pages to print. Mandatory. */
|
|
+ void setPageList(const QList<int> &pageList);
|
|
+
|
|
+ /**
|
|
+ Sets the title of the PS Document. Optional
|
|
+ */
|
|
+ void setTitle(const QString &title);
|
|
+
|
|
+ /**
|
|
+ Sets the horizontal DPI. Defaults to 72.0
|
|
+ */
|
|
+ void setHDPI(double hDPI);
|
|
+
|
|
+ /**
|
|
+ Sets the vertical DPI. Defaults to 72.0
|
|
+ */
|
|
+ void setVDPI(double vDPI);
|
|
+
|
|
+ /**
|
|
+ Sets the rotate. Defaults to not rotated
|
|
+ */
|
|
+ void setRotate(int rotate);
|
|
+
|
|
+ /**
|
|
+ Sets the output paper width. Has to be set.
|
|
+ */
|
|
+ void setPaperWidth(int paperWidth);
|
|
+
|
|
+ /**
|
|
+ Sets the output paper height. Has to be set.
|
|
+ */
|
|
+ void setPaperHeight(int paperHeight);
|
|
+
|
|
+ /**
|
|
+ Sets the output right margin. Defaults to 0
|
|
+ */
|
|
+ void setRightMargin(int marginRight);
|
|
+
|
|
+ /**
|
|
+ Sets the output bottom margin. Defaults to 0
|
|
+ */
|
|
+ void setBottomMargin(int marginBottom);
|
|
+
|
|
+ /**
|
|
+ Sets the output left margin. Defaults to 0
|
|
+ */
|
|
+ void setLeftMargin(int marginLeft);
|
|
+
|
|
+ /**
|
|
+ Sets the output top margin. Defaults to 0
|
|
+ */
|
|
+ void setTopMargin(int marginTop);
|
|
+
|
|
+ /**
|
|
+ Defines if margins have to be strictly followed (even if that
|
|
+ means changing aspect ratio), or if the margins can be adapted
|
|
+ to keep aspect ratio.
|
|
+
|
|
+ Defaults to false.
|
|
+ */
|
|
+ void setStrictMargins(bool strictMargins);
|
|
+
|
|
+ /** Defines if the page will be rasterized to an image before printing. Defaults to false */
|
|
+ void setForceRasterize(bool forceRasterize);
|
|
+
|
|
+ /**
|
|
+ Sets the options for the PS export.
|
|
+
|
|
+ \since 0.10
|
|
+ */
|
|
+ void setPSOptions(PSOptions options);
|
|
+
|
|
+ /**
|
|
+ The currently set options for the PS export.
|
|
+
|
|
+ The default flags are: Printing.
|
|
+
|
|
+ \since 0.10
|
|
+ */
|
|
+ PSOptions psOptions() const;
|
|
+
|
|
+ /**
|
|
+ Sets a function that will be called each time a page is converted.
|
|
+
|
|
+ The payload belongs to the caller.
|
|
+
|
|
+ \since 0.16
|
|
+ */
|
|
+ void setPageConvertedCallback(void (* callback)(int page, void *payload), void *payload);
|
|
+
|
|
+ bool convert();
|
|
+
|
|
+ private:
|
|
+ Q_DECLARE_PRIVATE(PSConverter)
|
|
+ Q_DISABLE_COPY(PSConverter)
|
|
+
|
|
+ PSConverter(DocumentData *document);
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ Converts a PDF to PDF (thus saves a copy of the document).
|
|
+
|
|
+ \since 0.8
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT PDFConverter : public BaseConverter
|
|
+ {
|
|
+ friend class Document;
|
|
+ public:
|
|
+ /**
|
|
+ Options for the PDF export.
|
|
+ */
|
|
+ enum PDFOption {
|
|
+ WithChanges = 0x00000001 ///< The changes done to the document are saved as well
|
|
+ };
|
|
+ Q_DECLARE_FLAGS( PDFOptions, PDFOption )
|
|
+
|
|
+ /**
|
|
+ Destructor.
|
|
+ */
|
|
+ virtual ~PDFConverter();
|
|
+
|
|
+ /**
|
|
+ Sets the options for the PDF export.
|
|
+ */
|
|
+ void setPDFOptions(PDFOptions options);
|
|
+ /**
|
|
+ The currently set options for the PDF export.
|
|
+ */
|
|
+ PDFOptions pdfOptions() const;
|
|
+
|
|
+ bool convert();
|
|
+
|
|
+ private:
|
|
+ Q_DECLARE_PRIVATE(PDFConverter)
|
|
+ Q_DISABLE_COPY(PDFConverter)
|
|
+
|
|
+ PDFConverter(DocumentData *document);
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ Conversion from PDF date string format to QDateTime
|
|
+ */
|
|
+ POPPLER_QT4_EXPORT QDateTime convertDate( char *dateString );
|
|
+
|
|
+ /**
|
|
+ Whether the color management functions are available.
|
|
+
|
|
+ \since 0.12
|
|
+ */
|
|
+ POPPLER_QT4_EXPORT bool isCmsAvailable();
|
|
+
|
|
+ /**
|
|
+ Whether the overprint preview functionality is available.
|
|
+
|
|
+ \since 0.22
|
|
+ */
|
|
+ POPPLER_QT4_EXPORT bool isOverprintPreviewAvailable();
|
|
+
|
|
+ class SoundData;
|
|
+ /**
|
|
+ Container class for a sound file in a PDF document.
|
|
+
|
|
+ A sound can be either External (in that case should be loaded the file
|
|
+ whose url is represented by url() ), or Embedded, and the player has to
|
|
+ play the data contained in data().
|
|
+
|
|
+ \since 0.6
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT SoundObject {
|
|
+ public:
|
|
+ /**
|
|
+ The type of sound
|
|
+ */
|
|
+ enum SoundType {
|
|
+ External, ///< The real sound file is external
|
|
+ Embedded ///< The sound is contained in the data
|
|
+ };
|
|
+
|
|
+ /**
|
|
+ The encoding format used for the sound
|
|
+ */
|
|
+ enum SoundEncoding {
|
|
+ Raw, ///< Raw encoding, with unspecified or unsigned values in the range [ 0, 2^B - 1 ]
|
|
+ Signed, ///< Twos-complement values
|
|
+ muLaw, ///< mu-law-encoded samples
|
|
+ ALaw ///< A-law-encoded samples
|
|
+ };
|
|
+
|
|
+ /// \cond PRIVATE
|
|
+ SoundObject(Sound *popplersound);
|
|
+ /// \endcond
|
|
+
|
|
+ ~SoundObject();
|
|
+
|
|
+ /**
|
|
+ Is the sound embedded (SoundObject::Embedded) or external (SoundObject::External)?
|
|
+ */
|
|
+ SoundType soundType() const;
|
|
+
|
|
+ /**
|
|
+ The URL of the sound file to be played, in case of SoundObject::External
|
|
+ */
|
|
+ QString url() const;
|
|
+
|
|
+ /**
|
|
+ The data of the sound, in case of SoundObject::Embedded
|
|
+ */
|
|
+ QByteArray data() const;
|
|
+
|
|
+ /**
|
|
+ The sampling rate of the sound
|
|
+ */
|
|
+ double samplingRate() const;
|
|
+
|
|
+ /**
|
|
+ The number of sound channels to use to play the sound
|
|
+ */
|
|
+ int channels() const;
|
|
+
|
|
+ /**
|
|
+ The number of bits per sample value per channel
|
|
+ */
|
|
+ int bitsPerSample() const;
|
|
+
|
|
+ /**
|
|
+ The encoding used for the sound
|
|
+ */
|
|
+ SoundEncoding soundEncoding() const;
|
|
+
|
|
+ private:
|
|
+ Q_DISABLE_COPY(SoundObject)
|
|
+
|
|
+ SoundData *m_soundData;
|
|
+ };
|
|
+
|
|
+ class MovieData;
|
|
+ /**
|
|
+ Container class for a movie object in a PDF document.
|
|
+
|
|
+ \since 0.10
|
|
+ */
|
|
+ class POPPLER_QT4_EXPORT MovieObject {
|
|
+ friend class AnnotationPrivate;
|
|
+ public:
|
|
+ /**
|
|
+ The play mode for playing the movie
|
|
+ */
|
|
+ enum PlayMode {
|
|
+ PlayOnce, ///< Play the movie once, closing the movie controls at the end
|
|
+ PlayOpen, ///< Like PlayOnce, but leaving the controls open
|
|
+ PlayRepeat, ///< Play continuously until stopped
|
|
+ PlayPalindrome ///< Play forward, then backward, then again foward and so on until stopped
|
|
+ };
|
|
+
|
|
+ ~MovieObject();
|
|
+
|
|
+ /**
|
|
+ The URL of the movie to be played
|
|
+ */
|
|
+ QString url() const;
|
|
+
|
|
+ /**
|
|
+ The size of the movie
|
|
+ */
|
|
+ QSize size() const;
|
|
+
|
|
+ /**
|
|
+ The rotation (either 0, 90, 180, or 270 degrees clockwise) for the movie,
|
|
+ */
|
|
+ int rotation() const;
|
|
+
|
|
+ /**
|
|
+ Whether show a bar with movie controls
|
|
+ */
|
|
+ bool showControls() const;
|
|
+
|
|
+ /**
|
|
+ How to play the movie
|
|
+ */
|
|
+ PlayMode playMode() const;
|
|
+
|
|
+ /**
|
|
+ Returns whether a poster image should be shown if the movie is not playing.
|
|
+ \since 0.22
|
|
+ */
|
|
+ bool showPosterImage() const;
|
|
+
|
|
+ /**
|
|
+ Returns the poster image that should be shown if the movie is not playing.
|
|
+ If the image is null but showImagePoster() returns @c true, the first frame of the movie
|
|
+ should be used as poster image.
|
|
+ \since 0.22
|
|
+ */
|
|
+ QImage posterImage() const;
|
|
+
|
|
+ private:
|
|
+ /// \cond PRIVATE
|
|
+ MovieObject( AnnotMovie *ann );
|
|
+ /// \endcond
|
|
+
|
|
+ Q_DISABLE_COPY(MovieObject)
|
|
+
|
|
+ MovieData *m_movieData;
|
|
+ };
|
|
+
|
|
+}
|
|
+
|
|
+Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::Page::PainterFlags)
|
|
+Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::Page::SearchFlags)
|
|
+Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::Document::RenderHints)
|
|
+Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::PDFConverter::PDFOptions)
|
|
+Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::PSConverter::PSOptions)
|
|
+
|
|
+#endif
|
|
diff --git a/qt4/src/poppler-sound.cc b/qt4/src/poppler-sound.cc
|
|
new file mode 100644
|
|
index 00000000..eb19b9d3
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-sound.cc
|
|
@@ -0,0 +1,132 @@
|
|
+/* poppler-sound.cc: qt interface to poppler
|
|
+ * Copyright (C) 2006-2007, Pino Toscano <pino@kde.org>
|
|
+ * Copyright (C) 2008, Albert Astals Cid <aacid@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-qt4.h"
|
|
+
|
|
+#include "Object.h"
|
|
+#include "Stream.h"
|
|
+#include "Sound.h"
|
|
+
|
|
+namespace Poppler
|
|
+{
|
|
+
|
|
+class SoundData
|
|
+{
|
|
+public:
|
|
+ SoundData()
|
|
+ : m_soundObj( 0 )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ ~SoundData()
|
|
+ {
|
|
+ delete m_soundObj;
|
|
+ }
|
|
+
|
|
+ SoundObject::SoundType m_type;
|
|
+ Sound *m_soundObj;
|
|
+};
|
|
+
|
|
+SoundObject::SoundObject(Sound *popplersound)
|
|
+{
|
|
+ m_soundData = new SoundData();
|
|
+ switch ( popplersound->getSoundKind() )
|
|
+ {
|
|
+ case soundEmbedded:
|
|
+ m_soundData->m_type = SoundObject::Embedded;
|
|
+ break;
|
|
+ case soundExternal:
|
|
+ default:
|
|
+ m_soundData->m_type = SoundObject::External;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ m_soundData->m_soundObj = popplersound->copy();
|
|
+}
|
|
+
|
|
+SoundObject::~SoundObject()
|
|
+{
|
|
+ delete m_soundData;
|
|
+}
|
|
+
|
|
+SoundObject::SoundType SoundObject::soundType() const
|
|
+{
|
|
+ return m_soundData->m_type;
|
|
+}
|
|
+
|
|
+QString SoundObject::url() const
|
|
+{
|
|
+ if ( m_soundData->m_type != SoundObject::External )
|
|
+ return QString();
|
|
+
|
|
+ GooString * goo = m_soundData->m_soundObj->getFileName();
|
|
+ return goo ? QString( goo->c_str() ) : QString();
|
|
+}
|
|
+
|
|
+QByteArray SoundObject::data() const
|
|
+{
|
|
+ if ( m_soundData->m_type != SoundObject::Embedded )
|
|
+ return QByteArray();
|
|
+
|
|
+ Stream *stream = m_soundData->m_soundObj->getStream();
|
|
+ stream->reset();
|
|
+ int dataLen = 0;
|
|
+ QByteArray fileArray;
|
|
+ int i;
|
|
+ while ( (i = stream->getChar()) != EOF) {
|
|
+ fileArray[dataLen] = (char)i;
|
|
+ ++dataLen;
|
|
+ }
|
|
+ fileArray.resize(dataLen);
|
|
+
|
|
+ return fileArray;
|
|
+}
|
|
+
|
|
+double SoundObject::samplingRate() const
|
|
+{
|
|
+ return m_soundData->m_soundObj->getSamplingRate();
|
|
+}
|
|
+
|
|
+int SoundObject::channels() const
|
|
+{
|
|
+ return m_soundData->m_soundObj->getChannels();
|
|
+}
|
|
+
|
|
+int SoundObject::bitsPerSample() const
|
|
+{
|
|
+ return m_soundData->m_soundObj->getBitsPerSample();
|
|
+}
|
|
+
|
|
+SoundObject::SoundEncoding SoundObject::soundEncoding() const
|
|
+{
|
|
+ switch ( m_soundData->m_soundObj->getEncoding() )
|
|
+ {
|
|
+ case soundRaw:
|
|
+ return SoundObject::Raw;
|
|
+ case soundSigned:
|
|
+ return SoundObject::Signed;
|
|
+ case soundMuLaw:
|
|
+ return SoundObject::muLaw;
|
|
+ case soundALaw:
|
|
+ return SoundObject::ALaw;
|
|
+ }
|
|
+ return SoundObject::Raw;
|
|
+}
|
|
+
|
|
+}
|
|
diff --git a/qt4/src/poppler-textbox.cc b/qt4/src/poppler-textbox.cc
|
|
new file mode 100644
|
|
index 00000000..88cf2a9e
|
|
--- /dev/null
|
|
+++ b/qt4/src/poppler-textbox.cc
|
|
@@ -0,0 +1,63 @@
|
|
+/* poppler-qt.h: qt interface to poppler
|
|
+ * Copyright (C) 2005, Brad Hards <bradh@frogmouth.net>
|
|
+ * Copyright (C) 2006-2008, Albert Astals Cid <aacid@kde.org>
|
|
+ * Copyright (C) 2008, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include "poppler-qt4.h"
|
|
+#include "poppler-private.h"
|
|
+
|
|
+namespace Poppler {
|
|
+
|
|
+TextBox::TextBox(const QString& text, const QRectF &bBox)
|
|
+{
|
|
+ m_data = new TextBoxData();
|
|
+ m_data->text = text;
|
|
+ m_data->bBox = bBox;
|
|
+}
|
|
+
|
|
+TextBox::~TextBox()
|
|
+{
|
|
+ delete m_data;
|
|
+}
|
|
+
|
|
+QString TextBox::text() const
|
|
+{
|
|
+ return m_data->text;
|
|
+}
|
|
+
|
|
+QRectF TextBox::boundingBox() const
|
|
+{
|
|
+ return m_data->bBox;
|
|
+}
|
|
+
|
|
+TextBox *TextBox::nextWord() const
|
|
+{
|
|
+ return m_data->nextWord;
|
|
+}
|
|
+
|
|
+QRectF TextBox::charBoundingBox(int i) const
|
|
+{
|
|
+ return m_data->charBBoxes.value(i);
|
|
+}
|
|
+
|
|
+bool TextBox::hasSpaceAfter() const
|
|
+{
|
|
+ return m_data->hasSpaceAfter;
|
|
+}
|
|
+
|
|
+}
|
|
diff --git a/qt4/tests/.gitignore b/qt4/tests/.gitignore
|
|
new file mode 100644
|
|
index 00000000..3746eb87
|
|
--- /dev/null
|
|
+++ b/qt4/tests/.gitignore
|
|
@@ -0,0 +1,33 @@
|
|
+.deps
|
|
+.libs
|
|
+*.la
|
|
+*.lo
|
|
+*.moc
|
|
+Makefile
|
|
+Makefile.in
|
|
+stress-poppler-qt4
|
|
+stress-poppler-dir
|
|
+test-poppler-qt4
|
|
+test-password-qt4
|
|
+poppler-attachments
|
|
+poppler-fonts
|
|
+poppler-texts
|
|
+poppler-forms
|
|
+stress-threads-qt4
|
|
+test-render-to-file
|
|
+check_actualtext
|
|
+check_attachments
|
|
+check_dateConversion
|
|
+check_fonts
|
|
+check_goostring
|
|
+check_lexer
|
|
+check_links
|
|
+check_metadata
|
|
+check_optcontent
|
|
+check_permissions
|
|
+check_pagelayout
|
|
+check_pagemode
|
|
+check_password
|
|
+check_search
|
|
+check_strings
|
|
+
|
|
diff --git a/qt4/tests/CMakeLists.txt b/qt4/tests/CMakeLists.txt
|
|
new file mode 100644
|
|
index 00000000..a01a638a
|
|
--- /dev/null
|
|
+++ b/qt4/tests/CMakeLists.txt
|
|
@@ -0,0 +1,67 @@
|
|
+add_definitions(${QT4_DEFINITIONS})
|
|
+add_definitions(-DTESTDATADIR=\"${TESTDATADIR}\")
|
|
+
|
|
+include_directories(
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../src
|
|
+ ${CMAKE_CURRENT_BINARY_DIR}
|
|
+ ${QT4_INCLUDE_DIR}
|
|
+)
|
|
+
|
|
+macro(QT4_ADD_SIMPLETEST exe source)
|
|
+ string(REPLACE "-" "" test_name ${exe})
|
|
+ set(${test_name}_SOURCES
|
|
+ ${source}
|
|
+ )
|
|
+ poppler_add_test(${exe} BUILD_QT4_TESTS ${${test_name}_SOURCES})
|
|
+ target_link_libraries(${exe} poppler-qt4)
|
|
+ if(MSVC)
|
|
+ target_link_libraries(${exe} poppler ${poppler_LIBS})
|
|
+ endif()
|
|
+endmacro(QT4_ADD_SIMPLETEST)
|
|
+
|
|
+macro(QT4_ADD_QTEST exe source)
|
|
+ if (QT4_QTTEST_FOUND)
|
|
+ string(REPLACE "-" "" test_name ${exe})
|
|
+ set(${test_name}_SOURCES
|
|
+ ${source}
|
|
+ )
|
|
+ poppler_add_unittest(${exe} BUILD_QT4_TESTS ${${test_name}_SOURCES})
|
|
+ qt4_automoc(${${test_name}_SOURCES})
|
|
+ target_link_libraries(${exe} poppler-qt4 ${QT4_QTTEST_LIBRARY})
|
|
+ if(MSVC)
|
|
+ target_link_libraries(${exe} poppler ${poppler_LIBS})
|
|
+ endif()
|
|
+ endif ()
|
|
+endmacro(QT4_ADD_QTEST)
|
|
+
|
|
+
|
|
+qt4_add_simpletest(test-poppler-qt4 test-poppler-qt4.cpp)
|
|
+qt4_add_simpletest(test-password-qt4 test-password-qt4.cpp)
|
|
+qt4_add_simpletest(test-render-to-file-qt4 test-render-to-file.cpp)
|
|
+qt4_add_simpletest(poppler-qt4-forms poppler-forms.cpp)
|
|
+qt4_add_simpletest(poppler-qt4-fonts poppler-fonts.cpp)
|
|
+qt4_add_simpletest(poppler-qt4-attachments poppler-attachments.cpp)
|
|
+qt4_add_simpletest(stress-poppler-qt4 stress-poppler-qt4.cpp)
|
|
+qt4_add_simpletest(stress-poppler-dir-qt4 stress-poppler-dir.cpp)
|
|
+qt4_add_simpletest(stress-threads-qt4 stress-threads-qt4.cpp)
|
|
+qt4_add_simpletest(poppler-qt4-texts poppler-texts.cpp)
|
|
+
|
|
+qt4_add_qtest(check_qt4_attachments check_attachments.cpp)
|
|
+qt4_add_qtest(check_qt4_dateConversion check_dateConversion.cpp)
|
|
+qt4_add_qtest(check_qt4_fonts check_fonts.cpp)
|
|
+qt4_add_qtest(check_qt4_links check_links.cpp)
|
|
+qt4_add_qtest(check_qt4_metadata check_metadata.cpp)
|
|
+qt4_add_qtest(check_qt4_optcontent check_optcontent.cpp)
|
|
+qt4_add_qtest(check_qt4_pagelayout check_pagelayout.cpp)
|
|
+qt4_add_qtest(check_qt4_pagemode check_pagemode.cpp)
|
|
+qt4_add_qtest(check_qt4_password check_password.cpp)
|
|
+qt4_add_qtest(check_qt4_permissions check_permissions.cpp)
|
|
+qt4_add_qtest(check_qt4_search check_search.cpp)
|
|
+qt4_add_qtest(check_qt4_actualtext check_actualtext.cpp)
|
|
+qt4_add_qtest(check_qt4_lexer check_lexer.cpp)
|
|
+qt4_add_qtest(check_qt4_pagelabelinfo check_pagelabelinfo.cpp)
|
|
+qt4_add_qtest(check_qt4_goostring check_goostring.cpp)
|
|
+if (NOT WIN32)
|
|
+ qt4_add_qtest(check_qt4_strings check_strings.cpp)
|
|
+endif ()
|
|
diff --git a/qt4/tests/README.unittest b/qt4/tests/README.unittest
|
|
new file mode 100644
|
|
index 00000000..02296e08
|
|
--- /dev/null
|
|
+++ b/qt4/tests/README.unittest
|
|
@@ -0,0 +1,23 @@
|
|
+The unittests for the Qt4 bindings rely on the QtTestLib package, and
|
|
+will not be built until this is installed. If you do not have it, then
|
|
+you can download it from the Trolltech website.
|
|
+
|
|
+Note that there are a range of ways in which you can run the tests:
|
|
+1. "make check" will run all the tests.
|
|
+2. You can run a single test by executing the applicable
|
|
+executable. For example, you can run the PageMode tests by
|
|
+"./check_pagemode"
|
|
+3. You can run a single function within a single test by appending the
|
|
+name of the function to the executable. For example, if you just want
|
|
+to run the FullScreen test within the PageMode tests, you can
|
|
+"./check_pagemode checkFullScreen". Run the executable with -functions
|
|
+to get a list of all the functions.
|
|
+4. You can run a single function with specific data by appending the
|
|
+name of the function, followed by a colon, then the data label to the
|
|
+executable. For example, to just do the Author check within the
|
|
+metadata checks, you can "./check_metadata checkStrings:Author".
|
|
+
|
|
+For a full list of options, run a executable with "-help".
|
|
+
|
|
+Brad Hards
|
|
+bradh@frogmouth.net
|
|
diff --git a/qt4/tests/check_actualtext.cpp b/qt4/tests/check_actualtext.cpp
|
|
new file mode 100644
|
|
index 00000000..5c765c51
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_actualtext.cpp
|
|
@@ -0,0 +1,33 @@
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <QtCore/QFile>
|
|
+
|
|
+class TestActualText: public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void checkActualText1();
|
|
+};
|
|
+
|
|
+void TestActualText::checkActualText1()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/WithActualText.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ Poppler::Page *page = doc->page(0);
|
|
+ QVERIFY( page );
|
|
+
|
|
+ QCOMPARE( page->text(QRectF()), QString("The slow brown fox jumps over the black dog.") );
|
|
+
|
|
+ delete page;
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestActualText)
|
|
+
|
|
+#include "check_actualtext.moc"
|
|
+
|
|
diff --git a/qt4/tests/check_attachments.cpp b/qt4/tests/check_attachments.cpp
|
|
new file mode 100644
|
|
index 00000000..73e31502
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_attachments.cpp
|
|
@@ -0,0 +1,157 @@
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <QtCore/QFile>
|
|
+
|
|
+class TestAttachments: public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void checkNoAttachments();
|
|
+ void checkAttach1();
|
|
+ void checkAttach2();
|
|
+ void checkAttach3();
|
|
+ void checkAttach4();
|
|
+};
|
|
+
|
|
+void TestAttachments::checkNoAttachments()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/truetype.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QCOMPARE( doc->hasEmbeddedFiles(), false );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestAttachments::checkAttach1()
|
|
+{
|
|
+
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/WithAttachments.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QVERIFY( doc->hasEmbeddedFiles() );
|
|
+
|
|
+ QList<Poppler::EmbeddedFile*> fileList = doc->embeddedFiles();
|
|
+ QCOMPARE( fileList.size(), 2 );
|
|
+
|
|
+ Poppler::EmbeddedFile *embfile = fileList.at(0);
|
|
+ QCOMPARE( embfile->name(), QString( "kroller.png" ) );
|
|
+ QCOMPARE( embfile->description(), QString() );
|
|
+ QCOMPARE( embfile->createDate(), QDateTime( QDate(), QTime() ) );
|
|
+ QCOMPARE( embfile->modDate(), QDateTime( QDate(), QTime() ) );
|
|
+ QCOMPARE( embfile->mimeType(), QString() );
|
|
+
|
|
+ QFile file(TESTDATADIR "/unittestcases/kroller.png" );
|
|
+ QVERIFY( file.open( QIODevice::ReadOnly ) );
|
|
+ QByteArray krollerData = file.readAll();
|
|
+ QByteArray embdata = embfile->data();
|
|
+ QCOMPARE( krollerData, embdata );
|
|
+
|
|
+
|
|
+ Poppler::EmbeddedFile *embfile2 = fileList.at(1);
|
|
+ QCOMPARE( embfile2->name(), QString("gnome-64.gif") );
|
|
+ QCOMPARE( embfile2->description(), QString() );
|
|
+ QCOMPARE( embfile2->modDate(), QDateTime( QDate(), QTime() ) );
|
|
+ QCOMPARE( embfile2->createDate(), QDateTime( QDate(), QTime() ) );
|
|
+ QCOMPARE( embfile2->mimeType(), QString() );
|
|
+
|
|
+ QFile file2(TESTDATADIR "/unittestcases/gnome-64.gif" );
|
|
+ QVERIFY( file2.open( QIODevice::ReadOnly ) );
|
|
+ QByteArray g64Data = file2.readAll();
|
|
+ QByteArray emb2data = embfile2->data();
|
|
+ QCOMPARE( g64Data, emb2data );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+
|
|
+void TestAttachments::checkAttach2()
|
|
+{
|
|
+
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/A6EmbeddedFiles.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QVERIFY( doc->hasEmbeddedFiles() );
|
|
+
|
|
+ QList<Poppler::EmbeddedFile*> fileList;
|
|
+ fileList = doc->embeddedFiles();
|
|
+ QCOMPARE( fileList.size(), 3 );
|
|
+
|
|
+ Poppler::EmbeddedFile *embfile1 = fileList.at(0);
|
|
+ QCOMPARE( embfile1->name(), QString("Acro7 thoughts") );
|
|
+ QCOMPARE( embfile1->description(), QString() );
|
|
+ QCOMPARE( embfile1->createDate(), QDateTime( QDate( 2003, 8, 4 ), QTime( 13, 54, 54), Qt::UTC ) );
|
|
+ QCOMPARE( embfile1->modDate(), QDateTime( QDate( 2003, 8, 4 ), QTime( 14, 15, 27), Qt::UTC ) );
|
|
+ QCOMPARE( embfile1->mimeType(), QString("text/xml") );
|
|
+
|
|
+ Poppler::EmbeddedFile *embfile2 = fileList.at(1);
|
|
+ QCOMPARE( embfile2->name(), QString("acro transitions 1.xls") );
|
|
+ QCOMPARE( embfile2->description(), QString() );
|
|
+ QCOMPARE( embfile2->createDate(), QDateTime( QDate( 2003, 7, 18 ), QTime( 21, 7, 16), Qt::UTC ) );
|
|
+ QCOMPARE( embfile2->modDate(), QDateTime( QDate( 2003, 7, 22 ), QTime( 13, 4, 40), Qt::UTC ) );
|
|
+ QCOMPARE( embfile2->mimeType(), QString("application/excel") );
|
|
+
|
|
+ Poppler::EmbeddedFile *embfile3 = fileList.at(2);
|
|
+ QCOMPARE( embfile3->name(), QString("apago_pdfe_wide.gif") );
|
|
+ QCOMPARE( embfile3->description(), QString() );
|
|
+ QCOMPARE( embfile3->createDate(), QDateTime( QDate( 2003, 1, 31 ), QTime( 15, 54, 29), Qt::UTC ) );
|
|
+ QCOMPARE( embfile3->modDate(), QDateTime( QDate( 2003, 1, 31 ), QTime( 15, 52, 58), Qt::UTC ) );
|
|
+ QCOMPARE( embfile3->mimeType(), QString() );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestAttachments::checkAttach3()
|
|
+{
|
|
+
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/shapes+attachments.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QVERIFY( doc->hasEmbeddedFiles() );
|
|
+
|
|
+ QList<Poppler::EmbeddedFile*> fileList;
|
|
+ fileList = doc->embeddedFiles();
|
|
+ QCOMPARE( fileList.size(), 1 );
|
|
+
|
|
+ Poppler::EmbeddedFile *embfile = fileList.at(0);
|
|
+ QCOMPARE( embfile->name(), QString( "ADEX1.xpdf.pgp" ) );
|
|
+ QCOMPARE( embfile->description(), QString() );
|
|
+ QCOMPARE( embfile->createDate(), QDateTime( QDate( 2004, 3, 29 ), QTime( 19, 37, 16), Qt::UTC ) );
|
|
+ QCOMPARE( embfile->modDate(), QDateTime( QDate( 2004, 3, 29 ), QTime( 19, 37, 16), Qt::UTC ) );
|
|
+ QCOMPARE( embfile->mimeType(), QString() );
|
|
+ delete doc;
|
|
+
|
|
+}
|
|
+
|
|
+void TestAttachments::checkAttach4()
|
|
+{
|
|
+
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/imageretrieve+attachment.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QVERIFY( doc->hasEmbeddedFiles() );
|
|
+
|
|
+ QList<Poppler::EmbeddedFile*> fileList;
|
|
+ fileList = doc->embeddedFiles();
|
|
+ QCOMPARE( fileList.size(), 1 );
|
|
+
|
|
+ Poppler::EmbeddedFile *embfile = fileList.at(0);
|
|
+ QCOMPARE( embfile->name(), QString( "export-altona.csv" ) );
|
|
+ QCOMPARE( embfile->description(), QString("Altona Export") );
|
|
+ QCOMPARE( embfile->createDate(), QDateTime( QDate( 2005, 8, 30 ), QTime( 20, 49, 35), Qt::UTC ) );
|
|
+ QCOMPARE( embfile->modDate(), QDateTime( QDate( 2005, 8, 30 ), QTime( 20, 49, 52), Qt::UTC ) );
|
|
+ QCOMPARE( embfile->mimeType(), QString("application/vnd.ms-excel") );
|
|
+ delete doc;
|
|
+
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestAttachments)
|
|
+#include "check_attachments.moc"
|
|
+
|
|
diff --git a/qt4/tests/check_dateConversion.cpp b/qt4/tests/check_dateConversion.cpp
|
|
new file mode 100644
|
|
index 00000000..c1f84e2f
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_dateConversion.cpp
|
|
@@ -0,0 +1,142 @@
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+Q_DECLARE_METATYPE(QDate)
|
|
+Q_DECLARE_METATYPE(QTime)
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+class TestDateConv: public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void initTestCase();
|
|
+ void checkDates_data();
|
|
+ void checkDates();
|
|
+ void checkInvalidDates_data();
|
|
+ void checkInvalidDates();
|
|
+};
|
|
+
|
|
+void TestDateConv::initTestCase()
|
|
+{
|
|
+ qRegisterMetaType<QDate>("QDate");
|
|
+ qRegisterMetaType<QTime>("QTime");
|
|
+}
|
|
+
|
|
+void TestDateConv::checkDates_data()
|
|
+{
|
|
+ QTest::addColumn<QByteArray>("input");
|
|
+ QTest::addColumn<QDate>("day");
|
|
+ QTest::addColumn<QTime>("time");
|
|
+
|
|
+ // This is a typical case - all data provided
|
|
+ QTest::newRow("D:20040101121110")
|
|
+ << QByteArray("D:20040101121110Z")
|
|
+ << QDate( 2004, 1, 1)
|
|
+ << QTime( 12, 11, 10);
|
|
+
|
|
+ // The D: is strongly recommended, but optional
|
|
+ QTest::newRow("20040101121110")
|
|
+ << QByteArray("20040101121110Z")
|
|
+ << QDate( 2004, 1, 1)
|
|
+ << QTime( 12, 11, 10);
|
|
+
|
|
+ // Only the year is actually required
|
|
+ QTest::newRow("D:2006")
|
|
+ << QByteArray("D:2006")
|
|
+ << QDate( 2006, 1, 1)
|
|
+ << QTime( 0, 0, 0);
|
|
+
|
|
+ QTest::newRow("D:200602")
|
|
+ << QByteArray("D:200602")
|
|
+ << QDate( 2006, 2, 1)
|
|
+ << QTime( 0, 0, 0);
|
|
+
|
|
+ QTest::newRow("D:20060304")
|
|
+ << QByteArray("D:20060304")
|
|
+ << QDate( 2006, 3, 4)
|
|
+ << QTime( 0, 0, 0);
|
|
+
|
|
+ QTest::newRow("D:2006030405")
|
|
+ << QByteArray("D:2006030405")
|
|
+ << QDate( 2006, 3, 4)
|
|
+ << QTime( 5, 0, 0);
|
|
+
|
|
+ QTest::newRow("D:200603040512")
|
|
+ << QByteArray("D:200603040512")
|
|
+ << QDate( 2006, 3, 4)
|
|
+ << QTime( 5, 12, 0);
|
|
+
|
|
+ // If the timezone isn't specified, I assume UTC
|
|
+ QTest::newRow("D:20060304051226")
|
|
+ << QByteArray("D:20060304051226")
|
|
+ << QDate( 2006, 3, 4)
|
|
+ << QTime( 5, 12, 26);
|
|
+
|
|
+ // Check for real timezone conversions
|
|
+ QTest::newRow("D:20030131115258-04'00'")
|
|
+ << QByteArray("D:20030131115258-04'00'")
|
|
+ << QDate( 2003, 1, 31)
|
|
+ << QTime( 15, 52, 58);
|
|
+
|
|
+ QTest::newRow("D:20030131115258+05'00'")
|
|
+ << QByteArray("D:20030131115258+05'00'")
|
|
+ << QDate( 2003, 1, 31)
|
|
+ << QTime( 6, 52, 58);
|
|
+
|
|
+ // There are places that have non-hour offsets
|
|
+ // Yep, that means you Adelaide.
|
|
+ QTest::newRow("D:20030131115258+08'30'")
|
|
+ << QByteArray("D:20030131115258+08'30'")
|
|
+ << QDate( 2003, 1, 31)
|
|
+ << QTime( 3, 22, 58);
|
|
+
|
|
+ QTest::newRow("D:20030131115258-08'30'")
|
|
+ << QByteArray("D:20030131115258-08'30'")
|
|
+ << QDate( 2003, 1, 31)
|
|
+ << QTime( 20, 22, 58);
|
|
+}
|
|
+
|
|
+void TestDateConv::checkDates()
|
|
+{
|
|
+ QFETCH(QByteArray, input);
|
|
+ QFETCH(QDate, day);
|
|
+ QFETCH(QTime, time);
|
|
+
|
|
+ QCOMPARE( Poppler::convertDate(input.data()), QDateTime(day, time, Qt::UTC) );
|
|
+}
|
|
+
|
|
+void TestDateConv::checkInvalidDates_data()
|
|
+{
|
|
+ QTest::addColumn<QByteArray>("input");
|
|
+
|
|
+ // Null data
|
|
+ QTest::newRow("Null data")
|
|
+ << QByteArray();
|
|
+
|
|
+ // Empty data
|
|
+ QTest::newRow("Empty data")
|
|
+ << QByteArray("");
|
|
+
|
|
+ // Empty data
|
|
+ QTest::newRow("One character")
|
|
+ << QByteArray("D");
|
|
+
|
|
+ // Empty data
|
|
+ QTest::newRow("'D:'")
|
|
+ << QByteArray("D:");
|
|
+
|
|
+ // Empty data
|
|
+ QTest::newRow("Not a date")
|
|
+ << QByteArray("D:IAmNotAValidDate");
|
|
+}
|
|
+
|
|
+void TestDateConv::checkInvalidDates()
|
|
+{
|
|
+ QFETCH(QByteArray, input);
|
|
+
|
|
+ QCOMPARE(Poppler::convertDate(input.data()), QDateTime());
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestDateConv)
|
|
+
|
|
+#include "check_dateConversion.moc"
|
|
diff --git a/qt4/tests/check_fonts.cpp b/qt4/tests/check_fonts.cpp
|
|
new file mode 100644
|
|
index 00000000..77579a97
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_fonts.cpp
|
|
@@ -0,0 +1,248 @@
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <memory>
|
|
+
|
|
+class TestFontsData: public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void checkNoFonts();
|
|
+ void checkType1();
|
|
+ void checkType3();
|
|
+ void checkTrueType();
|
|
+ void checkFontIterator();
|
|
+ void checkSecondDocumentQuery();
|
|
+ void checkMultipleIterations();
|
|
+ void checkScanForFonts();
|
|
+};
|
|
+
|
|
+
|
|
+static QList<Poppler::FontInfo> loadFontsViaIterator( Poppler::Document *doc, int from = 0, int count = -1 )
|
|
+{
|
|
+ int num = count == -1 ? doc->numPages() - from : count;
|
|
+ QList<Poppler::FontInfo> list;
|
|
+ std::unique_ptr< Poppler::FontIterator > it( doc->newFontIterator( from ) );
|
|
+ while ( it->hasNext() && num )
|
|
+ {
|
|
+ list += it->next();
|
|
+ --num;
|
|
+ }
|
|
+ return list;
|
|
+}
|
|
+
|
|
+namespace Poppler
|
|
+{
|
|
+static bool operator==( const FontInfo &f1, const FontInfo &f2 )
|
|
+{
|
|
+ if ( f1.name() != f2.name() )
|
|
+ return false;
|
|
+ if ( f1.file() != f2.file() )
|
|
+ return false;
|
|
+ if ( f1.isEmbedded() != f2.isEmbedded() )
|
|
+ return false;
|
|
+ if ( f1.isSubset() != f2.isSubset() )
|
|
+ return false;
|
|
+ if ( f1.type() != f2.type() )
|
|
+ return false;
|
|
+ if ( f1.typeName() != f2.typeName() )
|
|
+ return false;
|
|
+ return true;
|
|
+}
|
|
+}
|
|
+
|
|
+void TestFontsData::checkNoFonts()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/tests/image.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QList<Poppler::FontInfo> listOfFonts = doc->fonts();
|
|
+ QCOMPARE( listOfFonts.size(), 0 );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestFontsData::checkType1()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/tests/text.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QList<Poppler::FontInfo> listOfFonts = doc->fonts();
|
|
+ QCOMPARE( listOfFonts.size(), 1 );
|
|
+ QCOMPARE( listOfFonts.at(0).name(), QString("Helvetica") );
|
|
+ QCOMPARE( listOfFonts.at(0).type(), Poppler::FontInfo::Type1 );
|
|
+ QCOMPARE( listOfFonts.at(0).typeName(), QString("Type 1") );
|
|
+
|
|
+ QCOMPARE( listOfFonts.at(0).isEmbedded(), false );
|
|
+ QCOMPARE( listOfFonts.at(0).isSubset(), false );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestFontsData::checkType3()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/tests/type3.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QList<Poppler::FontInfo> listOfFonts = doc->fonts();
|
|
+ QCOMPARE( listOfFonts.size(), 2 );
|
|
+ QCOMPARE( listOfFonts.at(0).name(), QString("Helvetica") );
|
|
+ QCOMPARE( listOfFonts.at(0).type(), Poppler::FontInfo::Type1 );
|
|
+ QCOMPARE( listOfFonts.at(0).typeName(), QString("Type 1") );
|
|
+
|
|
+ QCOMPARE( listOfFonts.at(0).isEmbedded(), false );
|
|
+ QCOMPARE( listOfFonts.at(0).isSubset(), false );
|
|
+
|
|
+ QCOMPARE( listOfFonts.at(1).name(), QString("") );
|
|
+ QCOMPARE( listOfFonts.at(1).type(), Poppler::FontInfo::Type3 );
|
|
+ QCOMPARE( listOfFonts.at(1).typeName(), QString("Type 3") );
|
|
+
|
|
+ QCOMPARE( listOfFonts.at(1).isEmbedded(), true );
|
|
+ QCOMPARE( listOfFonts.at(1).isSubset(), false );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestFontsData::checkTrueType()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/truetype.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QList<Poppler::FontInfo> listOfFonts = doc->fonts();
|
|
+ QCOMPARE( listOfFonts.size(), 2 );
|
|
+ QCOMPARE( listOfFonts.at(0).name(), QString("Arial-BoldMT") );
|
|
+ QCOMPARE( listOfFonts.at(0).type(), Poppler::FontInfo::TrueType );
|
|
+ QCOMPARE( listOfFonts.at(0).typeName(), QString("TrueType") );
|
|
+
|
|
+ QCOMPARE( listOfFonts.at(0).isEmbedded(), false );
|
|
+ QCOMPARE( listOfFonts.at(0).isSubset(), false );
|
|
+
|
|
+ QCOMPARE( listOfFonts.at(1).name(), QString("ArialMT") );
|
|
+ QCOMPARE( listOfFonts.at(1).type(), Poppler::FontInfo::TrueType );
|
|
+ QCOMPARE( listOfFonts.at(1).typeName(), QString("TrueType") );
|
|
+
|
|
+ QCOMPARE( listOfFonts.at(1).isEmbedded(), false );
|
|
+ QCOMPARE( listOfFonts.at(1).isSubset(), false );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestFontsData::checkFontIterator()
|
|
+{
|
|
+ // loading a 1-page document
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/tests/type3.pdf");
|
|
+ QVERIFY( doc );
|
|
+ // loading a 6-pages document
|
|
+ Poppler::Document *doc6 = Poppler::Document::load(TESTDATADIR "/tests/cropbox.pdf");
|
|
+ QVERIFY( doc6 );
|
|
+
|
|
+ std::unique_ptr< Poppler::FontIterator > it;
|
|
+
|
|
+ // some tests with the 1-page document:
|
|
+ // - check a default iterator
|
|
+ it.reset( doc->newFontIterator() );
|
|
+ QVERIFY( it->hasNext() );
|
|
+ // - check an iterator for negative pages to behave as 0
|
|
+ it.reset( doc->newFontIterator( -1 ) );
|
|
+ QVERIFY( it->hasNext() );
|
|
+ // - check an iterator for pages out of the page limit
|
|
+ it.reset( doc->newFontIterator( 1 ) );
|
|
+ QVERIFY( !it->hasNext() );
|
|
+ // - check that it reaches the end after 1 iteration
|
|
+ it.reset( doc->newFontIterator() );
|
|
+ QVERIFY( it->hasNext() );
|
|
+ it->next();
|
|
+ QVERIFY( !it->hasNext() );
|
|
+
|
|
+ // some tests with the 6-page document:
|
|
+ // - check a default iterator
|
|
+ it.reset( doc6->newFontIterator() );
|
|
+ QVERIFY( it->hasNext() );
|
|
+ // - check an iterator for pages out of the page limit
|
|
+ it.reset( doc6->newFontIterator( 6 ) );
|
|
+ QVERIFY( !it->hasNext() );
|
|
+ // - check that it reaches the end after 6 iterations
|
|
+ it.reset( doc6->newFontIterator() );
|
|
+ QVERIFY( it->hasNext() );
|
|
+ it->next();
|
|
+ QVERIFY( it->hasNext() );
|
|
+ it->next();
|
|
+ QVERIFY( it->hasNext() );
|
|
+ it->next();
|
|
+ QVERIFY( it->hasNext() );
|
|
+ it->next();
|
|
+ QVERIFY( it->hasNext() );
|
|
+ it->next();
|
|
+ QVERIFY( it->hasNext() );
|
|
+ it->next();
|
|
+ QVERIFY( !it->hasNext() );
|
|
+
|
|
+ delete doc;
|
|
+ delete doc6;
|
|
+}
|
|
+
|
|
+void TestFontsData::checkSecondDocumentQuery()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/tests/type3.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QList<Poppler::FontInfo> listOfFonts = doc->fonts();
|
|
+ QCOMPARE( listOfFonts.size(), 2 );
|
|
+ // check we get the very same result when calling fonts() again (#19405)
|
|
+ QList<Poppler::FontInfo> listOfFonts2 = doc->fonts();
|
|
+ QCOMPARE( listOfFonts, listOfFonts2 );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestFontsData::checkMultipleIterations()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/tests/type3.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QList<Poppler::FontInfo> listOfFonts = loadFontsViaIterator( doc );
|
|
+ QCOMPARE( listOfFonts.size(), 2 );
|
|
+ QList<Poppler::FontInfo> listOfFonts2 = loadFontsViaIterator( doc );
|
|
+ QCOMPARE( listOfFonts, listOfFonts2 );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestFontsData::checkScanForFonts()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/tests/fonts.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QList<Poppler::FontInfo> listOfFonts = doc->fonts();
|
|
+ QCOMPARE( listOfFonts.size(), 3 );
|
|
+ // check we get the very same result when gatering fonts using scanForFonts
|
|
+ QList<Poppler::FontInfo> listOfFonts2;
|
|
+ for ( int i = 0; i < doc->numPages(); ++i )
|
|
+ {
|
|
+ doc->scanForFonts( 1, &listOfFonts2 );
|
|
+ }
|
|
+ QCOMPARE( listOfFonts, listOfFonts2 );
|
|
+
|
|
+ // check doing a second scanForFonts gives no result
|
|
+ QList<Poppler::FontInfo> listOfFonts3;
|
|
+ for ( int i = 0; i < doc->numPages(); ++i )
|
|
+ {
|
|
+ doc->scanForFonts( 1, &listOfFonts3 );
|
|
+ }
|
|
+ QVERIFY( listOfFonts3.isEmpty() );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestFontsData)
|
|
+#include "check_fonts.moc"
|
|
+
|
|
diff --git a/qt4/tests/check_goostring.cpp b/qt4/tests/check_goostring.cpp
|
|
new file mode 100644
|
|
index 00000000..69f7cdc5
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_goostring.cpp
|
|
@@ -0,0 +1,127 @@
|
|
+#include <QtCore/QScopedPointer>
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include "goo/GooString.h"
|
|
+
|
|
+class TestGooString : public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void testInsertData_data();
|
|
+ void testInsertData();
|
|
+ void testInsert();
|
|
+ void testFormat();
|
|
+};
|
|
+
|
|
+void TestGooString::testInsertData_data()
|
|
+{
|
|
+ QTest::addColumn<QByteArray>("string");
|
|
+ QTest::addColumn<QByteArray>("addition");
|
|
+ QTest::addColumn<int>("position");
|
|
+ QTest::addColumn<QByteArray>("result");
|
|
+
|
|
+ QTest::newRow("foo") << QByteArray("foo") << QByteArray("bar") << 0 << QByteArray("barfoo");
|
|
+ QTest::newRow("<empty>") << QByteArray() << QByteArray("bar") << 0 << QByteArray("bar");
|
|
+ QTest::newRow("foo+bar #1") << QByteArray("f+bar") << QByteArray("oo") << 1 << QByteArray("foo+bar");
|
|
+ QTest::newRow("foo+bar #2") << QByteArray("fobar") << QByteArray("o+") << 2 << QByteArray("foo+bar");
|
|
+ QTest::newRow("foo+bar #last") << QByteArray("foo+r") << QByteArray("ba") << 4 << QByteArray("foo+bar");
|
|
+ QTest::newRow("foo+bar #end") << QByteArray("foo+") << QByteArray("bar") << 4 << QByteArray("foo+bar");
|
|
+ QTest::newRow("long #start") << QByteArray("very string") << QByteArray("long long long long long ") << 5 << QByteArray("very long long long long long string");
|
|
+}
|
|
+
|
|
+void TestGooString::testInsertData()
|
|
+{
|
|
+ QFETCH(QByteArray, string);
|
|
+ QFETCH(QByteArray, addition);
|
|
+ QFETCH(int, position);
|
|
+ QFETCH(QByteArray, result);
|
|
+
|
|
+ GooString goo(string.constData());
|
|
+ QCOMPARE(goo.c_str(), string.constData());
|
|
+ goo.insert(position, addition.constData());
|
|
+ QCOMPARE(goo.c_str(), result.constData());
|
|
+}
|
|
+
|
|
+void TestGooString::testInsert()
|
|
+{
|
|
+ {
|
|
+ GooString goo;
|
|
+ goo.insert(0, ".");
|
|
+ goo.insert(0, "This is a very long long test string");
|
|
+ QCOMPARE(goo.c_str(), "This is a very long long test string.");
|
|
+ }
|
|
+ {
|
|
+ GooString goo;
|
|
+ goo.insert(0, "second-part-third-part");
|
|
+ goo.insert(0, "first-part-");
|
|
+ QCOMPARE(goo.c_str(), "first-part-second-part-third-part");
|
|
+ }
|
|
+}
|
|
+
|
|
+void TestGooString::testFormat()
|
|
+{
|
|
+ {
|
|
+ const QScopedPointer<GooString> goo(GooString::format("{0:d},{1:x}", 1, 0xF));
|
|
+ QCOMPARE(goo->c_str(), "1,f");
|
|
+ }
|
|
+ {
|
|
+ const QScopedPointer<GooString> goo(GooString::format("{0:d},{0:x},{0:X},{0:o},{0:b},{0:w}", 0xA));
|
|
+ QCOMPARE(goo->c_str(), "10,a,A,12,1010, ");
|
|
+ }
|
|
+ {
|
|
+ const QScopedPointer<GooString> goo(GooString::format("{0:d},{0:x},{0:X},{0:o},{0:b}", -0xA));
|
|
+ QCOMPARE(goo->c_str(), "-10,-a,-A,-12,-1010");
|
|
+ }
|
|
+ {
|
|
+ const QScopedPointer<GooString> goo(GooString::format("{0:c}{1:c}{2:c}{3:c}",
|
|
+ 'T', (char)'E', (short)'S', (int)'T'));
|
|
+ QCOMPARE(goo->c_str(), "TEST");
|
|
+
|
|
+ const QScopedPointer<GooString> goo2(GooString::format("{0:s} {1:t}", "TEST", goo.data()));
|
|
+ QCOMPARE(goo2->c_str(), "TEST TEST");
|
|
+ }
|
|
+ {
|
|
+ const QScopedPointer<GooString> goo(GooString::format("{0:ud} {1:d} {2:d}",
|
|
+ UINT_MAX, INT_MAX, INT_MIN));
|
|
+ const QByteArray expected = QString("%1 %2 %3").arg(UINT_MAX).arg(INT_MAX).arg(INT_MIN).toLatin1();
|
|
+ QCOMPARE(goo->c_str(), expected.constData());
|
|
+ }
|
|
+ {
|
|
+ const QScopedPointer<GooString> goo(GooString::format("{0:uld} {1:ld} {2:ld}",
|
|
+ ULONG_MAX, LONG_MAX, LONG_MIN));
|
|
+ const QByteArray expected = QString("%1 %2 %3").arg(ULONG_MAX).arg(LONG_MAX).arg(LONG_MIN).toLatin1();
|
|
+ QCOMPARE(goo->c_str(), expected.constData());
|
|
+ }
|
|
+ {
|
|
+ const QScopedPointer<GooString> goo(GooString::format("{0:ulld} {1:lld} {2:lld}",
|
|
+ ULLONG_MAX, LLONG_MAX, LLONG_MIN));
|
|
+ const QByteArray expected = QString("%1 %2 %3").arg(ULLONG_MAX).arg(LLONG_MAX).arg(LLONG_MIN).toLatin1();
|
|
+ QCOMPARE(goo->c_str(), expected.constData());
|
|
+ }
|
|
+ {
|
|
+ const QScopedPointer<GooString> gooD(GooString::format("{0:.1f} {0:.1g} {0:.1gs} | {1:.1f} {1:.1g} {1:.1gs}", 1., .012));
|
|
+ const QScopedPointer<GooString> gooF(GooString::format("{0:.1f} {0:.1g} {0:.1gs} | {1:.1f} {1:.1g} {1:.1gs}", 1.f, .012f));
|
|
+ QCOMPARE(gooD->c_str(), "1.0 1 1 | 0.0 0 0.01");
|
|
+ QCOMPARE(gooF->c_str(), "1.0 1 1 | 0.0 0 0.01");
|
|
+ }
|
|
+ {
|
|
+ const QScopedPointer<GooString> goo(GooString::format("{0:.4f} {0:.4g} {0:.4gs}", .012));
|
|
+ QCOMPARE(goo->c_str(), "0.0120 0.012 0.012");
|
|
+ }
|
|
+ {
|
|
+ const QScopedPointer<GooString> goo(GooString::format("{{ SomeText {0:d} }}", 1));
|
|
+ QCOMPARE(goo->c_str(), "{ SomeText 1 }");
|
|
+ }
|
|
+ {
|
|
+ const QScopedPointer<GooString> goo(GooString::format("{{{{ {{ SomeText {0:d}", 2));
|
|
+ QCOMPARE(goo->c_str(), "{{ { SomeText 2");
|
|
+ }
|
|
+ {
|
|
+ const QScopedPointer<GooString> goo(GooString::format("SomeText {0:d} }} }}}}", 3));
|
|
+ QCOMPARE(goo->c_str(), "SomeText 3 } }}");
|
|
+ }
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestGooString)
|
|
+#include "check_goostring.moc"
|
|
+
|
|
diff --git a/qt4/tests/check_lexer.cpp b/qt4/tests/check_lexer.cpp
|
|
new file mode 100644
|
|
index 00000000..93c3621d
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_lexer.cpp
|
|
@@ -0,0 +1,107 @@
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include "Object.h"
|
|
+#include "Lexer.h"
|
|
+
|
|
+class TestLexer : public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void testNumbers();
|
|
+};
|
|
+
|
|
+void TestLexer::testNumbers()
|
|
+{
|
|
+ char data[] = "0 1 -1 2147483647 -2147483647 2147483648 -2147483648 4294967297 -2147483649 0.1 1.1 -1.1 2147483647.1 -2147483647.1 2147483648.1 -2147483648.1 4294967297.1 -2147483649.1 9223372036854775807 18446744073709551615";
|
|
+ MemStream *stream = new MemStream(data, 0, strlen(data), Object(objNull));
|
|
+ Lexer *lexer = new Lexer(NULL, stream);
|
|
+ QVERIFY( lexer );
|
|
+
|
|
+ Object obj;
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objInt);
|
|
+ QCOMPARE(obj.getInt(), 0);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objInt);
|
|
+ QCOMPARE(obj.getInt(), 1);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objInt);
|
|
+ QCOMPARE(obj.getInt(), -1);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objInt);
|
|
+ QCOMPARE(obj.getInt(), 2147483647);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objInt);
|
|
+ QCOMPARE(obj.getInt(), -2147483647);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objInt64);
|
|
+ QCOMPARE(obj.getInt64(), 2147483648ll);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objInt);
|
|
+ QCOMPARE(obj.getInt(), -2147483647-1);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objInt64);
|
|
+ QCOMPARE(obj.getInt64(), 4294967297ll);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objInt64);
|
|
+ QCOMPARE(obj.getInt64(), -2147483649ll);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objReal);
|
|
+ QCOMPARE(obj.getReal(), 0.1);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objReal);
|
|
+ QCOMPARE(obj.getReal(), 1.1);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objReal);
|
|
+ QCOMPARE(obj.getReal(), -1.1);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objReal);
|
|
+ QCOMPARE(obj.getReal(), 2147483647.1);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objReal);
|
|
+ QCOMPARE(obj.getReal(), -2147483647.1);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objReal);
|
|
+ QCOMPARE(obj.getReal(), 2147483648.1);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objReal);
|
|
+ QCOMPARE(obj.getReal(), -2147483648.1);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objReal);
|
|
+ QCOMPARE(obj.getReal(), 4294967297.1);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objReal);
|
|
+ QCOMPARE(obj.getReal(), -2147483649.1);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objInt64);
|
|
+ QCOMPARE(obj.getInt64(), 9223372036854775807ll);
|
|
+
|
|
+ obj = lexer->getObj();
|
|
+ QCOMPARE(obj.getType(), objReal);
|
|
+ QCOMPARE(obj.getReal(), 18446744073709551616.);
|
|
+
|
|
+ delete lexer;
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestLexer)
|
|
+#include "check_lexer.moc"
|
|
+
|
|
diff --git a/qt4/tests/check_links.cpp b/qt4/tests/check_links.cpp
|
|
new file mode 100644
|
|
index 00000000..e5c17368
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_links.cpp
|
|
@@ -0,0 +1,98 @@
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+#include <memory>
|
|
+
|
|
+class TestLinks : public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void checkDocumentWithNoDests();
|
|
+ void checkDests_xr01();
|
|
+ void checkDests_xr02();
|
|
+};
|
|
+
|
|
+static bool isDestinationValid_pageNumber( const Poppler::LinkDestination *dest, const Poppler::Document *doc )
|
|
+{
|
|
+ return dest->pageNumber() > 0 && dest->pageNumber() <= doc->numPages();
|
|
+}
|
|
+
|
|
+static bool isDestinationValid_name( const Poppler::LinkDestination *dest )
|
|
+{
|
|
+ return !dest->destinationName().isEmpty();
|
|
+}
|
|
+
|
|
+
|
|
+void TestLinks::checkDocumentWithNoDests()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/WithAttachments.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ std::unique_ptr< Poppler::LinkDestination > dest;
|
|
+ dest.reset( doc->linkDestination("no.dests.in.this.document") );
|
|
+ QVERIFY( !isDestinationValid_pageNumber( dest.get(), doc ) );
|
|
+ QVERIFY( isDestinationValid_name( dest.get() ) );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestLinks::checkDests_xr01()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/xr01.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ Poppler::Page *page = doc->page(0);
|
|
+ QVERIFY( page );
|
|
+
|
|
+ QList< Poppler::Link* > links = page->links();
|
|
+ QCOMPARE( links.count(), 2 );
|
|
+
|
|
+ {
|
|
+ QCOMPARE( links.at(0)->linkType(), Poppler::Link::Goto );
|
|
+ Poppler::LinkGoto *link = static_cast< Poppler::LinkGoto * >( links.at(0) );
|
|
+ const Poppler::LinkDestination dest = link->destination();
|
|
+ QVERIFY( !isDestinationValid_pageNumber( &dest, doc ) );
|
|
+ QVERIFY( isDestinationValid_name( &dest ) );
|
|
+ QCOMPARE( dest.destinationName(), QString::fromLatin1("section.1") );
|
|
+ }
|
|
+
|
|
+ {
|
|
+ QCOMPARE( links.at(1)->linkType(), Poppler::Link::Goto );
|
|
+ Poppler::LinkGoto *link = static_cast< Poppler::LinkGoto * >( links.at(1) );
|
|
+ const Poppler::LinkDestination dest = link->destination();
|
|
+ QVERIFY( !isDestinationValid_pageNumber( &dest, doc ) );
|
|
+ QVERIFY( isDestinationValid_name( &dest ) );
|
|
+ QCOMPARE( dest.destinationName(), QString::fromLatin1("section.2") );
|
|
+ }
|
|
+
|
|
+ qDeleteAll(links);
|
|
+ delete page;
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestLinks::checkDests_xr02()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/xr02.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ std::unique_ptr< Poppler::LinkDestination > dest;
|
|
+ dest.reset( doc->linkDestination("section.1") );
|
|
+ QVERIFY( isDestinationValid_pageNumber( dest.get(), doc ) );
|
|
+ QVERIFY( !isDestinationValid_name( dest.get() ) );
|
|
+ dest.reset( doc->linkDestination("section.2") );
|
|
+ QVERIFY( isDestinationValid_pageNumber( dest.get(), doc ) );
|
|
+ QVERIFY( !isDestinationValid_name( dest.get() ) );
|
|
+ dest.reset( doc->linkDestination("section.3") );
|
|
+ QVERIFY( !isDestinationValid_pageNumber( dest.get(), doc ) );
|
|
+ QVERIFY( isDestinationValid_name( dest.get() ) );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestLinks)
|
|
+
|
|
+#include "check_links.moc"
|
|
diff --git a/qt4/tests/check_metadata.cpp b/qt4/tests/check_metadata.cpp
|
|
new file mode 100644
|
|
index 00000000..fb4f7163
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_metadata.cpp
|
|
@@ -0,0 +1,275 @@
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+class TestMetaData: public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void checkStrings_data();
|
|
+ void checkStrings();
|
|
+ void checkStrings2_data();
|
|
+ void checkStrings2();
|
|
+ void checkStringKeys();
|
|
+ void checkLinearised();
|
|
+ void checkNumPages();
|
|
+ void checkDate();
|
|
+ void checkPageSize();
|
|
+ void checkPortraitOrientation();
|
|
+ void checkLandscapeOrientation();
|
|
+ void checkUpsideDownOrientation();
|
|
+ void checkSeascapeOrientation();
|
|
+ void checkVersion();
|
|
+ void checkPdfId();
|
|
+ void checkNoPdfId();
|
|
+};
|
|
+
|
|
+void TestMetaData::checkStrings_data()
|
|
+{
|
|
+ QTest::addColumn<QString>("key");
|
|
+ QTest::addColumn<QString>("value");
|
|
+
|
|
+ QTest::newRow( "Author" ) << "Author" << "Brad Hards";
|
|
+ QTest::newRow( "Title" ) << "Title" << "Two pages";
|
|
+ QTest::newRow( "Subject" ) << "Subject"
|
|
+ << "A two page layout for poppler testing";
|
|
+ QTest::newRow( "Keywords" ) << "Keywords" << "Qt4 bindings";
|
|
+ QTest::newRow( "Creator" ) << "Creator" << "iText: cgpdftops CUPS filter";
|
|
+ QTest::newRow( "Producer" ) << "Producer" << "Acrobat Distiller 7.0 for Macintosh";
|
|
+}
|
|
+
|
|
+void TestMetaData::checkStrings()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/doublepage.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QFETCH( QString, key );
|
|
+ QFETCH( QString, value );
|
|
+ QCOMPARE( doc->info(key), value );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestMetaData::checkStrings2_data()
|
|
+{
|
|
+ QTest::addColumn<QString>("key");
|
|
+ QTest::addColumn<QString>("value");
|
|
+
|
|
+ QTest::newRow( "Title" ) << "Title" << "Malaga hotels";
|
|
+ QTest::newRow( "Author" ) << "Author" << "Brad Hards";
|
|
+ QTest::newRow( "Creator" ) << "Creator" << "Safari: cgpdftops CUPS filter";
|
|
+ QTest::newRow( "Producer" ) << "Producer" << "Acrobat Distiller 7.0 for Macintosh";
|
|
+ QTest::newRow( "Keywords" ) << "Keywords" << "First\rSecond\rthird";
|
|
+ QTest::newRow( "Custom1" ) << "Custom1" << "CustomValue1";
|
|
+ QTest::newRow( "Custom2" ) << "Custom2" << "CustomValue2";
|
|
+}
|
|
+
|
|
+void TestMetaData::checkStrings2()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/truetype.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QFETCH( QString, key );
|
|
+ QFETCH( QString, value );
|
|
+ QCOMPARE( doc->info(key), value );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestMetaData::checkStringKeys()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/truetype.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QStringList keyList;
|
|
+ keyList << "Title" << "Author" << "Creator" << "Keywords" << "CreationDate";
|
|
+ keyList << "Producer" << "ModDate" << "Custom1" << "Custom2";
|
|
+ keyList.sort();
|
|
+ QStringList keysInDoc = doc->infoKeys();
|
|
+ keysInDoc.sort();
|
|
+ QCOMPARE( keysInDoc, keyList );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestMetaData::checkLinearised()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/orientation.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QVERIFY( doc->isLinearized() );
|
|
+
|
|
+ delete doc;
|
|
+
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/truetype.pdf");
|
|
+ QVERIFY( doc );
|
|
+ QCOMPARE( doc->isLinearized(), false );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestMetaData::checkPortraitOrientation()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/orientation.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ Poppler::Page *page = doc->page(0);
|
|
+ QCOMPARE( page->orientation(), Poppler::Page::Portrait );
|
|
+
|
|
+ delete page;
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestMetaData::checkNumPages()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/doublepage.pdf");
|
|
+ QVERIFY( doc );
|
|
+ QCOMPARE( doc->numPages(), 2 );
|
|
+
|
|
+ delete doc;
|
|
+
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/truetype.pdf");
|
|
+ QVERIFY( doc );
|
|
+ QCOMPARE( doc->numPages(), 1 );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestMetaData::checkDate()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/truetype.pdf");
|
|
+ QVERIFY( doc );
|
|
+ QCOMPARE( doc->date("ModDate"), QDateTime(QDate(2005, 12, 5), QTime(9,44,46), Qt::UTC ) );
|
|
+ QCOMPARE( doc->date("CreationDate"), QDateTime(QDate(2005, 8, 13), QTime(1,12,11), Qt::UTC ) );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestMetaData::checkPageSize()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/truetype.pdf");
|
|
+ QVERIFY( doc );
|
|
+ Poppler::Page *page = doc->page(0);
|
|
+ QCOMPARE( page->pageSize(), QSize(595, 842) );
|
|
+ QCOMPARE( page->pageSizeF(), QSizeF(595.22, 842) );
|
|
+
|
|
+ delete page;
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+
|
|
+void TestMetaData::checkLandscapeOrientation()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/orientation.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ Poppler::Page *page = doc->page(1);
|
|
+ QCOMPARE( page->orientation(), Poppler::Page::Landscape );
|
|
+
|
|
+ delete page;
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestMetaData::checkUpsideDownOrientation()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/orientation.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ Poppler::Page *page = doc->page(2);
|
|
+ QCOMPARE( page->orientation(), Poppler::Page::UpsideDown );
|
|
+
|
|
+ delete page;
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestMetaData::checkSeascapeOrientation()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/orientation.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ Poppler::Page *page = doc->page(3);
|
|
+ QCOMPARE( page->orientation(), Poppler::Page::Seascape );
|
|
+
|
|
+ delete page;
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestMetaData::checkVersion()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/doublepage.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QCOMPARE( doc->pdfVersion(), 1.6 );
|
|
+ int major = 0, minor = 0;
|
|
+ doc->getPdfVersion( &major, &minor );
|
|
+ QCOMPARE( major, 1 );
|
|
+ QCOMPARE( minor, 6 );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestMetaData::checkPdfId()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/A6EmbeddedFiles.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ const QByteArray referencePermanentId( "00C9D5B6D8FB11D7A902003065D630AA" );
|
|
+ const QByteArray referenceUpdateId( "39AECAE6D8FB11D7A902003065D630AA" );
|
|
+
|
|
+ {
|
|
+ // no IDs wanted, just existance check
|
|
+ QVERIFY( doc->getPdfId( 0, 0 ) );
|
|
+ }
|
|
+ {
|
|
+ // only permanent ID
|
|
+ QByteArray permanentId;
|
|
+ QVERIFY( doc->getPdfId( &permanentId, 0 ) );
|
|
+ QCOMPARE( permanentId.toUpper(), referencePermanentId );
|
|
+ }
|
|
+ {
|
|
+ // only update ID
|
|
+ QByteArray updateId;
|
|
+ QVERIFY( doc->getPdfId( 0, &updateId ) );
|
|
+ QCOMPARE( updateId.toUpper(), referenceUpdateId );
|
|
+ }
|
|
+ {
|
|
+ // both IDs
|
|
+ QByteArray permanentId;
|
|
+ QByteArray updateId;
|
|
+ QVERIFY( doc->getPdfId( &permanentId, &updateId ) );
|
|
+ QCOMPARE( permanentId.toUpper(), referencePermanentId );
|
|
+ QCOMPARE( updateId.toUpper(), referenceUpdateId );
|
|
+ }
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestMetaData::checkNoPdfId()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/WithActualText.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QVERIFY( !doc->getPdfId( 0, 0 ) );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestMetaData)
|
|
+#include "check_metadata.moc"
|
|
+
|
|
diff --git a/qt4/tests/check_optcontent.cpp b/qt4/tests/check_optcontent.cpp
|
|
new file mode 100644
|
|
index 00000000..2de29952
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_optcontent.cpp
|
|
@@ -0,0 +1,446 @@
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include "PDFDoc.h"
|
|
+#include "GlobalParams.h"
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+class TestOptionalContent: public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void checkVisPolicy();
|
|
+ void checkNestedLayers();
|
|
+ void checkNoOptionalContent();
|
|
+ void checkIsVisible();
|
|
+ void checkVisibilitySetting();
|
|
+ void checkRadioButtons();
|
|
+};
|
|
+
|
|
+void TestOptionalContent::checkVisPolicy()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/vis_policy_test.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QVERIFY( doc->hasOptionalContent() );
|
|
+
|
|
+ Poppler::OptContentModel *optContent = doc->optionalContentModel();
|
|
+ QModelIndex index;
|
|
+ index = optContent->index( 0, 0, QModelIndex() );
|
|
+ QCOMPARE( optContent->data( index, Qt::DisplayRole ).toString(), QString( "A" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( index, Qt::CheckStateRole ).toInt() ), Qt::Checked );
|
|
+ index = optContent->index( 1, 0, QModelIndex() );
|
|
+ QCOMPARE( optContent->data( index, Qt::DisplayRole ).toString(), QString( "B" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( index, Qt::CheckStateRole ).toInt() ), Qt::Checked );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestOptionalContent::checkNestedLayers()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/NestedLayers.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QVERIFY( doc->hasOptionalContent() );
|
|
+
|
|
+ Poppler::OptContentModel *optContent = doc->optionalContentModel();
|
|
+ QModelIndex index;
|
|
+
|
|
+ index = optContent->index( 0, 0, QModelIndex() );
|
|
+ QCOMPARE( optContent->data( index, Qt::DisplayRole ).toString(), QString( "Black Text and Green Snow" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( index, Qt::CheckStateRole ).toInt() ), Qt::Unchecked );
|
|
+
|
|
+ index = optContent->index( 1, 0, QModelIndex() );
|
|
+ QCOMPARE( optContent->data( index, Qt::DisplayRole ).toString(), QString( "Mountains and Image" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( index, Qt::CheckStateRole ).toInt() ), Qt::Checked );
|
|
+
|
|
+ // This is a sub-item of "Mountains and Image"
|
|
+ QModelIndex subindex = optContent->index( 0, 0, index );
|
|
+ QCOMPARE( optContent->data( subindex, Qt::DisplayRole ).toString(), QString( "Image" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( index, Qt::CheckStateRole ).toInt() ), Qt::Checked );
|
|
+
|
|
+ index = optContent->index( 2, 0, QModelIndex() );
|
|
+ QCOMPARE( optContent->data( index, Qt::DisplayRole ).toString(), QString( "Starburst" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( index, Qt::CheckStateRole ).toInt() ), Qt::Checked );
|
|
+
|
|
+ index = optContent->index( 3, 0, QModelIndex() );
|
|
+ QCOMPARE( optContent->data( index, Qt::DisplayRole ).toString(), QString( "Watermark" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( index, Qt::CheckStateRole ).toInt() ), Qt::Unchecked );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestOptionalContent::checkNoOptionalContent()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/orientation.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QCOMPARE( doc->hasOptionalContent(), false );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestOptionalContent::checkIsVisible()
|
|
+{
|
|
+ GooString *fileName = new GooString(TESTDATADIR "/unittestcases/vis_policy_test.pdf");
|
|
+ globalParams = std::make_unique<GlobalParams>();
|
|
+ PDFDoc *doc = new PDFDoc( fileName );
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ OCGs *ocgs = doc->getOptContentConfig();
|
|
+ QVERIFY( ocgs );
|
|
+
|
|
+ XRef *xref = doc->getXRef();
|
|
+
|
|
+ Object obj;
|
|
+
|
|
+ // In this test, both Ref(21,0) and Ref(2,0) are set to On
|
|
+
|
|
+ // AnyOn, one element array:
|
|
+ // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
|
|
+ obj = xref->fetch( { 22, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QVERIFY( ocgs->optContentIsVisible( &obj ) );
|
|
+
|
|
+ // Same again, looking for any leaks or dubious free()'s
|
|
+ obj = xref->fetch( { 22, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QVERIFY( ocgs->optContentIsVisible( &obj ) );
|
|
+
|
|
+ // AnyOff, one element array:
|
|
+ // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
|
|
+ obj = xref->fetch( { 29, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // AllOn, one element array:
|
|
+ // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
|
|
+ obj = xref->fetch( { 36, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+
|
|
+ // AllOff, one element array:
|
|
+ // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
|
|
+ obj = xref->fetch( { 43, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // AnyOn, multi-element array:
|
|
+ // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
|
|
+ obj = xref->fetch( { 50, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+ // AnyOff, multi-element array:
|
|
+ // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
|
|
+ obj = xref->fetch( { 57, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // AllOn, multi-element array:
|
|
+ // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
|
|
+ obj = xref->fetch( { 64, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+ // AllOff, multi-element array:
|
|
+ // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
|
|
+ obj = xref->fetch( { 71, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ delete doc;
|
|
+ globalParams.reset();
|
|
+}
|
|
+
|
|
+void TestOptionalContent::checkVisibilitySetting()
|
|
+{
|
|
+ globalParams = std::make_unique<GlobalParams>();
|
|
+ GooString *fileName = new GooString(TESTDATADIR "/unittestcases/vis_policy_test.pdf");
|
|
+ PDFDoc *doc = new PDFDoc( fileName );
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ OCGs *ocgs = doc->getOptContentConfig();
|
|
+ QVERIFY( ocgs );
|
|
+
|
|
+ XRef *xref = doc->getXRef();
|
|
+
|
|
+ Object obj;
|
|
+
|
|
+ // In this test, both Ref(21,0) and Ref(28,0) start On,
|
|
+ // based on the file settings
|
|
+ Object ref21obj( { 21, 0 } );
|
|
+ Ref ref21 = ref21obj.getRef();
|
|
+ OptionalContentGroup *ocgA = ocgs->findOcgByRef( ref21 );
|
|
+ QVERIFY( ocgA );
|
|
+
|
|
+ QVERIFY( (ocgA->getName()->cmp("A")) == 0 );
|
|
+ QCOMPARE( ocgA->getState(), OptionalContentGroup::On );
|
|
+
|
|
+ Object ref28obj( { 28, 0 } );
|
|
+ Ref ref28 = ref28obj.getRef();
|
|
+ OptionalContentGroup *ocgB = ocgs->findOcgByRef( ref28 );
|
|
+ QVERIFY( ocgB );
|
|
+
|
|
+ QVERIFY( (ocgB->getName()->cmp("B")) == 0 );
|
|
+ QCOMPARE( ocgB->getState(), OptionalContentGroup::On );
|
|
+
|
|
+ // turn one Off
|
|
+ ocgA->setState( OptionalContentGroup::Off );
|
|
+
|
|
+ // AnyOn, one element array:
|
|
+ // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
|
|
+ obj = xref->fetch( { 22, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // Same again, looking for any leaks or dubious free()'s
|
|
+ obj = xref->fetch( { 22, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // AnyOff, one element array:
|
|
+ // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
|
|
+ obj = xref->fetch( { 29, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+ // AllOn, one element array:
|
|
+ // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
|
|
+ obj = xref->fetch( { 36, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+ // AllOff, one element array:
|
|
+ // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
|
|
+ obj = xref->fetch( { 43, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // AnyOn, multi-element array:
|
|
+ // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
|
|
+ obj = xref->fetch( { 50, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+ // AnyOff, multi-element array:
|
|
+ // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
|
|
+ obj = xref->fetch( { 57, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+ // AllOn, multi-element array:
|
|
+ // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
|
|
+ obj = xref->fetch( { 64, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // AllOff, multi-element array:
|
|
+ // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
|
|
+ obj = xref->fetch( { 71, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+
|
|
+ // Turn the other one off as well (i.e. both are Off)
|
|
+ ocgB->setState(OptionalContentGroup::Off);
|
|
+
|
|
+ // AnyOn, one element array:
|
|
+ // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
|
|
+ obj = xref->fetch( { 22, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // Same again, looking for any leaks or dubious free()'s
|
|
+ obj = xref->fetch( { 22, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // AnyOff, one element array:
|
|
+ // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
|
|
+ obj = xref->fetch( { 29, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+ // AllOn, one element array:
|
|
+ // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
|
|
+ obj = xref->fetch( { 36, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // AllOff, one element array:
|
|
+ // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
|
|
+ obj = xref->fetch( { 43, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+ // AnyOn, multi-element array:
|
|
+ // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
|
|
+ obj = xref->fetch( { 50, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // AnyOff, multi-element array:
|
|
+ // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
|
|
+ obj = xref->fetch( { 57, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+ // AllOn, multi-element array:
|
|
+ // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
|
|
+ obj = xref->fetch( { 64, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // AllOff, multi-element array:
|
|
+ // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
|
|
+ obj = xref->fetch( { 71, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+
|
|
+ // Turn the first one on again (21 is On, 28 is Off)
|
|
+ ocgA->setState(OptionalContentGroup::On);
|
|
+
|
|
+ // AnyOn, one element array:
|
|
+ // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
|
|
+ obj = xref->fetch( { 22, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+ // Same again, looking for any leaks or dubious free()'s
|
|
+ obj = xref->fetch( { 22, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+ // AnyOff, one element array:
|
|
+ // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
|
|
+ obj = xref->fetch( { 29, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // AllOn, one element array:
|
|
+ // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
|
|
+ obj = xref->fetch( { 36, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // AllOff, one element array:
|
|
+ // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
|
|
+ obj = xref->fetch( { 43, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+ // AnyOn, multi-element array:
|
|
+ // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
|
|
+ obj = xref->fetch( { 50, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+ // AnyOff, multi-element array:
|
|
+ // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
|
|
+ obj = xref->fetch( { 57, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
|
|
+
|
|
+ // AllOn, multi-element array:
|
|
+ // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
|
|
+ obj = xref->fetch( { 64, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ // AllOff, multi-element array:
|
|
+ // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
|
|
+ obj = xref->fetch( { 71, 0 } );
|
|
+ QVERIFY( obj.isDict() );
|
|
+ QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
|
|
+
|
|
+ delete doc;
|
|
+ globalParams.reset();
|
|
+}
|
|
+
|
|
+void TestOptionalContent::checkRadioButtons()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/ClarityOCGs.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QVERIFY( doc->hasOptionalContent() );
|
|
+
|
|
+ Poppler::OptContentModel *optContent = doc->optionalContentModel();
|
|
+ QModelIndex index;
|
|
+
|
|
+ index = optContent->index( 0, 0, QModelIndex() );
|
|
+ QCOMPARE( optContent->data( index, Qt::DisplayRole ).toString(), QString( "Languages" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( index, Qt::CheckStateRole ).toInt() ), Qt::Unchecked );
|
|
+
|
|
+ // These are sub-items of the "Languages" label
|
|
+ QModelIndex subindex = optContent->index( 0, 0, index );
|
|
+ QCOMPARE( optContent->data( subindex, Qt::DisplayRole ).toString(), QString( "English" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( subindex, Qt::CheckStateRole ).toInt() ), Qt::Checked );
|
|
+
|
|
+ subindex = optContent->index( 1, 0, index );
|
|
+ QCOMPARE( optContent->data( subindex, Qt::DisplayRole ).toString(), QString( "French" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( subindex, Qt::CheckStateRole ).toInt() ), Qt::Unchecked );
|
|
+
|
|
+ subindex = optContent->index( 2, 0, index );
|
|
+ QCOMPARE( optContent->data( subindex, Qt::DisplayRole ).toString(), QString( "Japanese" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( subindex, Qt::CheckStateRole ).toInt() ), Qt::Unchecked );
|
|
+
|
|
+ // RBGroup of languages, so turning on Japanese should turn off English
|
|
+ QVERIFY( optContent->setData( subindex, QVariant( true ), Qt::CheckStateRole ) );
|
|
+
|
|
+ subindex = optContent->index( 0, 0, index );
|
|
+ QCOMPARE( optContent->data( subindex, Qt::DisplayRole ).toString(), QString( "English" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( subindex, Qt::CheckStateRole ).toInt() ), Qt::Unchecked );
|
|
+
|
|
+ subindex = optContent->index( 2, 0, index );
|
|
+ QCOMPARE( optContent->data( subindex, Qt::DisplayRole ).toString(), QString( "Japanese" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( subindex, Qt::CheckStateRole ).toInt() ), Qt::Checked );
|
|
+
|
|
+ subindex = optContent->index( 1, 0, index );
|
|
+ QCOMPARE( optContent->data( subindex, Qt::DisplayRole ).toString(), QString( "French" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( subindex, Qt::CheckStateRole ).toInt() ), Qt::Unchecked );
|
|
+
|
|
+ // and turning on French should turn off Japanese
|
|
+ QVERIFY( optContent->setData( subindex, QVariant( true ), Qt::CheckStateRole ) );
|
|
+
|
|
+ subindex = optContent->index( 0, 0, index );
|
|
+ QCOMPARE( optContent->data( subindex, Qt::DisplayRole ).toString(), QString( "English" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( subindex, Qt::CheckStateRole ).toInt() ), Qt::Unchecked );
|
|
+
|
|
+ subindex = optContent->index( 2, 0, index );
|
|
+ QCOMPARE( optContent->data( subindex, Qt::DisplayRole ).toString(), QString( "Japanese" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( subindex, Qt::CheckStateRole ).toInt() ), Qt::Unchecked );
|
|
+
|
|
+ subindex = optContent->index( 1, 0, index );
|
|
+ QCOMPARE( optContent->data( subindex, Qt::DisplayRole ).toString(), QString( "French" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( subindex, Qt::CheckStateRole ).toInt() ), Qt::Checked );
|
|
+
|
|
+
|
|
+ // and turning off French should leave them all off
|
|
+ QVERIFY( optContent->setData( subindex, QVariant( false ), Qt::CheckStateRole ) );
|
|
+
|
|
+ subindex = optContent->index( 0, 0, index );
|
|
+ QCOMPARE( optContent->data( subindex, Qt::DisplayRole ).toString(), QString( "English" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( subindex, Qt::CheckStateRole ).toInt() ), Qt::Unchecked );
|
|
+
|
|
+ subindex = optContent->index( 2, 0, index );
|
|
+ QCOMPARE( optContent->data( subindex, Qt::DisplayRole ).toString(), QString( "Japanese" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( subindex, Qt::CheckStateRole ).toInt() ), Qt::Unchecked );
|
|
+
|
|
+ subindex = optContent->index( 1, 0, index );
|
|
+ QCOMPARE( optContent->data( subindex, Qt::DisplayRole ).toString(), QString( "French" ) );
|
|
+ QCOMPARE( static_cast<Qt::CheckState>( optContent->data( subindex, Qt::CheckStateRole ).toInt() ), Qt::Unchecked );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestOptionalContent)
|
|
+
|
|
+#include "check_optcontent.moc"
|
|
+
|
|
diff --git a/qt4/tests/check_pagelabelinfo.cpp b/qt4/tests/check_pagelabelinfo.cpp
|
|
new file mode 100644
|
|
index 00000000..4eb1ec36
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_pagelabelinfo.cpp
|
|
@@ -0,0 +1,43 @@
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include "PageLabelInfo_p.h"
|
|
+
|
|
+class TestPageLabelInfo : public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void testToRoman();
|
|
+ void testFromRoman();
|
|
+ void testToLatin();
|
|
+ void testFromLatin();
|
|
+};
|
|
+
|
|
+void TestPageLabelInfo::testToRoman()
|
|
+{
|
|
+ GooString str;
|
|
+ toRoman(177, &str, false);
|
|
+ QCOMPARE (str.c_str(), "clxxvii");
|
|
+}
|
|
+
|
|
+void TestPageLabelInfo::testFromRoman()
|
|
+{
|
|
+ GooString roman("clxxvii");
|
|
+ QCOMPARE(fromRoman(roman.c_str()), 177);
|
|
+}
|
|
+
|
|
+void TestPageLabelInfo::testToLatin()
|
|
+{
|
|
+ GooString str;
|
|
+ toLatin(54, &str, false);
|
|
+ QCOMPARE(str.c_str(), "bbb");
|
|
+}
|
|
+
|
|
+void TestPageLabelInfo::testFromLatin()
|
|
+{
|
|
+ GooString latin("ddd");
|
|
+ QCOMPARE(fromLatin(latin.c_str()), 56);
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestPageLabelInfo)
|
|
+#include "check_pagelabelinfo.moc"
|
|
+
|
|
diff --git a/qt4/tests/check_pagelayout.cpp b/qt4/tests/check_pagelayout.cpp
|
|
new file mode 100644
|
|
index 00000000..6108f886
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_pagelayout.cpp
|
|
@@ -0,0 +1,49 @@
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+class TestPageLayout: public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void checkNone();
|
|
+ void checkSingle();
|
|
+ void checkFacing();
|
|
+};
|
|
+
|
|
+void TestPageLayout::checkNone()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/UseNone.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QCOMPARE( doc->pageLayout(), Poppler::Document::NoLayout );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestPageLayout::checkSingle()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/FullScreen.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QCOMPARE( doc->pageLayout(), Poppler::Document::SinglePage );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestPageLayout::checkFacing()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/doublepage.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QCOMPARE( doc->pageLayout(), Poppler::Document::TwoPageRight );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestPageLayout)
|
|
+#include "check_pagelayout.moc"
|
|
+
|
|
diff --git a/qt4/tests/check_pagemode.cpp b/qt4/tests/check_pagemode.cpp
|
|
new file mode 100644
|
|
index 00000000..0565fe20
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_pagemode.cpp
|
|
@@ -0,0 +1,73 @@
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+class TestPageMode: public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void checkNone();
|
|
+ void checkFullScreen();
|
|
+ void checkAttachments();
|
|
+ void checkThumbs();
|
|
+ void checkOC();
|
|
+};
|
|
+
|
|
+void TestPageMode::checkNone()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/UseNone.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QCOMPARE( doc->pageMode(), Poppler::Document::UseNone );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestPageMode::checkFullScreen()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/FullScreen.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QCOMPARE( doc->pageMode(), Poppler::Document::FullScreen );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestPageMode::checkAttachments()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/UseAttachments.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QCOMPARE( doc->pageMode(), Poppler::Document::UseAttach );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestPageMode::checkThumbs()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/UseThumbs.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QCOMPARE( doc->pageMode(), Poppler::Document::UseThumbs );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestPageMode::checkOC()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/UseOC.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ QCOMPARE( doc->pageMode(), Poppler::Document::UseOC );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestPageMode)
|
|
+#include "check_pagemode.moc"
|
|
+
|
|
diff --git a/qt4/tests/check_password.cpp b/qt4/tests/check_password.cpp
|
|
new file mode 100644
|
|
index 00000000..4c7dcd1c
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_password.cpp
|
|
@@ -0,0 +1,88 @@
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+class TestPassword: public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void password1();
|
|
+ void password1a();
|
|
+ void password2();
|
|
+ void password2a();
|
|
+ void password2b();
|
|
+ void password3();
|
|
+};
|
|
+
|
|
+
|
|
+// BUG:4557
|
|
+void TestPassword::password1()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(QString::fromUtf8(TESTDATADIR "/unittestcases/Gday garçon - open.pdf"), "", QString::fromUtf8("garçon").toLatin1() );
|
|
+ QVERIFY( doc );
|
|
+ QVERIFY( !doc->isLocked() );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+
|
|
+void TestPassword::password1a()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(QString::fromUtf8(TESTDATADIR "/unittestcases/Gday garçon - open.pdf") );
|
|
+ QVERIFY( doc );
|
|
+ QVERIFY( doc->isLocked() );
|
|
+ QVERIFY( !doc->unlock( "", QString::fromUtf8("garçon").toLatin1() ) );
|
|
+ QVERIFY( !doc->isLocked() );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestPassword::password2()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(QString::fromUtf8(TESTDATADIR "/unittestcases/Gday garçon - owner.pdf"), QString::fromUtf8("garçon").toLatin1(), "" );
|
|
+ QVERIFY( doc );
|
|
+ QVERIFY( !doc->isLocked() );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestPassword::password2a()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(QString::fromUtf8(TESTDATADIR "/unittestcases/Gday garçon - owner.pdf"), QString::fromUtf8("garçon").toLatin1() );
|
|
+ QVERIFY( doc );
|
|
+ QVERIFY( !doc->isLocked() );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestPassword::password2b()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(QString::fromUtf8(TESTDATADIR "/unittestcases/Gday garçon - owner.pdf") );
|
|
+ QVERIFY( doc );
|
|
+ QVERIFY( !doc->isLocked() );
|
|
+ QVERIFY( !doc->unlock( QString::fromUtf8("garçon").toLatin1(), "" ) );
|
|
+ QVERIFY( !doc->isLocked() );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void TestPassword::password3()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load( QString::fromUtf8(TESTDATADIR "/unittestcases/PasswordEncrypted.pdf") );
|
|
+ QVERIFY( doc );
|
|
+ QVERIFY( doc->isLocked() );
|
|
+ QVERIFY( !doc->unlock( "", "password" ) );
|
|
+ QVERIFY( !doc->isLocked() );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestPassword)
|
|
+#include "check_password.moc"
|
|
+
|
|
diff --git a/qt4/tests/check_permissions.cpp b/qt4/tests/check_permissions.cpp
|
|
new file mode 100644
|
|
index 00000000..a3f3bdc6
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_permissions.cpp
|
|
@@ -0,0 +1,44 @@
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+class TestPermissions: public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void permissions1();
|
|
+};
|
|
+
|
|
+void TestPermissions::permissions1()
|
|
+{
|
|
+ Poppler::Document *doc;
|
|
+ doc = Poppler::Document::load(TESTDATADIR "/unittestcases/orientation.pdf");
|
|
+ QVERIFY( doc );
|
|
+
|
|
+ // we are allowed to print
|
|
+ QVERIFY( doc->okToPrint() );
|
|
+
|
|
+ // we are not allowed to change
|
|
+ QVERIFY( !(doc->okToChange()) );
|
|
+
|
|
+ // we are not allowed to copy or extract content
|
|
+ QVERIFY( !(doc->okToCopy()) );
|
|
+
|
|
+ // we are not allowed to print at high resolution
|
|
+ QVERIFY( !(doc->okToPrintHighRes()) );
|
|
+
|
|
+ // we are not allowed to fill forms
|
|
+ QVERIFY( !(doc->okToFillForm()) );
|
|
+
|
|
+ // we are allowed to extract content for accessibility
|
|
+ QVERIFY( doc->okToExtractForAccessibility() );
|
|
+
|
|
+ // we are allowed to assemble this document
|
|
+ QVERIFY( doc->okToAssemble() );
|
|
+
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestPermissions)
|
|
+#include "check_permissions.moc"
|
|
+
|
|
diff --git a/qt4/tests/check_search.cpp b/qt4/tests/check_search.cpp
|
|
new file mode 100644
|
|
index 00000000..99659e04
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_search.cpp
|
|
@@ -0,0 +1,175 @@
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+class TestSearch: public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+private slots:
|
|
+ void bug7063();
|
|
+ void testNextAndPrevious();
|
|
+ void testWholeWordsOnly();
|
|
+};
|
|
+
|
|
+void TestSearch::bug7063()
|
|
+{
|
|
+ QScopedPointer< Poppler::Document > document(Poppler::Document::load(TESTDATADIR "/unittestcases/bug7063.pdf"));
|
|
+ QVERIFY( document );
|
|
+
|
|
+ QScopedPointer< Poppler::Page > page(document->page(0));
|
|
+ QVERIFY( page );
|
|
+
|
|
+ QRectF pageRegion( QPointF(0,0), page->pageSize() );
|
|
+ QCOMPARE( page->search(QString("non-ascii:"), pageRegion, Poppler::Page::FromTop, Poppler::Page::CaseSensitive), true );
|
|
+
|
|
+ QCOMPARE( page->search(QString("Ascii"), pageRegion, Poppler::Page::FromTop, Poppler::Page::CaseSensitive), false );
|
|
+ QCOMPARE( page->search(QString("Ascii"), pageRegion, Poppler::Page::FromTop, Poppler::Page::CaseInsensitive), true );
|
|
+
|
|
+ QCOMPARE( page->search(QString("latin1:"), pageRegion, Poppler::Page::FromTop, Poppler::Page::CaseSensitive), false );
|
|
+
|
|
+ QCOMPARE( page->search(QString::fromUtf8("é"), pageRegion, Poppler::Page::FromTop, Poppler::Page::CaseSensitive), true );
|
|
+ QCOMPARE( page->search(QString::fromUtf8("à"), pageRegion, Poppler::Page::FromTop, Poppler::Page::CaseSensitive), true );
|
|
+ QCOMPARE( page->search(QString::fromUtf8("ç"), pageRegion, Poppler::Page::FromTop, Poppler::Page::CaseSensitive), true );
|
|
+ QCOMPARE( page->search(QString::fromUtf8("search \"é\", \"à\" or \"ç\""), pageRegion, Poppler::Page::FromTop, Poppler::Page::CaseSensitive), true );
|
|
+ QCOMPARE( page->search(QString::fromUtf8("¥µ©"), pageRegion, Poppler::Page::FromTop, Poppler::Page::CaseSensitive), true );
|
|
+ QCOMPARE( page->search(QString::fromUtf8("¥©"), pageRegion, Poppler::Page::FromTop, Poppler::Page::CaseSensitive), false );
|
|
+
|
|
+ double rectLeft = 0.0, rectTop = 0.0, rectRight = page->pageSizeF().width(), rectBottom = page->pageSizeF().height();
|
|
+
|
|
+ QCOMPARE( page->search(QString("non-ascii:"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::FromTop), true );
|
|
+
|
|
+ QCOMPARE( page->search(QString("Ascii"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::FromTop), false );
|
|
+ QCOMPARE( page->search(QString("Ascii"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::FromTop, Poppler::Page::IgnoreCase), true );
|
|
+
|
|
+ QCOMPARE( page->search(QString("latin1:"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::FromTop), false );
|
|
+
|
|
+ QCOMPARE( page->search(QString::fromUtf8("é"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::FromTop), true );
|
|
+ QCOMPARE( page->search(QString::fromUtf8("à"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::FromTop), true );
|
|
+ QCOMPARE( page->search(QString::fromUtf8("ç"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::FromTop), true );
|
|
+ QCOMPARE( page->search(QString::fromUtf8("search \"é\", \"à\" or \"ç\""), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::FromTop), true );
|
|
+ QCOMPARE( page->search(QString::fromUtf8("¥µ©"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::FromTop), true );
|
|
+ QCOMPARE( page->search(QString::fromUtf8("¥©"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::FromTop), false );
|
|
+}
|
|
+
|
|
+void TestSearch::testNextAndPrevious()
|
|
+{
|
|
+ QScopedPointer< Poppler::Document > document(Poppler::Document::load(TESTDATADIR "/unittestcases/xr01.pdf"));
|
|
+ QVERIFY( document );
|
|
+
|
|
+ QScopedPointer< Poppler::Page > page(document->page(0));
|
|
+ QVERIFY( page );
|
|
+
|
|
+ QRectF region( QPointF(0,0), page->pageSize() );
|
|
+
|
|
+ QCOMPARE( page->search(QString("is"), region, Poppler::Page::FromTop, Poppler::Page::CaseSensitive), true );
|
|
+ QVERIFY( qAbs(region.x() - 161.44) < 0.01 );
|
|
+ QVERIFY( qAbs(region.y() - 127.85) < 0.01 );
|
|
+ QVERIFY( qAbs(region.width() - 6.70) < 0.01 );
|
|
+ QVERIFY( qAbs(region.height() - 8.85) < 0.01 );
|
|
+ QCOMPARE( page->search(QString("is"), region, Poppler::Page::NextResult, Poppler::Page::CaseSensitive), true );
|
|
+ QVERIFY( qAbs(region.x() - 171.46) < 0.01 );
|
|
+ QVERIFY( qAbs(region.y() - 127.85) < 0.01 );
|
|
+ QVERIFY( qAbs(region.width() - 6.70) < 0.01 );
|
|
+ QVERIFY( qAbs(region.height() - 8.85) < 0.01 );
|
|
+ QCOMPARE( page->search(QString("is"), region, Poppler::Page::NextResult, Poppler::Page::CaseSensitive), true );
|
|
+ QVERIFY( qAbs(region.x() - 161.44) < 0.01 );
|
|
+ QVERIFY( qAbs(region.y() - 139.81) < 0.01 );
|
|
+ QVERIFY( qAbs(region.width() - 6.70) < 0.01 );
|
|
+ QVERIFY( qAbs(region.height() - 8.85) < 0.01 );
|
|
+ QCOMPARE( page->search(QString("is"), region, Poppler::Page::NextResult, Poppler::Page::CaseSensitive), true );
|
|
+ QVERIFY( qAbs(region.x() - 171.46) < 0.01 );
|
|
+ QVERIFY( qAbs(region.y() - 139.81) < 0.01 );
|
|
+ QVERIFY( qAbs(region.width() - 6.70) < 0.01 );
|
|
+ QVERIFY( qAbs(region.height() - 8.85) < 0.01 );
|
|
+ QCOMPARE( page->search(QString("is"), region, Poppler::Page::NextResult, Poppler::Page::CaseSensitive), false );
|
|
+ QCOMPARE( page->search(QString("is"), region, Poppler::Page::PreviousResult, Poppler::Page::CaseSensitive), true );
|
|
+ QVERIFY( qAbs(region.x() - 161.44) < 0.01 );
|
|
+ QVERIFY( qAbs(region.y() - 139.81) < 0.01 );
|
|
+ QVERIFY( qAbs(region.width() - 6.70) < 0.01 );
|
|
+ QVERIFY( qAbs(region.height() - 8.85) < 0.01 );
|
|
+ QCOMPARE( page->search(QString("is"), region, Poppler::Page::PreviousResult, Poppler::Page::CaseSensitive), true );
|
|
+ QVERIFY( qAbs(region.x() - 171.46) < 0.01 );
|
|
+ QVERIFY( qAbs(region.y() - 127.85) < 0.01 );
|
|
+ QVERIFY( qAbs(region.width() - 6.70) < 0.01 );
|
|
+ QVERIFY( qAbs(region.height() - 8.85) < 0.01 );
|
|
+ QCOMPARE( page->search(QString("is"), region, Poppler::Page::PreviousResult, Poppler::Page::CaseSensitive), true );
|
|
+ QVERIFY( qAbs(region.x() - 161.44) < 0.01 );
|
|
+ QVERIFY( qAbs(region.y() - 127.85) < 0.01 );
|
|
+ QVERIFY( qAbs(region.width() - 6.70) < 0.01 );
|
|
+ QVERIFY( qAbs(region.height() - 8.85) < 0.01 );
|
|
+ QCOMPARE( page->search(QString("is"), region, Poppler::Page::PreviousResult, Poppler::Page::CaseSensitive), false );
|
|
+
|
|
+ double rectLeft = 0.0, rectTop = 0.0, rectRight = page->pageSizeF().width(), rectBottom = page->pageSizeF().height();
|
|
+
|
|
+ QCOMPARE( page->search(QString("is"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::FromTop), true );
|
|
+ QVERIFY( qAbs(rectLeft - 161.44) < 0.01 );
|
|
+ QVERIFY( qAbs(rectTop - 127.85) < 0.01 );
|
|
+ QVERIFY( qAbs(rectRight - rectLeft - 6.70) < 0.01 );
|
|
+ QVERIFY( qAbs(rectBottom - rectTop - 8.85) < 0.01 );
|
|
+ QCOMPARE( page->search(QString("is"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::NextResult), true );
|
|
+ QVERIFY( qAbs(rectLeft - 171.46) < 0.01 );
|
|
+ QVERIFY( qAbs(rectTop - 127.85) < 0.01 );
|
|
+ QVERIFY( qAbs(rectRight - rectLeft - 6.70) < 0.01 );
|
|
+ QVERIFY( qAbs(rectBottom - rectTop - 8.85) < 0.01 );
|
|
+ QCOMPARE( page->search(QString("is"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::NextResult), true );
|
|
+ QVERIFY( qAbs(rectLeft - 161.44) < 0.01 );
|
|
+ QVERIFY( qAbs(rectTop - 139.81) < 0.01 );
|
|
+ QVERIFY( qAbs(rectRight - rectLeft - 6.70) < 0.01 );
|
|
+ QVERIFY( qAbs(rectBottom - rectTop - 8.85) < 0.01 );
|
|
+ QCOMPARE( page->search(QString("is"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::NextResult), true );
|
|
+ QVERIFY( qAbs(rectLeft - 171.46) < 0.01 );
|
|
+ QVERIFY( qAbs(rectTop - 139.81) < 0.01 );
|
|
+ QVERIFY( qAbs(rectRight - rectLeft - 6.70) < 0.01 );
|
|
+ QVERIFY( qAbs(rectBottom - rectTop - 8.85) < 0.01 );
|
|
+ QCOMPARE( page->search(QString("is"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::NextResult), false );
|
|
+ QCOMPARE( page->search(QString("is"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::PreviousResult), true );
|
|
+ QVERIFY( qAbs(rectLeft - 161.44) < 0.01 );
|
|
+ QVERIFY( qAbs(rectTop - 139.81) < 0.01 );
|
|
+ QVERIFY( qAbs(rectRight - rectLeft - 6.70) < 0.01 );
|
|
+ QVERIFY( qAbs(rectBottom - rectTop - 8.85) < 0.01 );
|
|
+ QCOMPARE( page->search(QString("is"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::PreviousResult), true );
|
|
+ QVERIFY( qAbs(rectLeft - 171.46) < 0.01 );
|
|
+ QVERIFY( qAbs(rectTop - 127.85) < 0.01 );
|
|
+ QVERIFY( qAbs(rectRight - rectLeft - 6.70) < 0.01 );
|
|
+ QVERIFY( qAbs(rectBottom - rectTop - 8.85) < 0.01 );
|
|
+ QCOMPARE( page->search(QString("is"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::PreviousResult), true );
|
|
+ QVERIFY( qAbs(rectLeft - 161.44) < 0.01 );
|
|
+ QVERIFY( qAbs(rectTop - 127.85) < 0.01 );
|
|
+ QVERIFY( qAbs(rectRight - rectLeft - 6.70) < 0.01 );
|
|
+ QVERIFY( qAbs(rectBottom - rectTop - 8.85) < 0.01 );
|
|
+ QCOMPARE( page->search(QString("is"), rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::PreviousResult), false );
|
|
+}
|
|
+
|
|
+void TestSearch::testWholeWordsOnly()
|
|
+{
|
|
+ QScopedPointer< Poppler::Document > document(Poppler::Document::load(TESTDATADIR "/unittestcases/WithActualText.pdf"));
|
|
+ QVERIFY( document );
|
|
+
|
|
+ QScopedPointer< Poppler::Page > page(document->page(0));
|
|
+ QVERIFY( page );
|
|
+
|
|
+ const Poppler::Page::SearchDirection direction = Poppler::Page::FromTop;
|
|
+
|
|
+ const Poppler::Page::SearchFlags mode0 = 0;
|
|
+ const Poppler::Page::SearchFlags mode1 = Poppler::Page::IgnoreCase;
|
|
+ const Poppler::Page::SearchFlags mode2 = Poppler::Page::WholeWords;
|
|
+ const Poppler::Page::SearchFlags mode3 = Poppler::Page::IgnoreCase | Poppler::Page::WholeWords;
|
|
+
|
|
+ double left, top, right, bottom;
|
|
+
|
|
+ QCOMPARE( page->search(QLatin1String("brown"), left, top, right, bottom, direction, mode0), true );
|
|
+ QCOMPARE( page->search(QLatin1String("brOwn"), left, top, right, bottom, direction, mode0), false );
|
|
+
|
|
+ QCOMPARE( page->search(QLatin1String("brOwn"), left, top, right, bottom, direction, mode1), true );
|
|
+ QCOMPARE( page->search(QLatin1String("brawn"), left, top, right, bottom, direction, mode1), false );
|
|
+
|
|
+ QCOMPARE( page->search(QLatin1String("brown"), left, top, right, bottom, direction, mode2), true );
|
|
+ QCOMPARE( page->search(QLatin1String("own"), left, top, right, bottom, direction, mode2), false );
|
|
+
|
|
+ QCOMPARE( page->search(QLatin1String("brOwn"), left, top, right, bottom, direction, mode3), true );
|
|
+ QCOMPARE( page->search(QLatin1String("Own"), left, top, right, bottom, direction, mode3), false );
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestSearch)
|
|
+#include "check_search.moc"
|
|
+
|
|
diff --git a/qt4/tests/check_strings.cpp b/qt4/tests/check_strings.cpp
|
|
new file mode 100644
|
|
index 00000000..700ae9c2
|
|
--- /dev/null
|
|
+++ b/qt4/tests/check_strings.cpp
|
|
@@ -0,0 +1,250 @@
|
|
+/*
|
|
+ * Copyright (C) 2010, 2011, Pino Toscano <pino@kde.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2, or (at your option)
|
|
+ * any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ */
|
|
+
|
|
+#include <QtTest/QtTest>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+#include <poppler-private.h>
|
|
+
|
|
+#include <GlobalParams.h>
|
|
+
|
|
+Q_DECLARE_METATYPE(GooString*)
|
|
+Q_DECLARE_METATYPE(Unicode*)
|
|
+
|
|
+class TestStrings : public QObject
|
|
+{
|
|
+ Q_OBJECT
|
|
+
|
|
+private slots:
|
|
+ void initTestCase();
|
|
+ void cleanupTestCase();
|
|
+ void check_unicodeToQString_data();
|
|
+ void check_unicodeToQString();
|
|
+ void check_UnicodeParsedString_data();
|
|
+ void check_UnicodeParsedString();
|
|
+ void check_QStringToUnicodeGooString_data();
|
|
+ void check_QStringToUnicodeGooString();
|
|
+ void check_QStringToGooString_data();
|
|
+ void check_QStringToGooString();
|
|
+
|
|
+private:
|
|
+ GooString* newGooString(const char *s);
|
|
+ GooString* newGooString(const char *s, int l);
|
|
+
|
|
+ QVector<GooString *> m_gooStrings;
|
|
+};
|
|
+
|
|
+void TestStrings::initTestCase()
|
|
+{
|
|
+ qRegisterMetaType<GooString*>("GooString*");
|
|
+ qRegisterMetaType<Unicode*>("Unicode*");
|
|
+
|
|
+ globalParams = std::make_unique<GlobalParams>();
|
|
+}
|
|
+
|
|
+void TestStrings::cleanupTestCase()
|
|
+{
|
|
+ qDeleteAll(m_gooStrings);
|
|
+
|
|
+ globalParams.reset();
|
|
+}
|
|
+
|
|
+void TestStrings::check_unicodeToQString_data()
|
|
+{
|
|
+ QTest::addColumn<Unicode*>("data");
|
|
+ QTest::addColumn<int>("length");
|
|
+ QTest::addColumn<QString>("result");
|
|
+
|
|
+ {
|
|
+ const int l = 1;
|
|
+ Unicode *u = new Unicode[l];
|
|
+ u[0] = int('a');
|
|
+ QTest::newRow("a") << u << l << QString::fromUtf8("a");
|
|
+ }
|
|
+ {
|
|
+ const int l = 1;
|
|
+ Unicode *u = new Unicode[l];
|
|
+ u[0] = 0x0161;
|
|
+ QTest::newRow("\u0161") << u << l << QString::fromUtf8("\u0161");
|
|
+ }
|
|
+ {
|
|
+ const int l = 2;
|
|
+ Unicode *u = new Unicode[l];
|
|
+ u[0] = int('a');
|
|
+ u[1] = int('b');
|
|
+ QTest::newRow("ab") << u << l << QString::fromUtf8("ab");
|
|
+ }
|
|
+ {
|
|
+ const int l = 2;
|
|
+ Unicode *u = new Unicode[l];
|
|
+ u[0] = int('a');
|
|
+ u[1] = 0x0161;
|
|
+ QTest::newRow("a\u0161") << u << l << QString::fromUtf8("a\u0161");
|
|
+ }
|
|
+ {
|
|
+ const int l = 2;
|
|
+ Unicode *u = new Unicode[l];
|
|
+ u[0] = 0x5c01;
|
|
+ u[1] = 0x9762;
|
|
+ QTest::newRow("\xe5\xb0\x81\xe9\x9d\xa2") << u << l << QString::fromUtf8("\xe5\xb0\x81\xe9\x9d\xa2");
|
|
+ }
|
|
+ {
|
|
+ const int l = 3;
|
|
+ Unicode *u = new Unicode[l];
|
|
+ u[0] = 0x5c01;
|
|
+ u[1] = 0x9762;
|
|
+ u[2] = 0x0;
|
|
+ QTest::newRow("\xe5\xb0\x81\xe9\x9d\xa2 + 0") << u << l << QString::fromUtf8("\xe5\xb0\x81\xe9\x9d\xa2");
|
|
+ }
|
|
+}
|
|
+
|
|
+void TestStrings::check_unicodeToQString()
|
|
+{
|
|
+ QFETCH(Unicode*, data);
|
|
+ QFETCH(int, length);
|
|
+ QFETCH(QString, result);
|
|
+
|
|
+ QCOMPARE(Poppler::unicodeToQString(data, length), result);
|
|
+
|
|
+ delete [] data;
|
|
+}
|
|
+
|
|
+void TestStrings::check_UnicodeParsedString_data()
|
|
+{
|
|
+ QTest::addColumn<GooString*>("string");
|
|
+ QTest::addColumn<QString>("result");
|
|
+
|
|
+ // non-unicode strings
|
|
+ QTest::newRow("<empty>") << newGooString("")
|
|
+ << QString();
|
|
+ QTest::newRow("a") << newGooString("a")
|
|
+ << QString::fromUtf8("a");
|
|
+ QTest::newRow("ab") << newGooString("ab")
|
|
+ << QString::fromUtf8("ab");
|
|
+ QTest::newRow("~") << newGooString("~")
|
|
+ << QString::fromUtf8("~");
|
|
+ QTest::newRow("test string") << newGooString("test string")
|
|
+ << QString::fromUtf8("test string");
|
|
+
|
|
+ // unicode strings
|
|
+ QTest::newRow("<unicode marks>") << newGooString("\xFE\xFF")
|
|
+ << QString();
|
|
+ QTest::newRow("U a") << newGooString("\xFE\xFF\0a", 4)
|
|
+ << QString::fromUtf8("a");
|
|
+ QTest::newRow("U ~") << newGooString("\xFE\xFF\0~", 4)
|
|
+ << QString::fromUtf8("~");
|
|
+ QTest::newRow("U aa") << newGooString("\xFE\xFF\0a\0a", 6)
|
|
+ << QString::fromUtf8("aa");
|
|
+ QTest::newRow("U \xC3\x9F") << newGooString("\xFE\xFF\0\xDF", 4)
|
|
+ << QString::fromUtf8("\xC3\x9F");
|
|
+ QTest::newRow("U \xC3\x9F\x61") << newGooString("\xFE\xFF\0\xDF\0\x61", 6)
|
|
+ << QString::fromUtf8("\xC3\x9F\x61");
|
|
+ QTest::newRow("U \xC5\xA1") << newGooString("\xFE\xFF\x01\x61", 4)
|
|
+ << QString::fromUtf8("\xC5\xA1");
|
|
+ QTest::newRow("U \xC5\xA1\x61") << newGooString("\xFE\xFF\x01\x61\0\x61", 6)
|
|
+ << QString::fromUtf8("\xC5\xA1\x61");
|
|
+ QTest::newRow("test string") << newGooString("\xFE\xFF\0t\0e\0s\0t\0 \0s\0t\0r\0i\0n\0g", 24)
|
|
+ << QString::fromUtf8("test string");
|
|
+}
|
|
+
|
|
+void TestStrings::check_UnicodeParsedString()
|
|
+{
|
|
+ QFETCH(GooString*, string);
|
|
+ QFETCH(QString, result);
|
|
+
|
|
+ QCOMPARE(Poppler::UnicodeParsedString(string), result);
|
|
+}
|
|
+
|
|
+void TestStrings::check_QStringToUnicodeGooString_data()
|
|
+{
|
|
+ QTest::addColumn<QString>("string");
|
|
+ QTest::addColumn<QByteArray>("result");
|
|
+
|
|
+
|
|
+ QTest::newRow("<null>") << QString()
|
|
+ << QByteArray("");
|
|
+ QTest::newRow("<empty>") << QString::fromUtf8("")
|
|
+ << QByteArray("");
|
|
+ QTest::newRow("a") << QString::fromUtf8("a")
|
|
+ << QByteArray("\0a", 2);
|
|
+ QTest::newRow("ab") << QString::fromUtf8("ab")
|
|
+ << QByteArray("\0a\0b", 4);
|
|
+ QTest::newRow("test string") << QString::fromUtf8("test string")
|
|
+ << QByteArray("\0t\0e\0s\0t\0 \0s\0t\0r\0i\0n\0g", 22);
|
|
+ QTest::newRow("\xC3\x9F") << QString::fromUtf8("\xC3\x9F")
|
|
+ << QByteArray("\0\xDF", 2);
|
|
+ QTest::newRow("\xC3\x9F\x61") << QString::fromUtf8("\xC3\x9F\x61")
|
|
+ << QByteArray("\0\xDF\0\x61", 4);
|
|
+}
|
|
+
|
|
+void TestStrings::check_QStringToUnicodeGooString()
|
|
+{
|
|
+ QFETCH(QString, string);
|
|
+ QFETCH(QByteArray, result);
|
|
+
|
|
+ GooString *goo = Poppler::QStringToUnicodeGooString(string);
|
|
+ QVERIFY(goo->hasUnicodeMarker());
|
|
+ QCOMPARE(goo->getLength(), string.length() * 2 + 2);
|
|
+ QCOMPARE(result, QByteArray::fromRawData(goo->c_str() + 2, goo->getLength() - 2));
|
|
+
|
|
+ delete goo;
|
|
+}
|
|
+
|
|
+void TestStrings::check_QStringToGooString_data()
|
|
+{
|
|
+ QTest::addColumn<QString>("string");
|
|
+ QTest::addColumn<GooString*>("result");
|
|
+
|
|
+ QTest::newRow("<null>") << QString()
|
|
+ << newGooString("");
|
|
+ QTest::newRow("<empty>") << QString::fromUtf8("")
|
|
+ << newGooString("");
|
|
+ QTest::newRow("a") << QString::fromUtf8("a")
|
|
+ << newGooString("a");
|
|
+ QTest::newRow("ab") << QString::fromUtf8("ab")
|
|
+ << newGooString("ab");
|
|
+}
|
|
+
|
|
+void TestStrings::check_QStringToGooString()
|
|
+{
|
|
+ QFETCH(QString, string);
|
|
+ QFETCH(GooString*, result);
|
|
+
|
|
+ GooString *goo = Poppler::QStringToGooString(string);
|
|
+ QCOMPARE(goo->c_str(), result->c_str());
|
|
+
|
|
+ delete goo;
|
|
+}
|
|
+
|
|
+GooString* TestStrings::newGooString(const char *s)
|
|
+{
|
|
+ GooString *goo = new GooString(s);
|
|
+ m_gooStrings.append(goo);
|
|
+ return goo;
|
|
+}
|
|
+
|
|
+GooString* TestStrings::newGooString(const char *s, int l)
|
|
+{
|
|
+ GooString *goo = new GooString(s, l);
|
|
+ m_gooStrings.append(goo);
|
|
+ return goo;
|
|
+}
|
|
+
|
|
+QTEST_MAIN(TestStrings)
|
|
+
|
|
+#include "check_strings.moc"
|
|
diff --git a/qt4/tests/poppler-attachments.cpp b/qt4/tests/poppler-attachments.cpp
|
|
new file mode 100644
|
|
index 00000000..992dc565
|
|
--- /dev/null
|
|
+++ b/qt4/tests/poppler-attachments.cpp
|
|
@@ -0,0 +1,39 @@
|
|
+#include <QtCore/QCoreApplication>
|
|
+#include <QtCore/QDebug>
|
|
+
|
|
+#include <iostream>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+int main( int argc, char **argv )
|
|
+{
|
|
+ QCoreApplication a( argc, argv ); // QApplication required!
|
|
+
|
|
+ if (!( argc == 2 ))
|
|
+ {
|
|
+ qWarning() << "usage: poppler-attachments filename";
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ Poppler::Document *doc = Poppler::Document::load(argv[1]);
|
|
+ if (!doc)
|
|
+ {
|
|
+ qWarning() << "doc not loaded";
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ if (doc->hasEmbeddedFiles()) {
|
|
+ std::cout << "Embedded files: " << std::endl;
|
|
+ foreach(Poppler::EmbeddedFile *file, doc->embeddedFiles()) {
|
|
+ std::cout << " " << qPrintable(file->name()) << std::endl;
|
|
+ std::cout << " desc:" << qPrintable(file->description()) << std::endl;
|
|
+ QByteArray data = file->data();
|
|
+ std::cout << " data: " << data.constData() << std::endl;
|
|
+ }
|
|
+
|
|
+ } else {
|
|
+ std::cout << "There are no embedded document at the top level" << std::endl;
|
|
+ }
|
|
+ delete doc;
|
|
+
|
|
+}
|
|
diff --git a/qt4/tests/poppler-fonts.cpp b/qt4/tests/poppler-fonts.cpp
|
|
new file mode 100644
|
|
index 00000000..6b66ec42
|
|
--- /dev/null
|
|
+++ b/qt4/tests/poppler-fonts.cpp
|
|
@@ -0,0 +1,89 @@
|
|
+#include <QtCore/QCoreApplication>
|
|
+#include <QtCore/QDebug>
|
|
+
|
|
+#include <iostream>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+int main( int argc, char **argv )
|
|
+{
|
|
+ QCoreApplication a( argc, argv ); // QApplication required!
|
|
+
|
|
+ if (!( argc == 2 ))
|
|
+ {
|
|
+ qWarning() << "usage: poppler-fonts filename";
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ Poppler::Document *doc = Poppler::Document::load(argv[1]);
|
|
+ if (!doc)
|
|
+ {
|
|
+ qWarning() << "doc not loaded";
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ std::cout << "name type emb sub font file";
|
|
+ std::cout << std::endl;
|
|
+ std::cout << "------------------------------------ ------------ --- --- ---------";
|
|
+ std::cout << std::endl;
|
|
+
|
|
+ foreach( const Poppler::FontInfo &font, doc->fonts() ) {
|
|
+ if (font.name().isNull()) {
|
|
+ std::cout << qPrintable( QString("%1").arg(QString("[none]"), -37) );
|
|
+ } else {
|
|
+ std::cout << qPrintable( QString("%1").arg(font.name(), -37) );
|
|
+ }
|
|
+ switch( font.type() ) {
|
|
+ case Poppler::FontInfo::unknown:
|
|
+ std::cout << "unknown ";
|
|
+ break;
|
|
+ case Poppler::FontInfo::Type1:
|
|
+ std::cout << "Type 1 ";
|
|
+ break;
|
|
+ case Poppler::FontInfo::Type1C:
|
|
+ std::cout << "Type 1C ";
|
|
+ break;
|
|
+ case Poppler::FontInfo::Type3:
|
|
+ std::cout << "Type 3 ";
|
|
+ break;
|
|
+ case Poppler::FontInfo::TrueType:
|
|
+ std::cout << "TrueType ";
|
|
+ break;
|
|
+ case Poppler::FontInfo::CIDType0:
|
|
+ std::cout << "CID Type 0 ";
|
|
+ break;
|
|
+ case Poppler::FontInfo::CIDType0C:
|
|
+ std::cout << "CID Type 0C ";
|
|
+ break;
|
|
+ case Poppler::FontInfo::CIDTrueType:
|
|
+ std::cout << "CID TrueType ";
|
|
+ break;
|
|
+ case Poppler::FontInfo::Type1COT:
|
|
+ std::cout << "Type 1C (OT) ";
|
|
+ break;
|
|
+ case Poppler::FontInfo::TrueTypeOT:
|
|
+ std::cout << "TrueType (OT) ";
|
|
+ break;
|
|
+ case Poppler::FontInfo::CIDType0COT:
|
|
+ std::cout << "CID Type 0C (OT) ";
|
|
+ break;
|
|
+ case Poppler::FontInfo::CIDTrueTypeOT:
|
|
+ std::cout << "CID TrueType (OT) ";
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if ( font.isEmbedded() ) {
|
|
+ std::cout << "yes ";
|
|
+ } else {
|
|
+ std::cout << "no ";
|
|
+ }
|
|
+ if ( font.isSubset() ) {
|
|
+ std::cout << "yes ";
|
|
+ } else {
|
|
+ std::cout << "no ";
|
|
+ }
|
|
+ std::cout << qPrintable( QString("%1").arg(font.file()) );
|
|
+ std::cout << std::endl;
|
|
+ }
|
|
+ delete doc;
|
|
+}
|
|
diff --git a/qt4/tests/poppler-forms.cpp b/qt4/tests/poppler-forms.cpp
|
|
new file mode 100644
|
|
index 00000000..98891a91
|
|
--- /dev/null
|
|
+++ b/qt4/tests/poppler-forms.cpp
|
|
@@ -0,0 +1,166 @@
|
|
+#include <QtCore/QCoreApplication>
|
|
+#include <QtCore/QDebug>
|
|
+
|
|
+#include <iostream>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+#include <poppler-form.h>
|
|
+
|
|
+static std::ostream& operator<< (std::ostream &out, Poppler::FormField::FormType type)
|
|
+{
|
|
+ switch (type) {
|
|
+ case Poppler::FormField::FormButton: out << "Button"; break;
|
|
+ case Poppler::FormField::FormText: out << "Text"; break;
|
|
+ case Poppler::FormField::FormChoice: out << "Choice"; break;
|
|
+ case Poppler::FormField::FormSignature: out << "Signature"; break;
|
|
+ }
|
|
+ return out;
|
|
+}
|
|
+
|
|
+static std::ostream& operator<< (std::ostream &out, Poppler::FormFieldButton::ButtonType type)
|
|
+{
|
|
+ switch (type) {
|
|
+ case Poppler::FormFieldButton::Push: out << "Push"; break;
|
|
+ case Poppler::FormFieldButton::CheckBox: out << "CheckBox"; break;
|
|
+ case Poppler::FormFieldButton::Radio: out << "Radio"; break;
|
|
+ }
|
|
+ return out;
|
|
+}
|
|
+
|
|
+static std::ostream& operator<< (std::ostream &out, Poppler::FormFieldText::TextType type)
|
|
+{
|
|
+ switch (type) {
|
|
+ case Poppler::FormFieldText::Normal: out << "Normal"; break;
|
|
+ case Poppler::FormFieldText::Multiline: out << "Multiline"; break;
|
|
+ case Poppler::FormFieldText::FileSelect: out << "FileSelect"; break;
|
|
+ }
|
|
+ return out;
|
|
+}
|
|
+
|
|
+static std::ostream& operator<< (std::ostream &out, Poppler::FormFieldChoice::ChoiceType type)
|
|
+{
|
|
+ switch (type) {
|
|
+ case Poppler::FormFieldChoice::ComboBox: out << "ComboBox"; break;
|
|
+ case Poppler::FormFieldChoice::ListBox: out << "ListBox"; break;
|
|
+ }
|
|
+ return out;
|
|
+}
|
|
+
|
|
+static std::ostream& operator<< (std::ostream &out, Qt::Alignment alignment)
|
|
+{
|
|
+ switch (alignment) {
|
|
+ case Qt::AlignLeft: out << "Left"; break;
|
|
+ case Qt::AlignRight: out << "Right"; break;
|
|
+ case Qt::AlignHCenter: out << "HCenter"; break;
|
|
+ case Qt::AlignJustify: out << "Justify"; break;
|
|
+ case Qt::AlignTop: out << "Top"; break;
|
|
+ case Qt::AlignBottom: out << "Bottom"; break;
|
|
+ case Qt::AlignVCenter: out << "VCenter"; break;
|
|
+ case Qt::AlignCenter: out << "Center"; break;
|
|
+ case Qt::AlignAbsolute: out << "Absolute"; break;
|
|
+ }
|
|
+ return out;
|
|
+}
|
|
+
|
|
+static std::ostream& operator<< (std::ostream &out, const QString &string)
|
|
+{
|
|
+ out << string.toUtf8().constData();
|
|
+ return out;
|
|
+}
|
|
+
|
|
+static std::ostream& operator<< (std::ostream &out, const QRectF &rect)
|
|
+{
|
|
+ out << QString("top: %1 left: %2 width: %3 height: %4").arg(rect.x()).arg(rect.y()).arg(rect.width()).arg(rect.height());
|
|
+ return out;
|
|
+}
|
|
+
|
|
+template<typename T>
|
|
+std::ostream& operator<< (std::ostream &out, const QList<T> &elems)
|
|
+{
|
|
+ bool isFirst = true;
|
|
+ for (int i = 0; i < elems.count(); ++i) {
|
|
+ if (!isFirst)
|
|
+ out << " ";
|
|
+ out << elems[i];
|
|
+ isFirst = false;
|
|
+ }
|
|
+ return out;
|
|
+}
|
|
+
|
|
+int main( int argc, char **argv )
|
|
+{
|
|
+ QCoreApplication a( argc, argv );
|
|
+
|
|
+ if (!( argc == 2 ))
|
|
+ {
|
|
+ qWarning() << "usage: poppler-forms filename";
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ Poppler::Document *doc = Poppler::Document::load(argv[1]);
|
|
+ if (!doc)
|
|
+ {
|
|
+ qWarning() << "doc not loaded";
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ std::cout << "Forms for file " << argv[1] << std::endl;
|
|
+ for (int i = 0; i < doc->numPages(); ++i) {
|
|
+ Poppler::Page *page = doc->page(i);
|
|
+ if (page) {
|
|
+ QList<Poppler::FormField*> forms = page->formFields();
|
|
+ std::cout << "\tPage " << i + 1 << std::endl;
|
|
+ foreach( const Poppler::FormField *form, forms ) {
|
|
+ std::cout << "\t\tForm" << std::endl;
|
|
+ std::cout << "\t\t\tType: " << form->type() << std::endl;
|
|
+ std::cout << "\t\t\tRect: " << form->rect() << std::endl;
|
|
+ std::cout << "\t\t\tID: " << form->id() << std::endl;
|
|
+ std::cout << "\t\t\tName: " << form->name() << std::endl;
|
|
+ std::cout << "\t\t\tFullyQualifiedName: " << form->fullyQualifiedName() << std::endl;
|
|
+ std::cout << "\t\t\tUIName: " << form->uiName() << std::endl;
|
|
+ std::cout << "\t\t\tReadOnly: " << form->isReadOnly() << std::endl;
|
|
+ std::cout << "\t\t\tVisible: " << form->isVisible() << std::endl;
|
|
+ switch (form->type()) {
|
|
+ case Poppler::FormField::FormButton: {
|
|
+ const Poppler::FormFieldButton *buttonForm = static_cast<const Poppler::FormFieldButton *>(form);
|
|
+ std::cout << "\t\t\tButtonType: " << buttonForm->buttonType() << std::endl;
|
|
+ std::cout << "\t\t\tCaption: " << buttonForm->caption() << std::endl;
|
|
+ std::cout << "\t\t\tState: " << buttonForm->state() << std::endl;
|
|
+ std::cout << "\t\t\tSiblings: " << buttonForm->siblings() << std::endl;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case Poppler::FormField::FormText: {
|
|
+ const Poppler::FormFieldText *textForm = static_cast<const Poppler::FormFieldText *>(form);
|
|
+ std::cout << "\t\t\tTextType: " << textForm->textType() << std::endl;
|
|
+ std::cout << "\t\t\tText: " << textForm->text() << std::endl;
|
|
+ std::cout << "\t\t\tIsPassword: " << textForm->isPassword() << std::endl;
|
|
+ std::cout << "\t\t\tIsRichText: " << textForm->isRichText() << std::endl;
|
|
+ std::cout << "\t\t\tMaximumLength: " << textForm->maximumLength() << std::endl;
|
|
+ std::cout << "\t\t\tTextAlignment: " << textForm->textAlignment() << std::endl;
|
|
+ std::cout << "\t\t\tCanBeSpellChecked: " << textForm->canBeSpellChecked() << std::endl;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case Poppler::FormField::FormChoice: {
|
|
+ const Poppler::FormFieldChoice *choiceForm = static_cast<const Poppler::FormFieldChoice *>(form);
|
|
+ std::cout << "\t\t\tChoiceType: " << choiceForm->choiceType() << std::endl;
|
|
+ std::cout << "\t\t\tChoices: " << choiceForm->choices() << std::endl;
|
|
+ std::cout << "\t\t\tIsEditable: " << choiceForm->isEditable() << std::endl;
|
|
+ std::cout << "\t\t\tIsMultiSelect: " << choiceForm->multiSelect() << std::endl;
|
|
+ std::cout << "\t\t\tCurrentChoices: " << choiceForm->currentChoices() << std::endl;
|
|
+ std::cout << "\t\t\tEditChoice: " << choiceForm->editChoice() << std::endl;
|
|
+ std::cout << "\t\t\tTextAlignment: " << choiceForm->textAlignment() << std::endl;
|
|
+ std::cout << "\t\t\tCanBeSpellChecked: " << choiceForm->canBeSpellChecked() << std::endl;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case Poppler::FormField::FormSignature:
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ qDeleteAll(forms);
|
|
+ }
|
|
+ }
|
|
+ delete doc;
|
|
+}
|
|
diff --git a/qt4/tests/poppler-texts.cpp b/qt4/tests/poppler-texts.cpp
|
|
new file mode 100644
|
|
index 00000000..ec283531
|
|
--- /dev/null
|
|
+++ b/qt4/tests/poppler-texts.cpp
|
|
@@ -0,0 +1,40 @@
|
|
+#include <QtCore/QCoreApplication>
|
|
+#include <QtCore/QDebug>
|
|
+
|
|
+#include <iostream>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+int main( int argc, char **argv )
|
|
+{
|
|
+ QCoreApplication a( argc, argv ); // QApplication required!
|
|
+
|
|
+ if (!( argc == 2 ))
|
|
+ {
|
|
+ qWarning() << "usage: poppler-texts filename";
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ Poppler::Document *doc = Poppler::Document::load(argv[1]);
|
|
+ if (!doc)
|
|
+ {
|
|
+ qWarning() << "doc not loaded";
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ for ( int i = 0; i < doc->numPages(); i++ )
|
|
+ {
|
|
+ int j = 0;
|
|
+ std::cout << "*** Page " << i << std::endl;
|
|
+ std::cout << std::flush;
|
|
+
|
|
+ Poppler::Page *page = doc->page(i);
|
|
+ const QByteArray utf8str = page->text( QRectF(), Poppler::Page::RawOrderLayout ).toUtf8();
|
|
+ std::cout << std::flush;
|
|
+ for ( j = 0; j < utf8str.size(); j++ )
|
|
+ std::cout << utf8str[j];
|
|
+ std::cout << std::endl;
|
|
+ delete page;
|
|
+ }
|
|
+ delete doc;
|
|
+}
|
|
diff --git a/qt4/tests/stress-poppler-dir.cpp b/qt4/tests/stress-poppler-dir.cpp
|
|
new file mode 100644
|
|
index 00000000..6eeab6fa
|
|
--- /dev/null
|
|
+++ b/qt4/tests/stress-poppler-dir.cpp
|
|
@@ -0,0 +1,67 @@
|
|
+#include <QtCore/QDebug>
|
|
+#include <QtCore/QDir>
|
|
+#include <QtCore/QTime>
|
|
+#include <QtGui/QApplication>
|
|
+#include <QtGui/QImage>
|
|
+
|
|
+#include <iostream>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+int main( int argc, char **argv )
|
|
+{
|
|
+ QApplication a( argc, argv ); // QApplication required!
|
|
+
|
|
+ QTime t;
|
|
+ t.start();
|
|
+
|
|
+ QDir directory( argv[1] );
|
|
+ foreach ( const QString &fileName, directory.entryList() ) {
|
|
+ if (fileName.endsWith("pdf") ) {
|
|
+ qDebug() << "Doing" << fileName.toLatin1().data() << ":";
|
|
+ Poppler::Document *doc = Poppler::Document::load( directory.canonicalPath()+"/"+fileName );
|
|
+ if (!doc) {
|
|
+ qWarning() << "doc not loaded";
|
|
+ } else if ( doc->isLocked() ) {
|
|
+ if (! doc->unlock( "", "password" ) ) {
|
|
+ qWarning() << "couldn't unlock document";
|
|
+ delete doc;
|
|
+ }
|
|
+ } else {
|
|
+ int major = 0, minor = 0;
|
|
+ doc->getPdfVersion( &major, &minor );
|
|
+ doc->info("Title");
|
|
+ doc->info("Subject");
|
|
+ doc->info("Author");
|
|
+ doc->info("Keywords");
|
|
+ doc->info("Creator");
|
|
+ doc->info("Producer");
|
|
+ doc->date("CreationDate").toString();
|
|
+ doc->date("ModDate").toString();
|
|
+ doc->numPages();
|
|
+ doc->isLinearized();
|
|
+ doc->isEncrypted();
|
|
+ doc->okToPrint();
|
|
+ doc->okToCopy();
|
|
+ doc->okToChange();
|
|
+ doc->okToAddNotes();
|
|
+ doc->pageMode();
|
|
+
|
|
+ for( int index = 0; index < doc->numPages(); ++index ) {
|
|
+ Poppler::Page *page = doc->page( index );
|
|
+ QImage image = page->renderToImage();
|
|
+ page->pageSize();
|
|
+ page->orientation();
|
|
+ delete page;
|
|
+ std::cout << ".";
|
|
+ std::cout.flush();
|
|
+ }
|
|
+ std::cout << std::endl;
|
|
+ delete doc;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ std::cout << "Elapsed time: " << (t.elapsed()/1000) << "seconds" << std::endl;
|
|
+
|
|
+}
|
|
diff --git a/qt4/tests/stress-poppler-qt4.cpp b/qt4/tests/stress-poppler-qt4.cpp
|
|
new file mode 100644
|
|
index 00000000..56844543
|
|
--- /dev/null
|
|
+++ b/qt4/tests/stress-poppler-qt4.cpp
|
|
@@ -0,0 +1,74 @@
|
|
+#include <QtCore/QDebug>
|
|
+#include <QtCore/QDir>
|
|
+#include <QtCore/QTime>
|
|
+#include <QtGui/QApplication>
|
|
+#include <QtGui/QImage>
|
|
+
|
|
+#include <iostream>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+int main( int argc, char **argv )
|
|
+{
|
|
+ QApplication a( argc, argv ); // QApplication required!
|
|
+
|
|
+ Q_UNUSED( argc );
|
|
+ Q_UNUSED( argv );
|
|
+
|
|
+ QTime t;
|
|
+ t.start();
|
|
+ QDir dbDir( QString( "./pdfdb" ) );
|
|
+ if ( !dbDir.exists() ) {
|
|
+ qWarning() << "Database directory does not exist";
|
|
+ }
|
|
+
|
|
+ QStringList excludeSubDirs;
|
|
+ excludeSubDirs << "000048" << "000607";
|
|
+
|
|
+ foreach ( const QString &subdir, dbDir.entryList(QStringList() << "0000*", QDir::Dirs) ) {
|
|
+ if ( excludeSubDirs.contains(subdir) ) {
|
|
+ // then skip it
|
|
+ } else {
|
|
+ QString path = "./pdfdb/" + subdir + "/data.pdf";
|
|
+ std::cout <<"Doing " << path.toLatin1().data() << " :";
|
|
+ Poppler::Document *doc = Poppler::Document::load( path );
|
|
+ if (!doc) {
|
|
+ qWarning() << "doc not loaded";
|
|
+ } else {
|
|
+ int major = 0, minor = 0;
|
|
+ doc->getPdfVersion( &major, &minor );
|
|
+ doc->info("Title");
|
|
+ doc->info("Subject");
|
|
+ doc->info("Author");
|
|
+ doc->info("Keywords");
|
|
+ doc->info("Creator");
|
|
+ doc->info("Producer");
|
|
+ doc->date("CreationDate").toString();
|
|
+ doc->date("ModDate").toString();
|
|
+ doc->numPages();
|
|
+ doc->isLinearized();
|
|
+ doc->isEncrypted();
|
|
+ doc->okToPrint();
|
|
+ doc->okToCopy();
|
|
+ doc->okToChange();
|
|
+ doc->okToAddNotes();
|
|
+ doc->pageMode();
|
|
+
|
|
+ for( int index = 0; index < doc->numPages(); ++index ) {
|
|
+ Poppler::Page *page = doc->page( index );
|
|
+ QImage image = page->renderToImage();
|
|
+ page->pageSize();
|
|
+ page->orientation();
|
|
+ delete page;
|
|
+ std::cout << ".";
|
|
+ std::cout.flush();
|
|
+ }
|
|
+ std::cout << std::endl;
|
|
+ delete doc;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ std::cout << "Elapsed time: " << (t.elapsed()/1000) << std::endl;
|
|
+
|
|
+}
|
|
diff --git a/qt4/tests/stress-threads-qt4.cpp b/qt4/tests/stress-threads-qt4.cpp
|
|
new file mode 100644
|
|
index 00000000..00968de1
|
|
--- /dev/null
|
|
+++ b/qt4/tests/stress-threads-qt4.cpp
|
|
@@ -0,0 +1,309 @@
|
|
+
|
|
+#ifndef _WIN32
|
|
+#include <unistd.h>
|
|
+#else
|
|
+#include <windows.h>
|
|
+#define sleep Sleep
|
|
+#endif
|
|
+#include <time.h>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+#include <poppler-form.h>
|
|
+
|
|
+#include <QtCore/QDebug>
|
|
+#include <QtCore/QFile>
|
|
+#include <QtCore/QMutex>
|
|
+#include <QtCore/QThread>
|
|
+#include <QtGui/QImage>
|
|
+
|
|
+class SillyThread : public QThread
|
|
+{
|
|
+public:
|
|
+ SillyThread(Poppler::Document* document, QObject* parent = 0);
|
|
+
|
|
+ void run();
|
|
+
|
|
+private:
|
|
+ Poppler::Document* m_document;
|
|
+ QVector< Poppler::Page* > m_pages;
|
|
+
|
|
+};
|
|
+
|
|
+class CrazyThread : public QThread
|
|
+{
|
|
+public:
|
|
+ CrazyThread(uint seed, Poppler::Document* document, QMutex* annotationMutex, QObject* parent = 0);
|
|
+
|
|
+ void run();
|
|
+
|
|
+private:
|
|
+ uint m_seed;
|
|
+ Poppler::Document* m_document;
|
|
+ QMutex* m_annotationMutex;
|
|
+
|
|
+};
|
|
+
|
|
+static Poppler::Page* loadPage(Poppler::Document* document, int index)
|
|
+{
|
|
+ Poppler::Page* page = document->page(index);
|
|
+
|
|
+ if(page == 0)
|
|
+ {
|
|
+ qDebug() << "!Document::page";
|
|
+
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+
|
|
+ return page;
|
|
+}
|
|
+
|
|
+static Poppler::Page* loadRandomPage(Poppler::Document* document)
|
|
+{
|
|
+ return loadPage(document, qrand() % document->numPages());
|
|
+}
|
|
+
|
|
+SillyThread::SillyThread(Poppler::Document* document, QObject* parent) : QThread(parent),
|
|
+ m_document(document),
|
|
+ m_pages()
|
|
+{
|
|
+ m_pages.reserve(m_document->numPages());
|
|
+
|
|
+ for(int index = 0; index < m_document->numPages(); ++index)
|
|
+ {
|
|
+ m_pages.append(loadPage(m_document, index));
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+void SillyThread::run()
|
|
+{
|
|
+ forever
|
|
+ {
|
|
+ foreach(Poppler::Page* page, m_pages)
|
|
+ {
|
|
+ QImage image = page->renderToImage();
|
|
+
|
|
+ if(image.isNull())
|
|
+ {
|
|
+ qDebug() << "!Page::renderToImage";
|
|
+
|
|
+ ::exit(EXIT_FAILURE);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+CrazyThread::CrazyThread(uint seed, Poppler::Document* document, QMutex* annotationMutex, QObject* parent) : QThread(parent),
|
|
+ m_seed(seed),
|
|
+ m_document(document),
|
|
+ m_annotationMutex(annotationMutex)
|
|
+{
|
|
+}
|
|
+
|
|
+void CrazyThread::run()
|
|
+{
|
|
+ typedef QScopedPointer< Poppler::Page > PagePointer;
|
|
+
|
|
+ qsrand(m_seed);
|
|
+
|
|
+ forever
|
|
+ {
|
|
+ if(qrand() % 2 == 0)
|
|
+ {
|
|
+ qDebug() << "search...";
|
|
+
|
|
+ PagePointer page(loadRandomPage(m_document));
|
|
+
|
|
+ page->search("c", Poppler::Page::CaseInsensitive);
|
|
+ page->search("r", Poppler::Page::CaseSensitive);
|
|
+ page->search("a", Poppler::Page::CaseInsensitive);
|
|
+ page->search("z", Poppler::Page::CaseSensitive);
|
|
+ page->search("y", Poppler::Page::CaseInsensitive);
|
|
+ }
|
|
+
|
|
+ if(qrand() % 2 == 0)
|
|
+ {
|
|
+ qDebug() << "links...";
|
|
+
|
|
+ PagePointer page(loadRandomPage(m_document));
|
|
+
|
|
+ QList< Poppler::Link* > links = page->links();
|
|
+
|
|
+ qDeleteAll(links);
|
|
+ }
|
|
+
|
|
+ if(qrand() % 2 == 0)
|
|
+ {
|
|
+ qDebug() << "form fields...";
|
|
+
|
|
+ PagePointer page(loadRandomPage(m_document));
|
|
+
|
|
+ QList< Poppler::FormField* > formFields = page->formFields();
|
|
+
|
|
+ qDeleteAll(formFields);
|
|
+ }
|
|
+
|
|
+ if(qrand() % 2 == 0)
|
|
+ {
|
|
+ qDebug() << "thumbnail...";
|
|
+
|
|
+ PagePointer page(loadRandomPage(m_document));
|
|
+
|
|
+ page->thumbnail();
|
|
+ }
|
|
+
|
|
+ if(qrand() % 2 == 0)
|
|
+ {
|
|
+ qDebug() << "text...";
|
|
+
|
|
+ PagePointer page(loadRandomPage(m_document));
|
|
+
|
|
+ page->text(QRectF(QPointF(), page->pageSizeF()));
|
|
+ }
|
|
+
|
|
+ if(qrand() % 2 == 0)
|
|
+ {
|
|
+ QMutexLocker mutexLocker(m_annotationMutex);
|
|
+
|
|
+ qDebug() << "add annotation...";
|
|
+
|
|
+ PagePointer page(loadRandomPage(m_document));
|
|
+
|
|
+ Poppler::Annotation* annotation = 0;
|
|
+
|
|
+ switch(qrand() % 3)
|
|
+ {
|
|
+ default:
|
|
+ case 0:
|
|
+ annotation = new Poppler::TextAnnotation(qrand() % 2 == 0 ? Poppler::TextAnnotation::Linked : Poppler::TextAnnotation::InPlace);
|
|
+ break;
|
|
+ case 1:
|
|
+ annotation = new Poppler::HighlightAnnotation();
|
|
+ break;
|
|
+ case 2:
|
|
+ annotation = new Poppler::InkAnnotation();
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ annotation->setBoundary(QRectF(0.0, 0.0, 0.5, 0.5));
|
|
+ annotation->setContents("crazy");
|
|
+
|
|
+ page->addAnnotation(annotation);
|
|
+
|
|
+ delete annotation;
|
|
+ }
|
|
+
|
|
+ if(qrand() % 2 == 0)
|
|
+ {
|
|
+ QMutexLocker mutexLocker(m_annotationMutex);
|
|
+
|
|
+ for(int index = 0; index < m_document->numPages(); ++index)
|
|
+ {
|
|
+ PagePointer page(loadPage(m_document, index));
|
|
+
|
|
+ QList< Poppler::Annotation* > annotations = page->annotations();
|
|
+
|
|
+ if(!annotations.isEmpty())
|
|
+ {
|
|
+ qDebug() << "modify annotation...";
|
|
+
|
|
+ annotations.at(qrand() % annotations.size())->setBoundary(QRectF(0.5, 0.5, 0.25, 0.25));
|
|
+ annotations.at(qrand() % annotations.size())->setAuthor("foo");
|
|
+ annotations.at(qrand() % annotations.size())->setContents("bar");
|
|
+ annotations.at(qrand() % annotations.size())->setCreationDate(QDateTime::currentDateTime());
|
|
+ annotations.at(qrand() % annotations.size())->setModificationDate(QDateTime::currentDateTime());
|
|
+ }
|
|
+
|
|
+ qDeleteAll(annotations);
|
|
+
|
|
+ if(!annotations.isEmpty())
|
|
+ {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(qrand() % 2 == 0)
|
|
+ {
|
|
+ QMutexLocker mutexLocker(m_annotationMutex);
|
|
+
|
|
+ for(int index = 0; index < m_document->numPages(); ++index)
|
|
+ {
|
|
+ PagePointer page(loadPage(m_document, index));
|
|
+
|
|
+ QList< Poppler::Annotation* > annotations = page->annotations();
|
|
+
|
|
+ if(!annotations.isEmpty())
|
|
+ {
|
|
+ qDebug() << "remove annotation...";
|
|
+
|
|
+ page->removeAnnotation(annotations.takeAt(qrand() % annotations.size()));
|
|
+ }
|
|
+
|
|
+ qDeleteAll(annotations);
|
|
+
|
|
+ if(!annotations.isEmpty())
|
|
+ {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(qrand() % 2 == 0)
|
|
+ {
|
|
+ qDebug() << "fonts...";
|
|
+
|
|
+ m_document->fonts();
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+int main(int argc, char** argv)
|
|
+{
|
|
+ if(argc < 5)
|
|
+ {
|
|
+ qDebug() << "usage: stress-threads-qt duration sillyCount crazyCount file(s)";
|
|
+
|
|
+ return EXIT_FAILURE;
|
|
+ }
|
|
+
|
|
+ const int duration = atoi(argv[1]);
|
|
+ const int sillyCount = atoi(argv[2]);
|
|
+ const int crazyCount = atoi(argv[3]);
|
|
+
|
|
+ qsrand(time(0));
|
|
+
|
|
+ for(int argi = 4; argi < argc; ++argi)
|
|
+ {
|
|
+ const QString file = QFile::decodeName(argv[argi]);
|
|
+ Poppler::Document* document = Poppler::Document::load(file);
|
|
+
|
|
+ if(document == 0)
|
|
+ {
|
|
+ qDebug() << "Could not load" << file;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if(document->isLocked())
|
|
+ {
|
|
+ qDebug() << file << "is locked";
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ for(int i = 0; i < sillyCount; ++i)
|
|
+ {
|
|
+ (new SillyThread(document))->start();
|
|
+ }
|
|
+
|
|
+ QMutex* annotationMutex = new QMutex();
|
|
+
|
|
+ for(int i = 0; i < crazyCount; ++i)
|
|
+ {
|
|
+ (new CrazyThread(qrand(), document, annotationMutex))->start();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ sleep(duration);
|
|
+
|
|
+ return EXIT_SUCCESS;
|
|
+}
|
|
diff --git a/qt4/tests/test-password-qt4.cpp b/qt4/tests/test-password-qt4.cpp
|
|
new file mode 100644
|
|
index 00000000..c961874d
|
|
--- /dev/null
|
|
+++ b/qt4/tests/test-password-qt4.cpp
|
|
@@ -0,0 +1,136 @@
|
|
+#include <QtCore/QDebug>
|
|
+#include <QtGui/QApplication>
|
|
+#include <QtGui/QImage>
|
|
+#include <QtGui/QPainter>
|
|
+#include <QtGui/QPaintEvent>
|
|
+#include <QtGui/QWidget>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+class PDFDisplay : public QWidget // picture display widget
|
|
+{
|
|
+public:
|
|
+ PDFDisplay( Poppler::Document *d );
|
|
+ ~PDFDisplay();
|
|
+protected:
|
|
+ void paintEvent( QPaintEvent * );
|
|
+ void keyPressEvent( QKeyEvent * );
|
|
+private:
|
|
+ void display();
|
|
+ int m_currentPage;
|
|
+ QImage image;
|
|
+ Poppler::Document *doc;
|
|
+};
|
|
+
|
|
+PDFDisplay::PDFDisplay( Poppler::Document *d )
|
|
+{
|
|
+ doc = d;
|
|
+ m_currentPage = 0;
|
|
+ display();
|
|
+}
|
|
+
|
|
+void PDFDisplay::display()
|
|
+{
|
|
+ if (doc) {
|
|
+ Poppler::Page *page = doc->page(m_currentPage);
|
|
+ if (page) {
|
|
+ qDebug() << "Displaying page: " << m_currentPage;
|
|
+ image = page->renderToImage();
|
|
+ update();
|
|
+ delete page;
|
|
+ }
|
|
+ } else {
|
|
+ qWarning() << "doc not loaded";
|
|
+ }
|
|
+}
|
|
+
|
|
+PDFDisplay::~PDFDisplay()
|
|
+{
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void PDFDisplay::paintEvent( QPaintEvent *e )
|
|
+{
|
|
+ QPainter paint( this ); // paint widget
|
|
+ if (!image.isNull()) {
|
|
+ paint.drawImage(0, 0, image);
|
|
+ } else {
|
|
+ qWarning() << "null image";
|
|
+ }
|
|
+}
|
|
+
|
|
+void PDFDisplay::keyPressEvent( QKeyEvent *e )
|
|
+{
|
|
+ if (e->key() == Qt::Key_Down)
|
|
+ {
|
|
+ if (m_currentPage + 1 < doc->numPages())
|
|
+ {
|
|
+ m_currentPage++;
|
|
+ display();
|
|
+ }
|
|
+ }
|
|
+ else if (e->key() == Qt::Key_Up)
|
|
+ {
|
|
+ if (m_currentPage > 0)
|
|
+ {
|
|
+ m_currentPage--;
|
|
+ display();
|
|
+ }
|
|
+ }
|
|
+ else if (e->key() == Qt::Key_Q)
|
|
+ {
|
|
+ exit(0);
|
|
+ }
|
|
+}
|
|
+
|
|
+int main( int argc, char **argv )
|
|
+{
|
|
+ QApplication a( argc, argv ); // QApplication required!
|
|
+
|
|
+ if ( argc != 3)
|
|
+ {
|
|
+ qWarning() << "usage: test-password-qt4 owner-password filename";
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ Poppler::Document *doc = Poppler::Document::load(argv[2], argv[1]);
|
|
+ if (!doc)
|
|
+ {
|
|
+ qWarning() << "doc not loaded";
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ // output some meta-data
|
|
+ int major = 0, minor = 0;
|
|
+ doc->getPdfVersion( &major, &minor );
|
|
+ qDebug() << " PDF Version: " << qPrintable(QString::fromLatin1("%1.%2").arg(major).arg(minor));
|
|
+ qDebug() << " Title: " << doc->info("Title");
|
|
+ qDebug() << " Subject: " << doc->info("Subject");
|
|
+ qDebug() << " Author: " << doc->info("Author");
|
|
+ qDebug() << " Key words: " << doc->info("Keywords");
|
|
+ qDebug() << " Creator: " << doc->info("Creator");
|
|
+ qDebug() << " Producer: " << doc->info("Producer");
|
|
+ qDebug() << " Date created: " << doc->date("CreationDate").toString();
|
|
+ qDebug() << " Date modified: " << doc->date("ModDate").toString();
|
|
+ qDebug() << "Number of pages: " << doc->numPages();
|
|
+ qDebug() << " Linearised: " << doc->isLinearized();
|
|
+ qDebug() << " Encrypted: " << doc->isEncrypted();
|
|
+ qDebug() << " OK to print: " << doc->okToPrint();
|
|
+ qDebug() << " OK to copy: " << doc->okToCopy();
|
|
+ qDebug() << " OK to change: " << doc->okToChange();
|
|
+ qDebug() << "OK to add notes: " << doc->okToAddNotes();
|
|
+ qDebug() << " Page mode: " << doc->pageMode();
|
|
+ QStringList fontNameList;
|
|
+ foreach( const Poppler::FontInfo &font, doc->fonts() )
|
|
+ fontNameList += font.name();
|
|
+ qDebug() << " Fonts: " << fontNameList.join( ", " );
|
|
+
|
|
+ Poppler::Page *page = doc->page(0);
|
|
+ qDebug() << " Page 1 size: " << page->pageSize().width()/72 << "inches x " << page->pageSize().height()/72 << "inches";
|
|
+
|
|
+ PDFDisplay test( doc ); // create picture display
|
|
+ test.setWindowTitle("Poppler-Qt4 Test");
|
|
+ test.show(); // show it
|
|
+
|
|
+ return a.exec(); // start event loop
|
|
+}
|
|
diff --git a/qt4/tests/test-poppler-qt4.cpp b/qt4/tests/test-poppler-qt4.cpp
|
|
new file mode 100644
|
|
index 00000000..ae6b11f3
|
|
--- /dev/null
|
|
+++ b/qt4/tests/test-poppler-qt4.cpp
|
|
@@ -0,0 +1,235 @@
|
|
+#include <QtCore/QDebug>
|
|
+#include <QtCore/QFile>
|
|
+#include <QtGui/QApplication>
|
|
+#include <QtGui/QImage>
|
|
+#include <QtGui/QLabel>
|
|
+#include <QtGui/QMouseEvent>
|
|
+#include <QtGui/QPainter>
|
|
+#include <QtGui/QPaintEvent>
|
|
+#include <QtGui/QToolTip>
|
|
+#include <QtGui/QWidget>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+class PDFDisplay : public QWidget // picture display widget
|
|
+{
|
|
+public:
|
|
+ PDFDisplay( Poppler::Document *d, bool arthur );
|
|
+ ~PDFDisplay();
|
|
+ void setShowTextRects(bool show);
|
|
+ void display();
|
|
+protected:
|
|
+ void paintEvent( QPaintEvent * );
|
|
+ void keyPressEvent( QKeyEvent * );
|
|
+ void mousePressEvent( QMouseEvent * );
|
|
+private:
|
|
+ int m_currentPage;
|
|
+ QImage image;
|
|
+ Poppler::Document *doc;
|
|
+ QString backendString;
|
|
+ bool showTextRects;
|
|
+ QList<Poppler::TextBox*> textRects;
|
|
+};
|
|
+
|
|
+PDFDisplay::PDFDisplay( Poppler::Document *d, bool arthur )
|
|
+{
|
|
+ showTextRects = false;
|
|
+ doc = d;
|
|
+ m_currentPage = 0;
|
|
+ if (arthur)
|
|
+ {
|
|
+ backendString = "Arthur";
|
|
+ doc->setRenderBackend(Poppler::Document::ArthurBackend);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ backendString = "Splash";
|
|
+ doc->setRenderBackend(Poppler::Document::SplashBackend);
|
|
+ }
|
|
+ doc->setRenderHint(Poppler::Document::Antialiasing, true);
|
|
+ doc->setRenderHint(Poppler::Document::TextAntialiasing, true);
|
|
+}
|
|
+
|
|
+void PDFDisplay::setShowTextRects(bool show)
|
|
+{
|
|
+ showTextRects = show;
|
|
+}
|
|
+
|
|
+void PDFDisplay::display()
|
|
+{
|
|
+ if (doc) {
|
|
+ Poppler::Page *page = doc->page(m_currentPage);
|
|
+ if (page) {
|
|
+ qDebug() << "Displaying page using" << backendString << "backend: " << m_currentPage;
|
|
+ QTime t = QTime::currentTime();
|
|
+ image = page->renderToImage();
|
|
+ qDebug() << "Rendering took" << t.msecsTo(QTime::currentTime()) << "msecs";
|
|
+ qDeleteAll(textRects);
|
|
+ if (showTextRects)
|
|
+ {
|
|
+ QPainter painter(&image);
|
|
+ painter.setPen(Qt::red);
|
|
+ textRects = page->textList();
|
|
+ foreach(Poppler::TextBox *tb, textRects)
|
|
+ {
|
|
+ painter.drawRect(tb->boundingBox());
|
|
+ }
|
|
+ }
|
|
+ else textRects.clear();
|
|
+ update();
|
|
+ delete page;
|
|
+ }
|
|
+ } else {
|
|
+ qWarning() << "doc not loaded";
|
|
+ }
|
|
+}
|
|
+
|
|
+PDFDisplay::~PDFDisplay()
|
|
+{
|
|
+ qDeleteAll(textRects);
|
|
+ delete doc;
|
|
+}
|
|
+
|
|
+void PDFDisplay::paintEvent( QPaintEvent *e )
|
|
+{
|
|
+ QPainter paint( this ); // paint widget
|
|
+ if (!image.isNull()) {
|
|
+ paint.drawImage(0, 0, image);
|
|
+ } else {
|
|
+ qWarning() << "null image";
|
|
+ }
|
|
+}
|
|
+
|
|
+void PDFDisplay::keyPressEvent( QKeyEvent *e )
|
|
+{
|
|
+ if (e->key() == Qt::Key_Down)
|
|
+ {
|
|
+ if (m_currentPage + 1 < doc->numPages())
|
|
+ {
|
|
+ m_currentPage++;
|
|
+ display();
|
|
+ }
|
|
+ }
|
|
+ else if (e->key() == Qt::Key_Up)
|
|
+ {
|
|
+ if (m_currentPage > 0)
|
|
+ {
|
|
+ m_currentPage--;
|
|
+ display();
|
|
+ }
|
|
+ }
|
|
+ else if (e->key() == Qt::Key_Q)
|
|
+ {
|
|
+ exit(0);
|
|
+ }
|
|
+}
|
|
+
|
|
+void PDFDisplay::mousePressEvent( QMouseEvent *e )
|
|
+{
|
|
+ int i = 0;
|
|
+ foreach(Poppler::TextBox *tb, textRects)
|
|
+ {
|
|
+ if (tb->boundingBox().contains(e->pos()))
|
|
+ {
|
|
+ QString tt = QString("Text: \"%1\"\nIndex in text list: %2").arg(tb->text()).arg(i);
|
|
+ QToolTip::showText(e->globalPos(), tt, this);
|
|
+ break;
|
|
+ }
|
|
+ ++i;
|
|
+ }
|
|
+}
|
|
+
|
|
+int main( int argc, char **argv )
|
|
+{
|
|
+ QApplication a( argc, argv ); // QApplication required!
|
|
+
|
|
+ if ( argc < 2 ||
|
|
+ (argc == 3 && strcmp(argv[2], "-extract") != 0 && strcmp(argv[2], "-arthur") != 0 && strcmp(argv[2], "-textRects") != 0) ||
|
|
+ argc > 3)
|
|
+ {
|
|
+ // use argument as file name
|
|
+ qWarning() << "usage: test-poppler-qt4 filename [-extract|-arthur|-textRects]";
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ Poppler::Document *doc = Poppler::Document::load(QFile::decodeName(argv[1]));
|
|
+ if (!doc)
|
|
+ {
|
|
+ qWarning() << "doc not loaded";
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ if (doc->isLocked())
|
|
+ {
|
|
+ qWarning() << "document locked (needs password)";
|
|
+ exit(0);
|
|
+ }
|
|
+
|
|
+ // output some meta-data
|
|
+ int major = 0, minor = 0;
|
|
+ doc->getPdfVersion( &major, &minor );
|
|
+ qDebug() << " PDF Version: " << qPrintable(QString::fromLatin1("%1.%2").arg(major).arg(minor));
|
|
+ qDebug() << " Title: " << doc->info("Title");
|
|
+ qDebug() << " Subject: " << doc->info("Subject");
|
|
+ qDebug() << " Author: " << doc->info("Author");
|
|
+ qDebug() << " Key words: " << doc->info("Keywords");
|
|
+ qDebug() << " Creator: " << doc->info("Creator");
|
|
+ qDebug() << " Producer: " << doc->info("Producer");
|
|
+ qDebug() << " Date created: " << doc->date("CreationDate").toString();
|
|
+ qDebug() << " Date modified: " << doc->date("ModDate").toString();
|
|
+ qDebug() << "Number of pages: " << doc->numPages();
|
|
+ qDebug() << " Linearised: " << doc->isLinearized();
|
|
+ qDebug() << " Encrypted: " << doc->isEncrypted();
|
|
+ qDebug() << " OK to print: " << doc->okToPrint();
|
|
+ qDebug() << " OK to copy: " << doc->okToCopy();
|
|
+ qDebug() << " OK to change: " << doc->okToChange();
|
|
+ qDebug() << "OK to add notes: " << doc->okToAddNotes();
|
|
+ qDebug() << " Page mode: " << doc->pageMode();
|
|
+ qDebug() << " Metadata: " << doc->metadata();
|
|
+
|
|
+ if ( doc->hasEmbeddedFiles() ) {
|
|
+ qDebug() << "Embedded files:";
|
|
+ foreach( Poppler::EmbeddedFile *file, doc->embeddedFiles() ) {
|
|
+ qDebug() << " " << file->name();
|
|
+ }
|
|
+ qDebug();
|
|
+ } else {
|
|
+ qDebug() << "No embedded files";
|
|
+ }
|
|
+
|
|
+ if (doc->numPages() <= 0)
|
|
+ {
|
|
+ delete doc;
|
|
+ qDebug() << "Doc has no pages";
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ Poppler::Page *page = doc->page(0);
|
|
+ if (page)
|
|
+ {
|
|
+ qDebug() << "Page 1 size: " << page->pageSize().width()/72 << "inches x " << page->pageSize().height()/72 << "inches";
|
|
+ delete page;
|
|
+ }
|
|
+
|
|
+ if (argc == 2 || (argc == 3 && strcmp(argv[2], "-arthur") == 0) || (argc == 3 && strcmp(argv[2], "-textRects") == 0))
|
|
+ {
|
|
+ bool useArthur = (argc == 3 && strcmp(argv[2], "-arthur") == 0);
|
|
+ PDFDisplay test( doc, useArthur ); // create picture display
|
|
+ test.setWindowTitle("Poppler-Qt4 Test");
|
|
+ test.setShowTextRects(argc == 3 && strcmp(argv[2], "-textRects") == 0);
|
|
+ test.display();
|
|
+ test.show(); // show it
|
|
+
|
|
+ return a.exec(); // start event loop
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ Poppler::Page *page = doc->page(0);
|
|
+
|
|
+ QLabel *l = new QLabel(page->text(QRectF()), 0);
|
|
+ l->show();
|
|
+ delete page;
|
|
+ delete doc;
|
|
+ return a.exec();
|
|
+ }
|
|
+}
|
|
diff --git a/qt4/tests/test-render-to-file.cpp b/qt4/tests/test-render-to-file.cpp
|
|
new file mode 100644
|
|
index 00000000..b01aa03c
|
|
--- /dev/null
|
|
+++ b/qt4/tests/test-render-to-file.cpp
|
|
@@ -0,0 +1,69 @@
|
|
+#include <QtCore/QDebug>
|
|
+#include <QtCore/QFile>
|
|
+#include <QtGui/QApplication>
|
|
+#include <QtGui/QImage>
|
|
+
|
|
+#include <poppler-qt4.h>
|
|
+
|
|
+int main( int argc, char **argv )
|
|
+{
|
|
+ QApplication a( argc, argv ); // QApplication required!
|
|
+
|
|
+ if ( argc < 2 ||
|
|
+ (argc == 3 && strcmp(argv[2], "-arthur") != 0) ||
|
|
+ argc > 3)
|
|
+ {
|
|
+ // use argument as file name
|
|
+ qWarning() << "usage: test-poppler-qt4 filename [-arthur]";
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ Poppler::Document *doc = Poppler::Document::load(QFile::decodeName(argv[1]));
|
|
+ if (!doc)
|
|
+ {
|
|
+ qWarning() << "doc not loaded";
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ if (doc->isLocked())
|
|
+ {
|
|
+ qWarning() << "document locked (needs password)";
|
|
+ exit(0);
|
|
+ }
|
|
+
|
|
+ if (doc->numPages() <= 0)
|
|
+ {
|
|
+ delete doc;
|
|
+ qDebug() << "Doc has no pages";
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ QString backendString;
|
|
+ if (argc == 3 && strcmp(argv[2], "-arthur") == 0)
|
|
+ {
|
|
+ backendString = "Arthur";
|
|
+ doc->setRenderBackend(Poppler::Document::ArthurBackend);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ backendString = "Splash";
|
|
+ doc->setRenderBackend(Poppler::Document::SplashBackend);
|
|
+ }
|
|
+ doc->setRenderHint(Poppler::Document::Antialiasing, true);
|
|
+ doc->setRenderHint(Poppler::Document::TextAntialiasing, true);
|
|
+
|
|
+ for (int i = 0; i < doc->numPages(); ++i)
|
|
+ {
|
|
+ Poppler::Page *page = doc->page(i);
|
|
+ if (page) {
|
|
+ qDebug() << "Rendering page using" << backendString << "backend: " << i;
|
|
+ QTime t = QTime::currentTime();
|
|
+ QImage image = page->renderToImage();
|
|
+ qDebug() << "Rendering took" << t.msecsTo(QTime::currentTime()) << "msecs";
|
|
+ image.save(QString("test-rennder-to-file%1.ppm").arg(i));
|
|
+ delete page;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
--
|
|
2.14.3
|
|
|