[poppler] 6 commits - qt5/demos qt5/src qt5/tests

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Jan 9 11:31:31 UTC 2019


 qt5/demos/toc.cpp                 |   27 ++---
 qt5/src/CMakeLists.txt            |    1 
 qt5/src/poppler-document.cc       |   16 +++
 qt5/src/poppler-outline-private.h |   45 +++++++++
 qt5/src/poppler-outline.cc        |  177 ++++++++++++++++++++++++++++++++++++++
 qt5/src/poppler-private.cc        |    2 
 qt5/src/poppler-qt5.h             |   88 ++++++++++++++++++
 qt5/tests/CMakeLists.txt          |    1 
 qt5/tests/check_outline.cpp       |   52 +++++++++++
 9 files changed, 394 insertions(+), 15 deletions(-)

New commits:
commit 9b9795e935867f4bc35c4fdb2979dda8c92f6292
Author: Albert Astals Cid <tsdgeos at yahoo.es>
Date:   Wed Jan 9 10:20:15 2019 +0000

    Update since to 0.74

diff --git a/qt5/src/poppler-qt5.h b/qt5/src/poppler-qt5.h
index 31d52cf1..38dd05fc 100644
--- a/qt5/src/poppler-qt5.h
+++ b/qt5/src/poppler-qt5.h
@@ -985,7 +985,7 @@ delete it;
 
        Represents an item in the outline of PDF document, i.e. a name, an internal or external link and a set of child items.
 
-       \since 0.72
+       \since 0.74
     **/
     class POPPLER_QT5_EXPORT OutlineItem {
       friend class Document;
@@ -1656,7 +1656,7 @@ QString subject = m_doc->info("Subject");
 
 	   \returns a vector of outline items, empty if there are none
 
-	   \since 0.72
+	   \since 0.74
 	**/
 	QVector<OutlineItem> outline() const;
 	
commit 3cb662cd84520bb669692bfba0560a1ffd233920
Author: Adam Reichold <adam.reichold at t-online.de>
Date:   Fri Dec 7 09:38:59 2018 +0100

    Add a method the check if an outline item has children to avoid having to eagerly expand the hierarchy anyway.

diff --git a/qt5/src/poppler-outline.cc b/qt5/src/poppler-outline.cc
index c7419296..b420a3ef 100644
--- a/qt5/src/poppler-outline.cc
+++ b/qt5/src/poppler-outline.cc
@@ -147,6 +147,17 @@ QString OutlineItem::uri() const
   return uri;
 }
 
