1 /* poppler-outline.cc: qt interface to poppler
2  *
3  * Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
4  * Copyright (C) 2019 Oliver Sander <oliver.sander@tu-dresden.de>
5  * Copyright (C) 2019 Albert Astals Cid <aacid@kde.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 #include <poppler-qt5.h>
23 #include <poppler-link.h>
24 
25 #include "poppler-private.h"
26 #include "poppler-outline-private.h"
27 
28 #include "Link.h"
29 #include "Outline.h"
30 
31 namespace Poppler {
32 
OutlineItem()33 OutlineItem::OutlineItem() : m_data { new OutlineItemData { nullptr, nullptr } } { }
34 
OutlineItem(OutlineItemData * data)35 OutlineItem::OutlineItem(OutlineItemData *data) : m_data { data } { }
36 
~OutlineItem()37 OutlineItem::~OutlineItem()
38 {
39     delete m_data;
40     m_data = nullptr;
41 }
42 
OutlineItem(const OutlineItem & other)43 OutlineItem::OutlineItem(const OutlineItem &other) : m_data { new OutlineItemData { *other.m_data } } { }
44 
operator =(const OutlineItem & other)45 OutlineItem &OutlineItem::operator=(const OutlineItem &other)
46 {
47     if (this == &other)
48         return *this;
49 
50     auto *data = new OutlineItemData { *other.m_data };
51     qSwap(m_data, data);
52     delete data;
53 
54     return *this;
55 }
56 
OutlineItem(OutlineItem && other)57 OutlineItem::OutlineItem(OutlineItem &&other) noexcept : m_data { other.m_data }
58 {
59     other.m_data = nullptr;
60 }
61 
operator =(OutlineItem && other)62 OutlineItem &OutlineItem::operator=(OutlineItem &&other) noexcept
63 {
64     qSwap(m_data, other.m_data);
65 
66     return *this;
67 }
68 
isNull() const69 bool OutlineItem::isNull() const
70 {
71     return !m_data->data;
72 }
73 
name() const74 QString OutlineItem::name() const
75 {
76     QString &name = m_data->name;
77 
78     if (name.isEmpty()) {
79         if (const ::OutlineItem *data = m_data->data) {
80             name = unicodeToQString(data->getTitle(), data->getTitleLength());
81         }
82     }
83 
84     return name;
85 }
86 
isOpen() const87 bool OutlineItem::isOpen() const
88 {
89     bool isOpen = false;
90 
91     if (const ::OutlineItem *data = m_data->data) {
92         isOpen = data->isOpen();
93     }
94 
95     return isOpen;
96 }
97 
destination() const98 QSharedPointer<const LinkDestination> OutlineItem::destination() const
99 {
100     QSharedPointer<const LinkDestination> &destination = m_data->destination;
101 
102     if (!destination) {
103         if (const ::OutlineItem *data = m_data->data) {
104             if (const ::LinkAction *action = data->getAction()) {
105                 if (action->getKind() == actionGoTo) {
106                     const auto *linkGoTo = static_cast<const LinkGoTo *>(action);
107                     destination.reset(new LinkDestination(LinkDestinationData(linkGoTo->getDest(), linkGoTo->getNamedDest(), m_data->documentData, false)));
108                 } else if (action->getKind() == actionGoToR) {
109                     const auto *linkGoToR = static_cast<const LinkGoToR *>(action);
110                     const bool external = linkGoToR->getFileName() != nullptr;
111                     destination.reset(new LinkDestination(LinkDestinationData(linkGoToR->getDest(), linkGoToR->getNamedDest(), m_data->documentData, external)));
112                 }
113             }
114         }
115     }
116 
117     return destination;
118 }
119 
externalFileName() const120 QString OutlineItem::externalFileName() const
121 {
122     QString &externalFileName = m_data->externalFileName;
123 
124     if (externalFileName.isEmpty()) {
125         if (const ::OutlineItem *data = m_data->data) {
126             if (const ::LinkAction *action = data->getAction()) {
127                 if (action->getKind() == actionGoToR) {
128                     if (const GooString *fileName = static_cast<const LinkGoToR *>(action)->getFileName()) {
129                         externalFileName = UnicodeParsedString(fileName);
130                     }
131                 }
132             }
133         }
134     }
135 
136     return externalFileName;
137 }
138 
uri() const139 QString OutlineItem::uri() const
140 {
141     QString &uri = m_data->uri;
142 
143     if (uri.isEmpty()) {
144         if (const ::OutlineItem *data = m_data->data) {
145             if (const ::LinkAction *action = data->getAction()) {
146                 if (action->getKind() == actionURI) {
147                     uri = UnicodeParsedString(static_cast<const LinkURI *>(action)->getURI());
148                 }
149             }
150         }
151     }
152 
153     return uri;
154 }
155 
hasChildren() const156 bool OutlineItem::hasChildren() const
157 {
158     bool result = false;
159 
160     if (::OutlineItem *data = m_data->data) {
161         result = data->hasKids();
162     }
163 
164     return result;
165 }
166 
children() const167 QVector<OutlineItem> OutlineItem::children() const
168 {
169     QVector<OutlineItem> result;
170 
171     if (::OutlineItem *data = m_data->data) {
172         data->open();
173         if (const std::vector<::OutlineItem *> *kids = data->getKids()) {
174             for (void *kid : *kids) {
175                 result.push_back(OutlineItem { new OutlineItemData { static_cast<::OutlineItem *>(kid), m_data->documentData } });
176             }
177         }
178     }
179 
180     return result;
181 }
182 
183 }
184