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 c94390c..9728212 100644
--- a/qt5/src/CMakeLists.txt
+++ b/qt5/src/CMakeLists.txt
@@ -34,6 +34,7 @@
   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 216ef58..1b5eb1d 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 @@
     
     QDomDocument *Document::toc() const
     {
-        Outline * outline = m_doc->doc->getOutline();
+	::Outline * outline = m_doc->doc->getOutline();
         if ( !outline )
             return nullptr;
 
@@ -600,6 +601,15 @@
         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 0000000..ccc0f8c
--- /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 0000000..a6e4b09
--- /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 333aafe..0c178a5 100644
--- a/qt5/src/poppler-private.cc
+++ b/qt5/src/poppler-private.cc
@@ -288,7 +288,7 @@
         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 5373a3a..6bc96a2 100644
--- a/qt5/src/poppler-qt5.h
+++ b/qt5/src/poppler-qt5.h
@@ -70,6 +70,9 @@
     class PDFConverter;
     class PSConverter;
 
+    struct OutlineItemData;
+    struct OutlineData;
+
     /**
 	Debug/error function.
 
@@ -978,6 +981,51 @@
 	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 @@
 	  \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 7fda268..5abcbc4 100644
--- a/qt5/tests/CMakeLists.txt
+++ b/qt5/tests/CMakeLists.txt
@@ -73,6 +73,7 @@
 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 0000000..c42f5e0
--- /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"