/* * Copyright (C) 2008, Pino Toscano * Copyright (C) 2018, Adam Reichold * Copyright (C) 2019, Albert Astals Cid * * 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 #include #include #include #include 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 m_children; }; class TocModel : public QAbstractItemModel { Q_OBJECT public: TocModel(QVector &&items, QObject *parent) : QAbstractItemModel(parent) { for (int i = 0; i < items.count(); ++i) { m_topItems << new Node(std::move(items[i]), i, nullptr); } } ~TocModel() override { qDeleteAll(m_topItems); } QVariant data(const QModelIndex &index, int role) const override { if (role != Qt::DisplayRole) { return {}; } Node *n = static_cast(index.internalPointer()); return n->m_item.name(); } QModelIndex index(int row, int column, const QModelIndex &parent) const override { Node *p = static_cast(parent.internalPointer()); const QVector &children = p ? p->m_children : m_topItems; return createIndex(row, column, children[row]); } QModelIndex parent(const QModelIndex &child) const override { Node *n = static_cast(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(parent.internalPointer()); if (!n) { return m_topItems.count(); } if (n->m_children.isEmpty() && !n->m_item.isNull()) { QVector 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(parent.internalPointer()); if (!n) { return true; } return n->m_item.hasChildren(); } int columnCount(const QModelIndex &parent) const override { return 1; } private: QVector 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(m_tree->model()); for (int i = 0; i < model->rowCount(parent); ++i) { QModelIndex index = model->index(i, 0, parent); Node *n = static_cast(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"