Commit 13b5eae9 authored by Adam Reichold's avatar Adam Reichold Committed by Albert Astals Cid

Add Qt5 API that lazily builds an outline by wrapping the internal objects.

parent 29fa0f23
......@@ -34,6 +34,7 @@ set(poppler_qt5_SRCS
poppler-textbox.cc
poppler-page-transition.cc
poppler-media.cc
poppler-outline.cc
ArthurOutputDev.cc
poppler-version.cpp
)
......
......@@ -48,6 +48,7 @@
#include "poppler-private.h"
#include "poppler-page-private.h"
#include "poppler-outline-private.h"
#if defined(USE_CMS)
#include <lcms2.h>
......@@ -585,7 +586,7 @@ namespace Poppler {
QDomDocument *Document::toc() const
{
Outline * outline = m_doc->doc->getOutline();
::Outline * outline = m_doc->doc->getOutline();
if ( !outline )
return nullptr;
......@@ -600,6 +601,15 @@ namespace Poppler {
return toc;
}
Outline *Document::outline() const
{
if (auto *outline = m_doc->doc->getOutline()) {
return new Outline{new OutlineData{outline, m_doc}};
}
return nullptr;
}
LinkDestination *Document::linkDestination( const QString &name )
{
GooString * namedDest = QStringToGooString( name );
......
/* poppler-outline-private.h: qt interface to poppler
*
* 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_OUTLINE_PRIVATE_H_
#define _POPPLER_OUTLINE_PRIVATE_H_
#include <QtCore/QSharedPointer>
#include <QtCore/QString>
class OutlineItem;
namespace Poppler {
class DocumentData;
class LinkDestination;
struct OutlineItemData
{
OutlineItemData(::OutlineItem *data, DocumentData *documentData) : data{data}, documentData{documentData} {}
::OutlineItem *data;
DocumentData *documentData;
mutable QString name;
mutable QSharedPointer<const LinkDestination> destination;
mutable QString externalFileName;
mutable QString uri;
};
struct OutlineData
{
OutlineData(const ::Outline *data, DocumentData *documentData) : data{data}, documentData{documentData} {}
const ::Outline *data;
DocumentData *documentData;
};
}
#endif
/* poppler-outline.cc: qt interface to poppler
*
* 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-qt5.h>
#include <poppler-link.h>
#include "poppler-private.h"
#include "poppler-outline-private.h"
#include "GooList.h"
#include "Link.h"
#include "Outline.h"
namespace Poppler {
OutlineItem::OutlineItem() : m_data{new OutlineItemData{nullptr, nullptr}} {}
OutlineItem::OutlineItem(OutlineItemData *data) : m_data{data} {}
OutlineItem::~OutlineItem()
{
delete m_data;
m_data = nullptr;
}
OutlineItem::OutlineItem(const OutlineItem &other) : m_data{new OutlineItemData{*other.m_data}} {}
OutlineItem &OutlineItem::operator=(const OutlineItem &other)
{
auto *data = new OutlineItemData{*other.m_data};
qSwap(m_data, data);
delete data;
return *this;
}
OutlineItem::OutlineItem(OutlineItem &&other) : m_data{other.m_data}
{
other.m_data = nullptr;
}
OutlineItem &OutlineItem::operator=(OutlineItem &&other)
{
qSwap(m_data, other.m_data);
return *this;
}
bool OutlineItem::isNull() const
{
return !m_data->data;
}
QString OutlineItem::name() const
{
QString &name = m_data->name;
if (name.isEmpty()) {
if (const ::OutlineItem *data = m_data->data) {
name = unicodeToQString(data->getTitle(), data->getTitleLength());
}
}
return name;
}
bool OutlineItem::isOpen() const
{
bool isOpen = false;
if (const ::OutlineItem *data = m_data->data) {
isOpen = data->isOpen();
}
return isOpen;
}
QSharedPointer<const LinkDestination> OutlineItem::destination() const
{
QSharedPointer<const LinkDestination> &destination = m_data->destination;
if (!destination) {
if (const ::OutlineItem *data = m_data->data) {
if (const ::LinkAction *action = data->getAction()) {
if (action->getKind() == actionGoTo) {
const auto *linkGoTo = static_cast<const LinkGoTo *>(action);
destination.reset(new LinkDestination(LinkDestinationData(linkGoTo->getDest(), linkGoTo->getNamedDest(), m_data->documentData, false)));
} else if (action->getKind() == actionGoToR) {
const auto *linkGoToR = static_cast<const LinkGoToR *>(action);
const bool external = linkGoToR->getFileName() != nullptr;
destination.reset(new LinkDestination(LinkDestinationData(linkGoToR->getDest(), linkGoToR->getNamedDest(), m_data->documentData, external)));
}
}
}
}
return destination;
}
QString OutlineItem::externalFileName() const
{
QString &externalFileName = m_data->externalFileName;
if (externalFileName.isEmpty()) {
if (const ::OutlineItem *data = m_data->data) {
if (const ::LinkAction *action = data->getAction()) {
if (action->getKind() == actionGoToR) {
if (const GooString *fileName = static_cast<const LinkGoToR *>(action)->getFileName()) {
externalFileName = UnicodeParsedString(fileName);
}
}
}
}
}
return externalFileName;
}
QString OutlineItem::uri() const
{
QString &uri = m_data->uri;
if (uri.isEmpty()) {
if (const ::OutlineItem *data = m_data->data) {
if (const ::LinkAction *action = data->getAction()) {
if (action->getKind() == actionURI) {
uri = UnicodeParsedString(static_cast<const LinkURI *>(action)->getURI());
}
}
}
}
return uri;
}
QVector<OutlineItem> OutlineItem::children() const
{
QVector<OutlineItem> result;
if (::OutlineItem *data = m_data->data) {
data->open();
if (const GooList *kids = data->getKids()) {
for (void *kid : *kids) {
result.push_back(OutlineItem{new OutlineItemData{static_cast<::OutlineItem *>(kid), m_data->documentData}});
}
}
}
return result;
}
Outline::Outline(OutlineData *data) : m_data{data} {}
Outline::~Outline()
{
delete m_data;
m_data = nullptr;
}
QVector<OutlineItem> Outline::items() const
{
QVector<OutlineItem> result;
const ::Outline *data = m_data->data;
if (const GooList *items = data->getItems()) {
for (void *item : *items) {
result.push_back(OutlineItem{new OutlineItemData{static_cast<::OutlineItem *>(item), m_data->documentData}});
}
}
return result;
}
}
......@@ -288,7 +288,7 @@ namespace Debug {
for ( int i = 0; i < numItems; ++i )
{
// iterate over every object in 'items'
OutlineItem * outlineItem = (OutlineItem *)items->get( i );
::OutlineItem * outlineItem = (::OutlineItem *)items->get( i );
// 1. create element using outlineItem's title as tagName
QString name;
......
......@@ -70,6 +70,9 @@ namespace Poppler {
class PDFConverter;
class PSConverter;
struct OutlineItemData;
struct OutlineData;
/**
Debug/error function.
......@@ -978,6 +981,51 @@ delete it;
PageData *m_page;
};
class POPPLER_QT5_EXPORT OutlineItem {
friend class Outline;
public:
OutlineItem();
~OutlineItem();
OutlineItem(const OutlineItem &other);
OutlineItem &operator=(const OutlineItem &other);
OutlineItem(OutlineItem &&other);
OutlineItem &operator=(OutlineItem &&other);
bool isNull() const;
QString name() const;
bool isOpen() const;
QSharedPointer<const LinkDestination> destination() const;
QString externalFileName() const;
QString uri() const;
QVector<OutlineItem> children() const;
private:
OutlineItem(OutlineItemData *data);
OutlineItemData *m_data;
};
class POPPLER_QT5_EXPORT Outline {
friend class Document;
public:
~Outline();
QVector<OutlineItem> items() const;
private:
Q_DISABLE_COPY(Outline)
Outline(OutlineData *data);
OutlineData *m_data;
};
/**
\brief PDF document.
......@@ -1571,6 +1619,8 @@ QString subject = m_doc->info("Subject");
\returns the TOC, or NULL if the Document does not have one
*/
QDomDocument *toc() const;
Outline *outline() const;
/**
Tries to resolve the named destination \p name.
......
......@@ -73,6 +73,7 @@ qt5_add_qtest(check_qt5_lexer check_lexer.cpp)
qt5_add_qtest(check_qt5_goostring check_goostring.cpp)
qt5_add_qtest(check_qt5_object check_object.cpp)
qt5_add_qtest(check_qt5_utf_conversion check_utf_conversion.cpp)
qt5_add_qtest(check_qt5_outline check_outline.cpp)
if (NOT WIN32)
qt5_add_qtest(check_qt5_pagelabelinfo check_pagelabelinfo.cpp)
qt5_add_qtest(check_qt5_strings check_strings.cpp)
......
#include <QtTest/QtTest>
#include <poppler-qt5.h>
#include <memory>
class TestOutline : public QObject
{
Q_OBJECT
public:
TestOutline(QObject *parent = nullptr) : QObject(parent) {}
private slots:
void checkOutline_xr02();
};
void TestOutline::checkOutline_xr02()
{
std::unique_ptr<Poppler::Document> document{
Poppler::Document::load(TESTDATADIR "/unittestcases/xr02.pdf")
};
QVERIFY(document.get());
std::unique_ptr<Poppler::Outline> outline{
document->outline()
};
QVERIFY(outline.get());
const auto items = outline->items();
QCOMPARE(items.size(), 2);
const auto &foo = items[0];
QVERIFY(!foo.isNull());
QCOMPARE(foo.name(), QStringLiteral("foo"));
QCOMPARE(foo.isOpen(), false);
const auto fooDest = foo.destination();
QVERIFY(!fooDest.isNull());
QCOMPARE(fooDest->pageNumber(), 1);
QVERIFY(foo.externalFileName().isEmpty());
QVERIFY(foo.uri().isEmpty());
QVERIFY(foo.children().isEmpty());
const auto &bar = items[1];
QVERIFY(!bar.isNull());
QCOMPARE(bar.name(), QStringLiteral("bar"));
QCOMPARE(bar.isOpen(), false);
const auto barDest = bar.destination();
QVERIFY(!barDest.isNull());
QCOMPARE(barDest->pageNumber(), 2);
QVERIFY(bar.externalFileName().isEmpty());
QVERIFY(bar.uri().isEmpty());
QVERIFY(bar.children().isEmpty());
}
QTEST_GUILESS_MAIN(TestOutline)
#include "check_outline.moc"
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment