| /* |
| * Copyright (C) 2008, Pino Toscano <pino@kde.org> |
| * Copyright (C) 2018, Adam Reichold <adam.reichold@t-online.de> |
| * Copyright (C) 2019, Albert Astals Cid <aacid@kde.org> |
| * |
| * 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 "toc.h" |
| |
| #include <poppler-qt5.h> |
| |
| #include <QtGui/QStandardItemModel> |
| #include <QtWidgets/QHeaderView> |
| #include <QtWidgets/QTreeWidget> |
| |
| #include <QDebug> |
| |
| struct Node |
| { |
| Node(Poppler::OutlineItem &&item, int row, Node *parent) |
| : m_row(row), m_parent(parent), m_item(std::move(item)) |
| { |
| } |
| |
| ~Node() |
| { |
| qDeleteAll(m_children); |
| } |
| |
| Node(const Node &) = delete; |
| Node& operator=(const Node &) = delete; |
| |
| int m_row; |
| Node *m_parent; |
| Poppler::OutlineItem m_item; |
| QVector<Node *> m_children; |
| }; |
| |
| class TocModel : public QAbstractItemModel |
| { |
| Q_OBJECT |
| public: |
| TocModel(QVector<Poppler::OutlineItem> &&items, QObject *parent) |
| : QAbstractItemModel(parent) |
| { |
| for (int i = 0; i < items.count(); ++i) { |
| m_topItems << new Node(std::move(items[i]), i, nullptr); |
| } |
| } |
| |
| ~TocModel() |
| { |
| qDeleteAll(m_topItems); |
| } |
| |
| QVariant data(const QModelIndex &index, int role) const override |
| { |
| if (role != Qt::DisplayRole) |
| return {}; |
| |
| Node *n = static_cast<Node*>(index.internalPointer()); |
| return n->m_item.name(); |
| } |
| |
| QModelIndex index(int row, int column, const QModelIndex &parent) const override |
| { |
| Node *p = static_cast<Node*>(parent.internalPointer()); |
| const QVector<Node *> &children = p ? p->m_children : m_topItems; |
| |
| return createIndex(row, column, children[row]); |
| } |
| |
| QModelIndex parent(const QModelIndex &child) const override |
| { |
| Node *n = static_cast<Node*>(child.internalPointer()); |
| if (n->m_parent == nullptr) |
| return QModelIndex(); |
| else |
| return createIndex(n->m_parent->m_row, 0, n->m_parent); |
| } |
| |
| int rowCount(const QModelIndex &parent) const override |
| { |
| Node *n = static_cast<Node*>(parent.internalPointer()); |
| if (!n) { |
| return m_topItems.count(); |
| } |
| |
| if (n->m_children.isEmpty() && !n->m_item.isNull()) { |
| QVector<Poppler::OutlineItem> items = n->m_item.children(); |
| for (int i = 0; i < items.count(); ++i) { |
| n->m_children << new Node(std::move(items[i]), i, n); |
| } |
| } |
| |
| return n->m_children.count(); |
| } |
| |
| bool hasChildren(const QModelIndex &parent) const override |
| { |
| Node *n = static_cast<Node*>(parent.internalPointer()); |
| if (!n) |
| return true; |
| |
| return n->m_item.hasChildren(); |
| } |
| |
| int columnCount(const QModelIndex &parent) const override |
| { |
| return 1; |
| } |
| |
| private: |
| QVector<Node *> m_topItems; |
| |
| }; |
| |
| TocDock::TocDock(QWidget *parent) |
| : AbstractInfoDock(parent) |
| { |
| m_tree = new QTreeView(this); |
| setWidget(m_tree); |
| m_tree->setAlternatingRowColors(true); |
| m_tree->header()->hide(); |
| setWindowTitle(tr("TOC")); |
| m_tree->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); |
| } |
| |
| TocDock::~TocDock() |
| { |
| } |
| |
| void TocDock::expandItemModels(const QModelIndex &parent) |
| { |
| TocModel *model = static_cast<TocModel*>(m_tree->model()); |
| for (int i = 0; i < model->rowCount(parent); ++i) { |
| QModelIndex index = model->index(i, 0, parent); |
| Node *n = static_cast<Node*>(index.internalPointer()); |
| if (n->m_item.isOpen()) { |
| m_tree->setExpanded(index, true); |
| expandItemModels(index); |
| } |
| } |
| } |
| |
| void TocDock::fillInfo() |
| { |
| auto outline = document()->outline(); |
| if (!outline.isEmpty()) { |
| TocModel *model = new TocModel(std::move(outline), this); |
| m_tree->setModel(model); |
| |
| expandItemModels(QModelIndex()); |
| } else { |
| QStandardItemModel *model = new QStandardItemModel(this); |
| QStandardItem *item = new QStandardItem(tr("No TOC")); |
| item->setFlags(item->flags() & ~Qt::ItemIsEnabled); |
| model->appendRow(item); |
| m_tree->setModel(model); |
| } |
| } |
| |
| void TocDock::documentClosed() |
| { |
| m_tree->setModel(nullptr); |
| AbstractInfoDock::documentClosed(); |
| } |
| |
| #include "toc.moc" |