Spaces:
Running
Running
/* | |
* Copyright (C) 2008, Pino Toscano <[email protected]> | |
* Copyright (C) 2018, Adam Reichold <[email protected]> | |
* Copyright (C) 2019, Albert Astals Cid <[email protected]> | |
* | |
* 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. | |
*/ | |
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() override { 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(); | |
} | |