File indexing completed on 2024-04-28 15:52:00

0001 /*
0002     SPDX-FileCopyrightText: 2004-2006 Albert Astals Cid <aacid@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "toc.h"
0008 
0009 // qt/kde includes
0010 #include <QContextMenuEvent>
0011 #include <QHeaderView>
0012 #include <QLayout>
0013 #include <QTreeView>
0014 #include <qdom.h>
0015 
0016 #include <KLineEdit>
0017 #include <KLocalizedString>
0018 #include <KTitleWidget>
0019 
0020 #include <kwidgetsaddons_version.h>
0021 
0022 // local includes
0023 #include "core/action.h"
0024 #include "gui/tocmodel.h"
0025 #include "ktreeviewsearchline.h"
0026 #include "pageitemdelegate.h"
0027 #include "settings.h"
0028 
0029 TOC::TOC(QWidget *parent, Okular::Document *document)
0030     : QWidget(parent)
0031     , m_document(document)
0032 {
0033     QVBoxLayout *mainlay = new QVBoxLayout(this);
0034     mainlay->setSpacing(6);
0035 
0036     KTitleWidget *titleWidget = new KTitleWidget(this);
0037     titleWidget->setLevel(4);
0038     titleWidget->setText(i18n("Contents"));
0039     mainlay->addWidget(titleWidget);
0040     mainlay->setAlignment(titleWidget, Qt::AlignHCenter);
0041     m_searchLine = new KTreeViewSearchLine(this);
0042     mainlay->addWidget(m_searchLine);
0043     m_searchLine->setPlaceholderText(i18n("Search..."));
0044     m_searchLine->setCaseSensitivity(Okular::Settings::self()->contentsSearchCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive);
0045     m_searchLine->setRegularExpression(Okular::Settings::self()->contentsSearchRegularExpression());
0046     connect(m_searchLine, &KTreeViewSearchLine::searchOptionsChanged, this, &TOC::saveSearchOptions);
0047 
0048     m_treeView = new QTreeView(this);
0049     mainlay->addWidget(m_treeView);
0050     m_model = new TOCModel(document, m_treeView);
0051     m_treeView->setModel(m_model);
0052     m_treeView->setSortingEnabled(false);
0053     m_treeView->setRootIsDecorated(true);
0054     m_treeView->setAlternatingRowColors(true);
0055     m_treeView->setItemDelegate(new PageItemDelegate(m_treeView));
0056     m_treeView->header()->hide();
0057     m_treeView->setSelectionBehavior(QAbstractItemView::SelectRows);
0058     connect(m_treeView, &QTreeView::clicked, this, &TOC::slotExecuted);
0059     connect(m_treeView, &QTreeView::activated, this, &TOC::slotExecuted);
0060     m_searchLine->setTreeView(m_treeView);
0061 }
0062 
0063 TOC::~TOC()
0064 {
0065     m_document->removeObserver(this);
0066 }
0067 
0068 void TOC::notifySetup(const QVector<Okular::Page *> & /*pages*/, int setupFlags)
0069 {
0070     if (!(setupFlags & Okular::DocumentObserver::DocumentChanged)) {
0071         return;
0072     }
0073 
0074     // clear contents
0075     m_model->clear();
0076 
0077     // request synopsis description (is a dom tree)
0078     const Okular::DocumentSynopsis *syn = m_document->documentSynopsis();
0079     if (!syn) {
0080         if (m_document->isOpened()) {
0081             // Make sure we clear the reload old model data
0082             m_model->setOldModelData(nullptr, QVector<QModelIndex>());
0083         }
0084         Q_EMIT hasTOC(false);
0085         return;
0086     }
0087 
0088     m_model->fill(syn);
0089     Q_EMIT hasTOC(!m_model->isEmpty());
0090 }
0091 
0092 void TOC::notifyCurrentPageChanged(int, int)
0093 {
0094     m_model->setCurrentViewport(m_document->viewport());
0095 }
0096 
0097 void TOC::prepareForReload()
0098 {
0099     if (m_model->isEmpty()) {
0100         return;
0101     }
0102 
0103     const QVector<QModelIndex> list = expandedNodes();
0104     TOCModel *m = m_model;
0105     m_model = new TOCModel(m_document, m_treeView);
0106     m_model->setOldModelData(m, list);
0107     m->setParent(nullptr);
0108 }
0109 
0110 void TOC::rollbackReload()
0111 {
0112     if (!m_model->hasOldModelData()) {
0113         return;
0114     }
0115 
0116     TOCModel *m = m_model;
0117     m_model = m->clearOldModelData();
0118     m_model->setParent(m_treeView);
0119     delete m;
0120 }
0121 
0122 void TOC::finishReload()
0123 {
0124     m_treeView->setModel(m_model);
0125     m_model->setParent(m_treeView);
0126 }
0127 
0128 QVector<QModelIndex> TOC::expandedNodes(const QModelIndex &parent) const
0129 {
0130     QVector<QModelIndex> list;
0131     for (int i = 0; i < m_model->rowCount(parent); i++) {
0132         const QModelIndex index = m_model->index(i, 0, parent);
0133         if (m_treeView->isExpanded(index)) {
0134             list << index;
0135         }
0136         if (m_model->hasChildren(index)) {
0137             list << expandedNodes(index);
0138         }
0139     }
0140     return list;
0141 }
0142 
0143 void TOC::reparseConfig()
0144 {
0145     m_searchLine->setCaseSensitivity(Okular::Settings::contentsSearchCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive);
0146     m_searchLine->setRegularExpression(Okular::Settings::contentsSearchRegularExpression());
0147     m_treeView->update();
0148 }
0149 
0150 void TOC::slotExecuted(const QModelIndex &index)
0151 {
0152     if (!index.isValid()) {
0153         return;
0154     }
0155 
0156     QString url = m_model->urlForIndex(index);
0157     if (!url.isEmpty()) {
0158         Okular::BrowseAction action(QUrl::fromLocalFile(url));
0159         m_document->processAction(&action);
0160         return;
0161     }
0162 
0163     QString externalFileName = m_model->externalFileNameForIndex(index);
0164     Okular::DocumentViewport viewport = m_model->viewportForIndex(index);
0165     if (!externalFileName.isEmpty()) {
0166         Okular::GotoAction action(externalFileName, viewport);
0167         m_document->processAction(&action);
0168     } else if (viewport.isValid()) {
0169         m_document->setViewport(viewport);
0170     }
0171 }
0172 
0173 void TOC::saveSearchOptions()
0174 {
0175     Okular::Settings::setContentsSearchRegularExpression(m_searchLine->regularExpression());
0176     Okular::Settings::setContentsSearchCaseSensitive(m_searchLine->caseSensitivity() == Qt::CaseSensitive ? true : false);
0177     Okular::Settings::self()->save();
0178 }
0179 
0180 void TOC::contextMenuEvent(QContextMenuEvent *e)
0181 {
0182     QModelIndex index = m_treeView->currentIndex();
0183     if (!index.isValid()) {
0184         return;
0185     }
0186 
0187     Okular::DocumentViewport viewport = m_model->viewportForIndex(index);
0188 
0189     Q_EMIT rightClick(viewport, e->globalPos(), m_model->data(index).toString());
0190 }
0191 
0192 void TOC::expandRecursively()
0193 {
0194     QList<QModelIndex> worklist = {m_treeView->currentIndex()};
0195     if (!worklist[0].isValid()) {
0196         return;
0197     }
0198     while (!worklist.isEmpty()) {
0199         QModelIndex index = worklist.takeLast();
0200         m_treeView->expand(index);
0201         for (int i = 0; i < m_model->rowCount(index); i++) {
0202             worklist += m_model->index(i, 0, index);
0203         }
0204     }
0205 }
0206 
0207 void TOC::collapseRecursively()
0208 {
0209     QList<QModelIndex> worklist = {m_treeView->currentIndex()};
0210     if (!worklist[0].isValid()) {
0211         return;
0212     }
0213     while (!worklist.isEmpty()) {
0214         QModelIndex index = worklist.takeLast();
0215         m_treeView->collapse(index);
0216         for (int i = 0; i < m_model->rowCount(index); i++) {
0217             worklist += m_model->index(i, 0, index);
0218         }
0219     }
0220 }
0221 
0222 void TOC::expandAll()
0223 {
0224     m_treeView->expandAll();
0225 }
0226 
0227 void TOC::collapseAll()
0228 {
0229     m_treeView->collapseAll();
0230 }