Commit 25148767 authored by Norbert Preining's avatar Norbert Preining

New upstream version 0.6.2~git20170424

parent ae0bc8a1
_Steps to reproduce the problem_:
1.
2.
3.
_Expected output_:
_Actual output_:
_TeXworks version_:
_TeXworks obtained from_:
_Operating system_:
_Please provide any additional information below_:
......@@ -2,8 +2,6 @@ language: cpp
matrix:
include:
- env: TARGET_OS=osx QT=4
os: osx
- env: TARGET_OS=osx QT=5
os: osx
- env: TARGET_OS=win QT=4
......
......@@ -38,6 +38,8 @@ IF ( ${CMAKE_INSTALL_PREFIX} MATCHES .*/_CPack_Packages/.* )
EXPECTED_MD5 "${POPPLER_DATA_ARCHIVE_MD5}"
SHOW_PROGRESS
)
ELSE ( )
MESSAGE(STATUS "Using Poppler data files in '${PROJECT_SOURCE_DIR}/${POPPLER_DATA_ARCHIVE}'")
ENDIF ()
IF ( NOT EXISTS "${PROJECT_SOURCE_DIR}/${POPPLER_DATA_BASE}" )
......@@ -45,8 +47,11 @@ IF ( ${CMAKE_INSTALL_PREFIX} MATCHES .*/_CPack_Packages/.* )
COMMAND tar xzf "${PROJECT_SOURCE_DIR}/${POPPLER_DATA_ARCHIVE}"
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
)
ELSE ( )
MESSAGE(STATUS "'${PROJECT_SOURCE_DIR}/${POPPLER_DATA_BASE}' already present")
ENDIF ()
MESSAGE(STATUS "Bundling poppler data files")
FILE(INSTALL "${PROJECT_SOURCE_DIR}/${POPPLER_DATA_BASE}/"
DESTINATION "${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}.app/Contents/poppler-data"
PATTERN CMakeLists.txt EXCLUDE
......@@ -63,6 +68,8 @@ IF ( ${CMAKE_INSTALL_PREFIX} MATCHES .*/_CPack_Packages/.* )
EXPECTED_MD5 "${TW_MANUAL_ARCHIVE_MD5}"
SHOW_PROGRESS
)
ELSE ( )
MESSAGE(STATUS "Using manual files in '${PROJECT_SOURCE_DIR}/${TW_MANUAL_ARCHIVE}'")
ENDIF ()
IF ( NOT EXISTS "${PROJECT_SOURCE_DIR}/${TW_MANUAL_BASE}" )
......@@ -71,8 +78,11 @@ IF ( ${CMAKE_INSTALL_PREFIX} MATCHES .*/_CPack_Packages/.* )
COMMAND unzip "${PROJECT_SOURCE_DIR}/${TW_MANUAL_ARCHIVE}"
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/${TW_MANUAL_BASE}"
)
ELSE ( )
MESSAGE(STATUS "'${PROJECT_SOURCE_DIR}/${TW_MANUAL_BASE}' already present")
ENDIF ()
MESSAGE(STATUS "Bundling manual files")
FILE(INSTALL "${PROJECT_SOURCE_DIR}/${TW_MANUAL_BASE}/TeXworks-manual"
DESTINATION "${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}.app/Contents/texworks-help/"
)
......
# This file contains a formula for installing Poppler on Mac OS X using the
# Homebrew package manager:
#
# http://mxcl.github.com/homebrew
# http://brew.sh/
#
# To install Poppler using this formula:
#
......@@ -13,11 +13,19 @@
# - help Qt apps find the poppler-data directory.
# - use native Mac OS X font handling (instead of fontconfig)
class Poppler < Formula
desc "PDF rendering library (based on the xpdf-3.0 code base)"
homepage "https://poppler.freedesktop.org/"
url "https://poppler.freedesktop.org/poppler-0.41.0.tar.xz"
sha256 "420abaab63caed9e1ee28964a0ba216d1979506726164bc99ad5ade289192a1b"
# BEGIN TEXWORKS ADDITION
version '0.41.0-texworks'
url "https://poppler.freedesktop.org/poppler-0.53.0.tar.xz"
sha256 "592bf72960c6b5948b67657594b05e72d9a278daf7613c9f3cdff9a5b73096a8"
# BEGIN TEXWORKS MODIFICATION
# bottle do
# rebuild 1
# sha256 "5b6de69e6ab1996332934e21b3a5220990e2a5943775d002ee8e5c2447b93758" => :sierra
# sha256 "44fcbb473c78c5ce034b65885fcb2e05d4ef0b2d537a043b7d2b6d44d075907b" => :el_capitan
# sha256 "47787f7ffa8f69dea50ebb1391186d8146386ad46f2f6b69e3786b7271caeb9d" => :yosemite
# end
version '0.53.0-texworks'
TEXWORKS_SOURCE_DIR = Pathname.new(__FILE__).realpath.dirname.join('../../..')
TEXWORKS_PATCH_DIR = TEXWORKS_SOURCE_DIR + 'lib-patches/'
......@@ -37,13 +45,13 @@ class Poppler < Formula
depends_on "autoconf" => :build
depends_on "automake" => :build
depends_on "libtool" => :build
# END TEXWORKS ADDITION
# END TEXWORKS MODIFICATION
option "with-qt", "Build Qt backend"
option "with-qt5", "Build Qt5 backend"
option "with-qt", "Build Qt5 backend"
option "with-little-cms2", "Use color management system"
deprecated_option "with-qt4" => "with-qt"
deprecated_option "with-qt5" => "with-qt"
deprecated_option "with-lcms2" => "with-little-cms2"
depends_on "pkg-config" => :build
......@@ -57,20 +65,22 @@ class Poppler < Formula
depends_on "libpng"
depends_on "libtiff"
depends_on "openjpeg"
depends_on "qt" => :optional
depends_on "qt5" => :optional
depends_on "little-cms2" => :optional
conflicts_with "pdftohtml", :because => "both install `pdftohtml` binaries"
conflicts_with "pdftohtml", "pdf2image", "xpdf",
:because => "poppler, pdftohtml, pdf2image, and xpdf install conflicting executables"
resource "font-data" do
url "https://poppler.freedesktop.org/poppler-data-0.4.7.tar.gz"
sha256 "e752b0d88a7aba54574152143e7bf76436a7ef51977c55d6bd9a48dccde3a7de"
end
needs :cxx11 if build.with?("qt") || MacOS.version < :mavericks
def install
ENV["LIBOPENJPEG_CFLAGS"] = "-I#{Formula["openjpeg"].opt_include}/openjpeg-1.5"
ENV.cxx11 if build.with?("qt") || MacOS.version < :mavericks
ENV["LIBOPENJPEG_CFLAGS"] = "-I#{Formula["openjpeg"].opt_include}/openjpeg-2.1"
args = %W[
--disable-dependency-tracking
......@@ -79,25 +89,23 @@ class Poppler < Formula
--enable-poppler-glib
--disable-gtk-test
--enable-introspection=yes
--disable-poppler-qt4
]
if build.with?("qt") && build.with?("qt5")
raise "poppler: --with-qt and --with-qt5 cannot be used at the same time"
elsif build.with? "qt"
args << "--enable-poppler-qt4"
elsif build.with? "qt5"
if build.with? "qt"
args << "--enable-poppler-qt5"
else
args << "--disable-poppler-qt4" << "--disable-poppler-qt5"
args << "--disable-poppler-qt5"
end
args << "--enable-cms=lcms2" if build.with? "little-cms2"
# BEGIN TEXWORKS ADDITION
# BEGIN TEXWORKS MODIFICATION
# We changed the config file (to add native font handling), so we need to
# update the configure script
system "autoreconf", "-ivf"
# END TEXWORKS ADDITION
# END TEXWORKS MODIFICATION
system "./configure", *args
system "make", "install"
resource("font-data").stage do
......@@ -109,4 +117,3 @@ class Poppler < Formula
system "#{bin}/pdfinfo", test_fixtures("test.pdf")
end
end
......@@ -183,6 +183,8 @@ IF (UNIX AND NOT APPLE)
ENDIF()
ENDIF()
set(CMAKE_CXX_STANDARD 11)
# Dependency Configuration
# ========================
......@@ -206,32 +208,50 @@ IF (NOT DESIRED_QT_VERSION OR DESIRED_QT_VERSION MATCHES 5)
find_package(Qt5DBus QUIET)
ENDIF ()
# FIXME: This will be executed even if Qt5 is not found. Defining -DSTATIC_QT5 is not a good idea in that case...
IF( WIN32 AND NOT BUILD_SHARED_LIBS )
IF(Qt5Widgets_FOUND AND Qt5Core_FOUND AND Qt5Gui_FOUND AND Qt5UiTools_FOUND AND Qt5Concurrent_FOUND AND Qt5Script_FOUND AND Qt5ScriptTools_FOUND AND Qt5Xml_FOUND AND (NOT UNIX OR APPLE OR Qt5DBus_FOUND))
SET(QT5_FOUND TRUE)
SET(QT_LIBRARIES Qt5::UiTools Qt5::ScriptTools Qt5::Script Qt5::Concurrent Qt5::Xml ${Qt5DBus_LIBRARIES} Qt5::Widgets Qt5::Gui Qt5::Core)
# Note: Qt5 only sets Qt5Widgets_VERSION, etc., but not QT_VERSION_MAJOR,
# etc. which is used here.
string(REGEX REPLACE "^([0-9]+).*$" "\\1" QT_VERSION_MAJOR "${Qt5Widgets_VERSION}")
string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*$" "\\1" QT_VERSION_MINOR "${Qt5Widgets_VERSION}")
string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" QT_VERSION_PATCH "${Qt5Widgets_VERSION}")
ELSE()
SET(QT5_FOUND FALSE)
ENDIF()
IF( QT5_FOUND AND WIN32 AND NOT BUILD_SHARED_LIBS )
# For static Windows builds, we also need to pull in the Qt5 Platform
# support library, which is not exposed to CMake properly, unfortunately
GET_TARGET_PROPERTY(QT_LIB_DIR "${Qt5Widgets_LIBRARIES}" LOCATION)
GET_FILENAME_COMPONENT(QT_LIB_DIR "${QT_LIB_DIR}" PATH)
FIND_LIBRARY(Qt5Platform_LIBRARIES Qt5PlatformSupport
HINTS "${QT_LIB_DIR}"
)
FIND_LIBRARY(Qt5QWindows_LIBRARIES qwindows
HINTS "${QT_LIB_DIR}/../plugins/platforms"
)
# Starting with Qt 5.8, Qt5PlatformSupport was modularized
if (QT_VERSION_MAJOR EQUAL 5 AND QT_VERSION_MINOR LESS 8)
FIND_LIBRARY(Qt5Platform_LIBRARIES Qt5PlatformSupport
HINTS "${QT_LIB_DIR}"
)
LIST(INSERT QT_LIBRARIES 0 ${Qt5Platform_LIBRARIES} ${Qt5QWindows_LIBRARIES})
else()
FIND_LIBRARY(Qt5FontDatabaseSupport_LIBRARIES Qt5FontDatabaseSupport
HINTS "${QT_LIB_DIR}"
)
FIND_LIBRARY(Qt5EventDispatcherSupport_LIBRARIES Qt5EventDispatcherSupport
HINTS "${QT_LIB_DIR}"
)
FIND_LIBRARY(Qt5ThemeSupport_LIBRARIES Qt5ThemeSupport
HINTS "${QT_LIB_DIR}"
)
LIST(INSERT QT_LIBRARIES 0 ${Qt5QWindows_LIBRARIES} ${Qt5FontDatabaseSupport_LIBRARIES} ${Qt5EventDispatcherSupport_LIBRARIES} ${Qt5ThemeSupport_LIBRARIES})
endif()
ADD_DEFINITIONS(-DSTATIC_QT5)
ENDIF()
IF(Qt5Widgets_FOUND AND Qt5Core_FOUND AND Qt5Gui_FOUND AND Qt5UiTools_FOUND AND Qt5Concurrent_FOUND AND Qt5Script_FOUND AND Qt5ScriptTools_FOUND AND Qt5Xml_FOUND)
SET(QT5_FOUND TRUE)
SET(QT_INCLUDE_DIR "${Qt5Widgets_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS} ${Qt5UiTools_INCLUDE_DIRS} ${Qt5Concurrent_INCLUDE_DIRS} ${Qt5Script_INCLUDE_DIRS} ${Qt5ScriptTools_INCLUDE_DIRS} ${Qt5Xml_INCLUDE_DIRS} ${Qt5DBus_INCLUDE_DIRS}")
SET(QT_LIBRARIES ${Qt5UiTools_LIBRARIES} ${Qt5ScriptTools_LIBRARIES} ${Qt5Script_LIBRARIES} ${Qt5Concurrent_LIBRARIES} ${Qt5Xml_LIBRARIES} ${Qt5DBus_LIBRARIES} ${Qt5Widgets_LIBRARIES} ${Qt5Platform_LIBRARIES} ${Qt5QWindows_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Core_LIBRARIES})
# Note: Qt5 only sets Qt5Widgets_VERSION, etc., but not QT_VERSION_MAJOR,
# etc. which is used here.
string(REGEX REPLACE "^([0-9]+).*$" "\\1" QT_VERSION_MAJOR "${Qt5Widgets_VERSION}")
string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*$" "\\1" QT_VERSION_MINOR "${Qt5Widgets_VERSION}")
string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" QT_VERSION_PATCH "${Qt5Widgets_VERSION}")
ENDIF()
ENDIF()
# If Qt5 is not found (or not desired), check for Qt4
IF (DESIRED_QT_VERSION MATCHES 4 OR NOT QT5_FOUND)
......@@ -318,9 +338,10 @@ IF ( WITH_PYTHON )
MARK_AS_ADVANCED(PYTHON_INCLUDE_DIR)
SET(PYTHONLIBS_FOUND TRUE)
ELSE ()
# **NOTE** For some reason, FindPythonLibs.cmake always seems to default to
# `/System/Library/Frameworks/Python.framework/Headers` as the include path
# on OS X.
# **NOTE**
# In order to find the correct version of 'PythonLibs', it seems that we need to run 'FIND_PACKAGE(PythonInterp)' firstly.
# In order to find the correct version of 'PythonInterp', we need to set 'PYTHONHOME' environment variable
FIND_PACKAGE(PythonInterp)
FIND_PACKAGE(PythonLibs)
ENDIF ()
ENDIF()
......
// This file is used to identify the latest git commit. Please do not touch.
#define GIT_COMMIT_HASH "3614278"
#define GIT_COMMIT_DATE "2016-05-01 10:43:14 +0200"
#define GIT_COMMIT_HASH "$Format:%h$"
#define GIT_COMMIT_DATE "$Format:%ci$"
unit-tests/*_test
QtPDF.pro
......@@ -99,7 +99,7 @@ FIND_LIBRARY(POPPLER_QT_LIBRARIES NAMES poppler-qt${QT_VERSION_MAJOR} ${POPPLER_
/usr/local
/usr
HINTS
${POPPLER_PKG_LIBRARY_DIRS} # Generated by pkg-config
${POPPLER_QT_PKG_LIBRARY_DIRS} # Generated by pkg-config
PATH_SUFFIXES
lib64
lib
......
......@@ -97,34 +97,54 @@ IF (DESIRED_QT_VERSION MATCHES 5 OR (NOT DESIRED_QT_VERSION AND (QT_VERSION_MAJO
IF( ${CMAKE_BUILD_TYPE} STREQUAL "Debug" )
find_package(Qt5Test QUIET)
ENDIF()
IF(Qt5Core_FOUND AND Qt5Widgets_FOUND AND Qt5Concurrent_FOUND AND Qt5Xml_FOUND AND (NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug" OR (Qt5Test_FOUND)))
SET(QT5_FOUND TRUE)
# Note: Qt5 only sets Qt5Widgets_VERSION, etc., but not QT_VERSION_MAJOR,
# etc. which is used here.
string(REGEX REPLACE "^([0-9]+).*$" "\\1" QT_VERSION_MAJOR "${Qt5Widgets_VERSION}")
string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*$" "\\1" QT_VERSION_MINOR "${Qt5Widgets_VERSION}")
string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" QT_VERSION_PATCH "${Qt5Widgets_VERSION}")
# Starting with Qt 5.7, c++11 must be used; before, it doesn't hurt
set(CMAKE_CXX_STANDARD 11)
SET(QT_LIBRARIES Qt5::Core Qt5::Widgets Qt5::Concurrent Qt5::Core Qt5::Xml)
SET(QT_TEST_LIBRARIES ${Qt5Test_LIBRARIES} Qt5::Core)
ELSE()
SET(QT5_FOUND FALSE)
ENDIF()
IF( WIN32 AND NOT BUILD_SHARED_LIBS )
IF( QT5_FOUND AND WIN32 AND NOT BUILD_SHARED_LIBS )
# For static Windows builds, we also need to pull in the Qt5 Platform
# support library, which is not exposed to CMake properly, unfortunately
GET_TARGET_PROPERTY(QT_LIB_DIR "${Qt5Widgets_LIBRARIES}" LOCATION)
GET_TARGET_PROPERTY(QT_LIB_DIR Qt5::Widgets LOCATION)
GET_FILENAME_COMPONENT(QT_LIB_DIR "${QT_LIB_DIR}" PATH)
FIND_LIBRARY(Qt5Platform_LIBRARIES Qt5PlatformSupport
HINTS "${QT_LIB_DIR}"
)
FIND_LIBRARY(Qt5QWindows_LIBRARIES qwindows
HINTS "${QT_LIB_DIR}/../plugins/platforms"
)
# Starting with Qt 5.8, Qt5PlatformSupport was modularized
if (QT_VERSION_MAJOR EQUAL 5 AND QT_VERSION_MINOR LESS 8)
FIND_LIBRARY(Qt5Platform_LIBRARIES Qt5PlatformSupport
HINTS "${QT_LIB_DIR}"
)
LIST(INSERT QT_LIBRARIES 0 ${Qt5Platform_LIBRARIES} ${Qt5QWindows_LIBRARIES})
else()
FIND_LIBRARY(Qt5FontDatabaseSupport_LIBRARIES Qt5FontDatabaseSupport
HINTS "${QT_LIB_DIR}"
)
FIND_LIBRARY(Qt5EventDispatcherSupport_LIBRARIES Qt5EventDispatcherSupport
HINTS "${QT_LIB_DIR}"
)
FIND_LIBRARY(Qt5ThemeSupport_LIBRARIES Qt5ThemeSupport
HINTS "${QT_LIB_DIR}"
)
LIST(INSERT QT_LIBRARIES 0 ${Qt5QWindows_LIBRARIES} ${Qt5FontDatabaseSupport_LIBRARIES} ${Qt5EventDispatcherSupport_LIBRARIES} ${Qt5ThemeSupport_LIBRARIES})
endif()
ADD_DEFINITIONS(-DSTATIC_QT5)
ENDIF()
IF(Qt5Core_FOUND AND Qt5Widgets_FOUND AND Qt5Concurrent_FOUND AND Qt5Core_FOUND AND (NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug" OR (Qt5Test_FOUND AND Qt5Xml_FOUND)))
SET(QT5_FOUND TRUE)
SET(QT_INCLUDE_DIR "${Qt5Core_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Concurrent_INCLUDE_DIRS}")
SET(QT_LIBRARIES ${Qt5Core_LIBRARIES} ${Qt5QWindows_LIBRARIES} ${Qt5Platform_LIBRARIES} ${Qt5Widgets_LIBRARIES} ${Qt5Concurrent_LIBRARIES} ${Qt5Core_LIBRARIES} ${Qt5Xml_LIBRARIES})
SET(QT_TEST_LIBRARIES ${Qt5Test_LIBRARIES} ${Qt5Core_LIBRARIES})
# Note: Qt5 only sets Qt5Widgets_VERSION, etc., but not QT_VERSION_MAJOR,
# etc. which is used here.
string(REGEX REPLACE "^([0-9]+).*$" "\\1" QT_VERSION_MAJOR "${Qt5Widgets_VERSION}")
string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*$" "\\1" QT_VERSION_MINOR "${Qt5Widgets_VERSION}")
string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" QT_VERSION_PATCH "${Qt5Widgets_VERSION}")
ENDIF()
# Define version-dependent wrappers
MACRO(QT_ADD_RESOURCES)
QT5_ADD_RESOURCES(${ARGV})
......@@ -175,7 +195,6 @@ FIND_PACKAGE(ZLIB REQUIRED)
# Aggregate library names and include directories into variables for easy
# access.
SET(QTPDF_INCLUDE_DIRS
${QT_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR}
${POPPLER_QT_INCLUDE_DIR}
)
......
......@@ -49,7 +49,7 @@ PDFViewer::PDFViewer(const QString pdf_doc, QWidget *parent, Qt::WindowFlags fla
connect(docWidget, SIGNAL(changedPage(int)), _counter, SLOT(setCurrentPage(int)));
connect(docWidget, SIGNAL(changedZoom(qreal)), _zoomWdgt, SLOT(setZoom(qreal)));
connect(docWidget, SIGNAL(requestOpenUrl(const QUrl)), this, SLOT(openUrl(const QUrl)));
connect(docWidget, SIGNAL(requestOpenPdf(QString, int, bool)), this, SLOT(openPdf(QString, int, bool)));
connect(docWidget, SIGNAL(requestOpenPdf(QString, QtPDF::PDFDestination, bool)), this, SLOT(openPdf(QString, QtPDF::PDFDestination, bool)));
connect(docWidget, SIGNAL(contextClick(const int, const QPointF)), this, SLOT(syncFromPdf(const int, const QPointF)));
connect(docWidget, SIGNAL(searchProgressChanged(int, int)), this, SLOT(searchProgressChanged(int, int)));
connect(docWidget, SIGNAL(changedDocument(const QWeakPointer<QtPDF::Backend::Document>)), this, SLOT(documentChanged(const QWeakPointer<QtPDF::Backend::Document>)));
......@@ -119,9 +119,9 @@ void PDFViewer::openUrl(const QUrl url) const
QDesktopServices::openUrl(url);
}
void PDFViewer::openPdf(QString filename, int page, bool newWindow) const
void PDFViewer::openPdf(QString filename, QtPDF::PDFDestination destination, bool newWindow) const
{
qDebug() << "Open PDF" << filename << "on page" << (page + 1) << "(in new window =" << newWindow << ")";
qDebug() << "Open PDF" << filename << "on page" << (destination.page() + 1) << "/ at anchor" << destination.destinationName() << "(in new window =" << newWindow << ")";
}
void PDFViewer::syncFromPdf(const int page, const QPointF pos)
......
......@@ -21,7 +21,7 @@ public slots:
private slots:
void openUrl(const QUrl url) const;
void openPdf(QString filename, int page, bool newWindow) const;
void openPdf(QString filename, QtPDF::PDFDestination destination, bool newWindow) const;
void syncFromPdf(const int page, const QPointF pos);
void searchProgressChanged(int percent, int occurrences);
void documentChanged(const QWeakPointer<QtPDF::Backend::Document> newDoc);
......
This diff is collapsed.
......@@ -146,6 +146,11 @@ protected:
FontProgramType _fontProgramType;
};
class PDFPageTile;
// Need a hash function in order to allow `PDFPageTile` to be used as a key
// object for a `QCache`.
uint qHash(const PDFPageTile &tile);
class PDFPageTile
{
......@@ -169,19 +174,23 @@ public:
return (xres == other.xres && yres == other.yres && render_box == other.render_box && page_num == other.page_num);
}
bool operator <(const PDFPageTile &other) const
{
return qHash(*this) < qHash(other);
}
#ifdef DEBUG
operator QString() const;
#endif
};
// Need a hash function in order to allow `PDFPageTile` to be used as a key
// object for a `QCache`.
uint qHash(const PDFPageTile &tile);
// This class is thread-safe
class PDFPageCache : protected QCache<PDFPageTile, QSharedPointer<QImage> >
{
typedef QCache<PDFPageTile, QSharedPointer<QImage> > Super;
public:
enum TileStatus { UNKNOWN, PLACEHOLDER, CURRENT, OUTDATED };
PDFPageCache() { }
virtual ~PDFPageCache() { }
......@@ -191,19 +200,26 @@ public:
// Returns the image under the key `tile` or NULL if it doesn't exist
QSharedPointer<QImage> getImage(const PDFPageTile & tile) const;
TileStatus getStatus(const PDFPageTile & tile) const;
// Returns the pointer to the image in the cache under they key `tile` after
// the insertion. If overwrite == true, this will always be image, otherwise
// it can be different
QSharedPointer<QImage> setImage(const PDFPageTile & tile, QImage * image, const bool overwrite = true);
QSharedPointer<QImage> setImage(const PDFPageTile & tile, QImage * image, const TileStatus status, const bool overwrite = true);
void lock() const { _lock.lockForRead(); }
void unlock() const { _lock.unlock(); }
void clear() { QWriteLocker l(&_lock); Super::clear(); }
void clear() { QWriteLocker l(&_lock); Super::clear(); _tileStatus.clear(); }
// Mark all tiles outdated
void markOutdated();
QList<PDFPageTile> tiles() const { return keys(); }
protected:
mutable QReadWriteLock _lock;
// Map to keep track of the current status of tiles; note that the status
// information is not deleted when the QCache scraps images to save memory.
QMap<PDFPageTile, TileStatus> _tileStatus;
};
class PageProcessingRequest : public QObject
......@@ -556,7 +572,7 @@ protected:
Page(Document *parent, int at, QSharedPointer<QReadWriteLock> docLock);
// Uses doc-read-lock and page-read-lock.
QSharedPointer<QImage> getCachedImage(double xres, double yres, QRect render_box = QRect());
QSharedPointer<QImage> getCachedImage(double xres, double yres, QRect render_box = QRect(), PDFPageCache::TileStatus * status = NULL);
// Uses doc-read-lock and page-read-lock.
virtual void asyncRenderToImage(QObject *listener, double xres, double yres, QRect render_box = QRect(), bool cache = false);
......
......@@ -1018,6 +1018,15 @@ void Select::resetBoxes(const int pageNum /* = -1 */)
#endif // DEBUG
}
void Select::pageDestroyed()
{
_highlightPath = NULL;
#ifdef DEBUG
_displayBoxes.clear();
#endif
resetBoxes(-1);
}
void Select::setHighlightColor(const QColor & color)
{
_highlightColor = color;
......
......@@ -242,8 +242,6 @@ protected:
// - marquee selection (selects all boxes inside a rectangle drawn by the user
// - Ctrl+C to copy selected text (if supported by backend)
//
// FIXME: When the document (or the current page) is changed, resetBoxes()
// should be called to ensure we don't work with the wrong boxes
// TODO: Marquee selection is slow for large rectangles
// TODO: Handle selections spanning multiple pages
// TODO: possibly load boxes asynchronously
......@@ -256,6 +254,7 @@ protected:
// moving the mouse, the boxes information is not updated
class Select : public AbstractTool
{
friend class QtPDF::PDFDocumentView;
public:
Select(PDFDocumentView * parent);
virtual ~Select();
......@@ -271,7 +270,11 @@ protected:
virtual void keyPressEvent(QKeyEvent *event);
void resetBoxes(const int pageNum = -1);
// Call this to notify Select that the page graphics item it has been working
// on has been destroyed so all pointers to graphics items should be
// invalidated
void pageDestroyed();
// The mouse mode depends on whether the LMB is pressed, and where/how it was
// pressed initially (e.g., over a box, over a free area, etc.)
enum MouseMode { MouseMode_None, MouseMode_MarqueeSelect, MouseMode_TextSelect, MouseMode_ImageSelect };
......
......@@ -131,7 +131,10 @@ void PDFDocumentView::setScene(QSharedPointer<PDFDocumentScene> a_scene)
}
_pdf_scene = a_scene;
// Reinitialize all scene-related data
// NB: This also resets any text selection and search results as it clears the
// page graphic items.
reinitializeFromScene();
if (a_scene) {
......@@ -164,9 +167,6 @@ void PDFDocumentView::setScene(QSharedPointer<PDFDocumentScene> a_scene)
// Ensure proper layout
setPageMode(_pageMode, true);
// Ensure search result list is empty in case we are switching from another
// scene.
_searchResults.clear();
if (_pdf_scene)
emit changedDocument(_pdf_scene->document());
else
......@@ -539,7 +539,7 @@ void PDFDocumentView::goToPage(const int pageNum, const QPointF anchor, const in
void PDFDocumentView::goToPDFDestination(const PDFDestination & dest, bool saveOldViewRect /* = true */)
{
if (!dest.isValid() || !dest.isExplicit())
if (!dest.isValid())
return;
Q_ASSERT(_pdf_scene != NULL);
......@@ -548,6 +548,15 @@ void PDFDocumentView::goToPDFDestination(const PDFDestination & dest, bool saveO
if (!doc)
return;
PDFDestination finalDest;
if (!dest.isExplicit()) {
finalDest = doc->resolveDestination(dest);
if (!finalDest.isValid())
return;
}
else
finalDest = dest;
Q_ASSERT(isPageItem(_pdf_scene->pageAt(_currentPage)));
PDFPageGraphicsItem * pageItem = static_cast<PDFPageGraphicsItem*>(_pdf_scene->pageAt(_currentPage));
Q_ASSERT(pageItem != NULL);
......@@ -558,7 +567,7 @@ void PDFDocumentView::goToPDFDestination(const PDFDestination & dest, bool saveO
oldViewport = QRectF(pageItem->mapToPage(oldViewport.topLeft()), \
pageItem->mapToPage(oldViewport.bottomRight()));
// Calculate the new viewport (in page coordinates)
QRectF view(dest.viewport(doc.data(), oldViewport, _zoomLevel));
QRectF view(finalDest.viewport(doc.data(), oldViewport, _zoomLevel));
if (saveOldViewRect) {
PDFDestination origin(_currentPage);
......@@ -567,7 +576,7 @@ void PDFDocumentView::goToPDFDestination(const PDFDestination & dest, bool saveO
_oldViewRects.push(origin);
}
goToPage(static_cast<PDFPageGraphicsItem*>(_pdf_scene->pageAt(dest.page())), view, true);
goToPage(static_cast<PDFPageGraphicsItem*>(_pdf_scene->pageAt(finalDest.page())), view, true);
}
void PDFDocumentView::zoomBy(const qreal zoomFactor, const QGraphicsView::ViewportAnchor anchor /* = QGraphicsView::AnchorViewCenter */)
......@@ -1161,7 +1170,7 @@ void PDFDocumentView::pdfActionTriggered(const PDFAction * action)
// security issue) or to create a new window, we need to propagate this
// up the hierarchy. Otherwise we can handle it ourselves here.
if (actionGoto->isRemote() || actionGoto->openInNewWindow())
emit requestOpenPdf(actionGoto->filename(), actionGoto->destination().page(), actionGoto->openInNewWindow());
emit requestOpenPdf(actionGoto->filename(), actionGoto->destination(), actionGoto->openInNewWindow());
else {
Q_ASSERT(_pdf_scene != NULL);
Q_ASSERT(!_pdf_scene->document().isNull());
......@@ -1244,6 +1253,20 @@ void PDFDocumentView::reinitializeFromScene()
_lastPage = -1;
_currentPage = -1;
}
// Ensure the text selection marker is reset (if any) as it holds pointers to
// page items (highlight path, boxes) that are now changed and/or destroyed.
DocumentTool::Select * selectTool = static_cast<DocumentTool::Select*>(getToolByType(DocumentTool::AbstractTool::Tool_Select));
if (selectTool)
selectTool->pageDestroyed();
// Ensure (old) search data is destroyed as well
if (!_searchResultWatcher.isFinished())
_searchResultWatcher.cancel();
_searchResults.clear();
_currentSearchResult = -1;
// Also reset _searchString. Otherwise the next search for the same string
// will assume the search has already been run (without results as
// _searchResults is empty) and won't run it again on the new scene data.
_searchString = QString();
}
......@@ -1437,13 +1460,14 @@ void PDFDocumentView::wheelEvent(QWheelEvent * event)
if (event->orientation() == Qt::Vertical && event->buttons() == Qt::NoButton && event->modifiers() == Qt::ControlModifier) {
// TODO: Possibly make the Ctrl modifier configurable?
// TODO: According to Qt docs, the delta() is not necessarily the same for all
// mice. Decide if we want to enforce the same step size regardless of the
// resolution of the mouse wheel sensor
if ( delta > 0 )
zoomIn(QGraphicsView::AnchorUnderMouse);
else if ( delta < 0 )
zoomOut(QGraphicsView::AnchorUnderMouse);
// According to Qt docs, the resolution of delta() is not necessarily the
// same for all mice. delta() returns the rotation in 1/8 degrees. Here, we
// use a zoom factor of 1.5 every 15 degrees (= delta() == 120, which seems
// to be a widespread default resolution).
// TODO: for high-resolution mice, this may trigger many small zooms,
// resulting in the rendering of many intermediate resolutions. This can
// cause a lagging display and can potentially fill the pdf cache.