+bool OutlineItem::hasChildren() const
+{
+  bool result = false;
+
+  if (::OutlineItem *data = m_data->data) {
+    result = data->hasKids();
+  }
+
+  return result;
+}
+
 QVector<OutlineItem> OutlineItem::children() const
 {
   QVector<OutlineItem> result;
diff --git a/qt5/src/poppler-qt5.h b/qt5/src/poppler-qt5.h
index d22279ac..31d52cf1 100644
--- a/qt5/src/poppler-qt5.h
+++ b/qt5/src/poppler-qt5.h
@@ -1039,6 +1039,13 @@ delete it;
       QString uri() const;
 
       /**
+	 Determines if this item has any child items
+
+	 \returns true if there are any child items
+      **/
+      bool hasChildren() const;
+
+      /**
 	 Gets the child items of this item
 
 	 \returns a vector outline items, empty if there are none
diff --git a/qt5/tests/check_outline.cpp b/qt5/tests/check_outline.cpp
index 95d780ab..b89a68ad 100644
--- a/qt5/tests/check_outline.cpp
+++ b/qt5/tests/check_outline.cpp
@@ -32,6 +32,7 @@ void TestOutline::checkOutline_xr02()
   QCOMPARE(fooDest->pageNumber(), 1);
   QVERIFY(foo.externalFileName().isEmpty());
   QVERIFY(foo.uri().isEmpty());
+  QVERIFY(!foo.hasChildren());
   QVERIFY(foo.children().isEmpty());
 
   const auto &bar = outline[1];
@@ -43,6 +44,7 @@ void TestOutline::checkOutline_xr02()
   QCOMPARE(barDest->pageNumber(), 2);
   QVERIFY(bar.externalFileName().isEmpty());
   QVERIFY(bar.uri().isEmpty());
+  QVERIFY(!bar.hasChildren());
   QVERIFY(bar.children().isEmpty());
 }
 
commit 3376db5e5b2588c5b4d0df74b5c9a3230ffbc78d
Author: Adam Reichold <adam.reichold at t-online.de>
Date:   Sat Nov 24 18:55:26 2018 +0100

    Port the Qt5 viewer demo to use the lazy outline item API (even if for loading all items up front for now).

diff --git a/qt5/demos/toc.cpp b/qt5/demos/toc.cpp
index 99167360..50d4d68d 100644
--- a/qt5/demos/toc.cpp
+++ b/qt5/demos/toc.cpp
@@ -23,29 +23,28 @@
 #include <QtWidgets/QHeaderView>
 #include <QtWidgets/QTreeWidget>
 
-static void fillToc(const QDomNode &parent, QTreeWidget *tree, QTreeWidgetItem *parentItem)
+static void fillToc(const QVector<Poppler::OutlineItem> &items, QTreeWidget *tree, QTreeWidgetItem *parentItem)
 {
     QTreeWidgetItem *newitem = nullptr;
-    for (QDomNode node = parent.firstChild(); !node.isNull(); node = node.nextSibling()) {
-        QDomElement e = node.toElement();
+    for (const auto &item : items) {
+        if (item.isNull()) {
+            continue;
+        }
 
         if (!parentItem) {
             newitem = new QTreeWidgetItem(tree, newitem);
         } else {
             newitem = new QTreeWidgetItem(parentItem, newitem);
         }
-        newitem->setText(0, e.tagName());
+        newitem->setText(0, item.name());
 
-        bool isOpen = false;
-        if (e.hasAttribute(QStringLiteral("Open"))) {
-            isOpen = QVariant(e.attribute(QStringLiteral("Open"))).toBool();
-        }
-        if (isOpen) {
+        if (item.isOpen()) {
             tree->expandItem(newitem);
         }
 
-        if (e.hasChildNodes()) {
-            fillToc(node, tree, newitem);
+        const auto children = item.children();
+        if (!children.isEmpty()) {
+            fillToc(children, tree, newitem);
         }
     }
 }
@@ -68,9 +67,9 @@ TocDock::~TocDock()
 
 void TocDock::fillInfo()
 {
-    const QDomDocument *toc = document()->toc();
-    if (toc) {
-        fillToc(*toc, m_tree, nullptr);
+    const auto outline = document()->outline();
+    if (!outline.isEmpty()) {
+        fillToc(outline, m_tree, nullptr);
     } else {
         QTreeWidgetItem *item = new QTreeWidgetItem();
         item->setText(0, tr("No TOC"));
commit a2e42c88cee27497517bbab098a917bfd80d26f7
Author: Adam Reichold <adam.reichold at t-online.de>
Date:   Sat Nov 24 18:55:01 2018 +0100

    Add missing doc comments for the lazy outline item API of the Qt5 frontend.

diff --git a/qt5/src/poppler-qt5.h b/qt5/src/poppler-qt5.h
index c8d0cb2a..d22279ac 100644
--- a/qt5/src/poppler-qt5.h
+++ b/qt5/src/poppler-qt5.h
@@ -980,9 +980,19 @@ delete it;
 	PageData *m_page;
     };
 
+    /**
+       \brief Item in the outline of a PDF document
+
+       Represents an item in the outline of PDF document, i.e. a name, an internal or external link and a set of child items.
+
+       \since 0.72
+    **/
     class POPPLER_QT5_EXPORT OutlineItem {
       friend class Document;
     public:
+      /**
+	 Constructs a null item, i.e. one that does not represent a valid item in the outline of some PDF document.
+      **/
       OutlineItem();
       ~OutlineItem();
 
@@ -992,18 +1002,47 @@ delete it;
       OutlineItem(OutlineItem &&other);
       OutlineItem &operator=(OutlineItem &&other);
 
+      /**
+	 Indicates whether an item is null, i.e. whether it does not represent a valid item in the outline of some PDF document.
+      **/
       bool isNull() const;
 
+      /**
+	 The name of the item which should be displayed to the user.
+      **/
       QString name() const;
 
+      /**
+	 Indicates whether the item should initially be display in an expanded or collapsed state.
+      **/
       bool isOpen() const;
 
+      /**
+	 The destination referred to by this item.
+
+	 \returns a shared pointer to an immutable link destination
+      **/
       QSharedPointer<const LinkDestination> destination() const;
 
+      /**
+	 The external file name of the document to which the \see destination refers
+
+	 \returns a string with the external file name or an empty string if there is none
+       */
       QString externalFileName() const;
 
+      /**
+	 The URI to which the item links
+
+	 \returns a string with the URI which this item links or an empty string if there is none
+      **/
       QString uri() const;
 
+      /**
+	 Gets the child items of this item
+
+	 \returns a vector outline items, empty if there are none
+      **/
       QVector<OutlineItem> children() const;
 
     private:
@@ -1605,6 +1644,13 @@ QString subject = m_doc->info("Subject");
 	*/
 	QDomDocument *toc() const;
 
+	/**
+	   Gets the outline of the document
+
+	   \returns a vector of outline items, empty if there are none
+
+	   \since 0.72
+	**/
 	QVector<OutlineItem> outline() const;
 	
 	/**
commit c0fc05ed1113383bcbb55272bd64e1842490e2a1
Author: Adam Reichold <adam.reichold at t-online.de>
Date:   Wed Oct 31 21:19:55 2018 +0100

    Remove the intermediate Outline type since all items are owned by the document and the top-level items will always be eagerly loaded anyway.

diff --git a/qt5/src/poppler-document.cc b/qt5/src/poppler-document.cc
index 1b5eb1d2..0aa5bed4 100644
--- a/qt5/src/poppler-document.cc
+++ b/qt5/src/poppler-document.cc
@@ -586,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;
 
@@ -601,13 +601,19 @@ namespace Poppler {
         return toc;
     }
 
-    Outline *Document::outline() const
+    QVector<OutlineItem> Document::outline() const
     {
-      if (auto *outline = m_doc->doc->getOutline()) {
-	return new Outline{new OutlineData{outline, m_doc}};
+      QVector<OutlineItem> result;
+
+      if (::Outline *outline = m_doc->doc->getOutline()) {
+	if (const GooList *items = outline->getItems()) {
+	  for (void *item : *items) {
+	    result.push_back(OutlineItem{new OutlineItemData{static_cast<::OutlineItem *>(item), m_doc}});
+	  }
+	}
       }
 
-      return nullptr;
+      return result;
     }
 
     LinkDestination *Document::linkDestination( const QString &name )
diff --git a/qt5/src/poppler-outline-private.h b/qt5/src/poppler-outline-private.h
index ccc0f8c9..6c00c162 100644
--- a/qt5/src/poppler-outline-private.h
+++ b/qt5/src/poppler-outline-private.h
@@ -40,13 +40,6 @@ struct OutlineItemData
   mutable QString uri;
 };
 
-struct OutlineData
-{
-  OutlineData(const ::Outline *data, DocumentData *documentData) : data{data}, documentData{documentData} {}
-  const ::Outline *data;
-  DocumentData *documentData;
-};
-
 }
 
 #endif
diff --git a/qt5/src/poppler-outline.cc b/qt5/src/poppler-outline.cc
index a6e4b092..c7419296 100644
--- a/qt5/src/poppler-outline.cc
+++ b/qt5/src/poppler-outline.cc
@@ -163,27 +163,4 @@ QVector<OutlineItem> OutlineItem::children() const
   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;
-}
-
 }
diff --git a/qt5/src/poppler-qt5.h b/qt5/src/poppler-qt5.h
index 6bc96a24..c8d0cb2a 100644
--- a/qt5/src/poppler-qt5.h
+++ b/qt5/src/poppler-qt5.h
@@ -71,7 +71,6 @@ namespace Poppler {
     class PSConverter;
 
     struct OutlineItemData;
-    struct OutlineData;
 
     /**
 	Debug/error function.
@@ -982,7 +981,7 @@ delete it;
     };
 
     class POPPLER_QT5_EXPORT OutlineItem {
-      friend class Outline;
+      friend class Document;
     public:
       OutlineItem();
       ~OutlineItem();
@@ -1012,20 +1011,6 @@ delete it;
       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.
 
@@ -1620,7 +1605,7 @@ QString subject = m_doc->info("Subject");
 	*/
 	QDomDocument *toc() const;
 
-	Outline *outline() const;
+	QVector<OutlineItem> outline() const;
 	
 	/**
 	   Tries to resolve the named destination \p name.
diff --git a/qt5/tests/check_outline.cpp b/qt5/tests/check_outline.cpp
index c42f5e0e..95d780ab 100644
--- a/qt5/tests/check_outline.cpp
+++ b/qt5/tests/check_outline.cpp
@@ -20,15 +20,10 @@ void TestOutline::checkOutline_xr02()
   };
   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 outline = document->outline();
+  QCOMPARE(outline.size(), 2);
 
-  const auto &foo = items[0];
+  const auto &foo = outline[0];
   QVERIFY(!foo.isNull());
   QCOMPARE(foo.name(), QStringLiteral("foo"));
   QCOMPARE(foo.isOpen(), false);
@@ -39,7 +34,7 @@ void TestOutline::checkOutline_xr02()
   QVERIFY(foo.uri().isEmpty());
   QVERIFY(foo.children().isEmpty());
 
-  const auto &bar = items[1];
+  const auto &bar = outline[1];
   QVERIFY(!bar.isNull());
   QCOMPARE(bar.name(), QStringLiteral("bar"));
   QCOMPARE(bar.isOpen(), false);
commit 13b5eae9f785a70bc6b9af8e773a555665a1b39c
Author: Adam Reichold <adam.reichold at t-online.de>
Date:   Wed Oct 31 19:03:57 2018 +0100

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

diff --git a/qt5/src/CMakeLists.txt b/qt5/src/CMakeLists.txt
index c94390c5..97282128 100644
--- a/qt5/src/CMakeLists.txt
+++ b/qt5/src/CMakeLists.txt
@@ -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
 )
diff --git a/qt5/src/poppler-document.cc b/qt5/src/poppler-document.cc
index 216ef582..1b5eb1d2 100644
--- a/qt5/src/poppler-document.cc
+++ b/qt5/src/poppler-document.cc
@@ -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 );
diff --git a/qt5/src/poppler-outline-private.h b/qt5/src/poppler-outline-private.h
new file mode 100644
index 00000000..ccc0f8c9
--- /dev/null
+++ b/qt5/src/poppler-outline-private.h
@@ -0,0 +1,52 @@
+/* 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
diff --git a/qt5/src/poppler-outline.cc b/qt5/src/poppler-outline.cc
new file mode 100644
index 00000000..a6e4b092
--- /dev/null
+++ b/qt5/src/poppler-outline.cc
@@ -0,0 +1,189 @@
+/* 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;
+}
+
+}
diff --git a/qt5/src/poppler-private.cc b/qt5/src/poppler-private.cc
index 333aafe3..0c178a54 100644
--- a/qt5/src/poppler-private.cc
+++ b/qt5/src/poppler-private.cc
@@ -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;
diff --git a/qt5/src/poppler-qt5.h b/qt5/src/poppler-qt5.h
index 5373a3a1..6bc96a24 100644
--- a/qt5/src/poppler-qt5.h
+++ b/qt5/src/poppler-qt5.h
@@ -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.
diff --git a/qt5/tests/CMakeLists.txt b/qt5/tests/CMakeLists.txt
index 7fda2687..5abcbc45 100644
--- a/qt5/tests/CMakeLists.txt
+++ b/qt5/tests/CMakeLists.txt
@@ -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)
diff --git a/qt5/tests/check_outline.cpp b/qt5/tests/check_outline.cpp
new file mode 100644
index 00000000..c42f5e0e
--- /dev/null
+++ b/qt5/tests/check_outline.cpp
@@ -0,0 +1,55 @@
+#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"


More information about the poppler mailing list