File indexing completed on 2024-05-12 05:43:34

0001 /*
0002     Copyright (C) 2015 Volker Krause <vkrause@kde.org>
0003 
0004     This program is free software; you can redistribute it and/or modify it
0005     under the terms of the GNU Library General Public License as published by
0006     the Free Software Foundation; either version 2 of the License, or (at your
0007     option) any later version.
0008 
0009     This program is distributed in the hope that it will be useful, but WITHOUT
0010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
0012     License for more details.
0013 
0014     You should have received a copy of the GNU General Public License
0015     along with this program.  If not, see <https://www.gnu.org/licenses/>.
0016 */
0017 
0018 #include "elfstructureview.h"
0019 #include "ui_elfstructureview.h"
0020 
0021 #include <elfmodel/elfmodel.h>
0022 #include <navigator/codenavigator.h>
0023 
0024 #include <QSortFilterProxyModel>
0025 
0026 #include <QMouseEvent>
0027 
0028 ElfStructureView::ElfStructureView(QWidget* parent):
0029     QWidget(parent),
0030     ui(new Ui::ElfStructureView),
0031     m_proxy(new QSortFilterProxyModel(this))
0032 {
0033     ui->setupUi(this);
0034     ui->elfStructureView->setModel(m_proxy);
0035     m_proxy->setRecursiveFilteringEnabled(true);
0036     ui->elfStructureView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
0037 
0038     connect(ui->elfStructureView->selectionModel(), &QItemSelectionModel::selectionChanged,
0039             this, &ElfStructureView::selectionChanged);
0040     connect(ui->elfStructureSearchLine, &QLineEdit::textChanged, this, [this](const QString &text) {
0041         m_proxy->setFilterFixedString(text);
0042     });
0043     connect(ui->elfDetailView, &QTextBrowser::anchorClicked, this, &ElfStructureView::anchorClicked);
0044 
0045     ui->actionBack->setShortcut(QKeySequence::Back);
0046     ui->actionForward->setShortcut(QKeySequence::Forward);
0047 
0048     connect(ui->actionBack, &QAction::triggered, this, [this]() {
0049         --m_historyIndex;
0050         m_historyLock = true;
0051         selectUrl(m_history.at(m_historyIndex));
0052         m_historyLock = false;
0053         updateActionState();
0054     });
0055     connect(ui->actionForward, &QAction::triggered, this, [this]() {
0056         ++m_historyIndex;
0057         m_historyLock = true;
0058         selectUrl(m_history.at(m_historyIndex));
0059         m_historyLock = false;
0060         updateActionState();
0061     });
0062     addActions({ ui->actionBack, ui->actionForward });
0063     updateActionState();
0064 
0065     installEventFilter(this);
0066 }
0067 
0068 ElfStructureView::~ElfStructureView() = default;
0069 
0070 void ElfStructureView::setModel(ElfModel* model)
0071 {
0072     m_elfModel = model;
0073     m_proxy->setSourceModel(model);
0074 }
0075 
0076 void ElfStructureView::selectionChanged(const QItemSelection &selection)
0077 {
0078     if (selection.isEmpty()) {
0079         ui->elfDetailView->clear();
0080     return;
0081     }
0082 
0083     const QModelIndex index = selection.first().topLeft();
0084     ui->elfDetailView->setHtml(index.data(ElfModel::DetailRole).toString());
0085 
0086     if (m_historyLock)
0087         return;
0088     const auto url = index.data(ElfModel::NodeUrl).toUrl();
0089     if (url.isValid() && !url.isEmpty()) {
0090         m_history.resize(m_historyIndex + 2);
0091         m_history[++m_historyIndex] = url;
0092         updateActionState();
0093     }
0094 }
0095 
0096 void ElfStructureView::anchorClicked(const QUrl& url)
0097 {
0098     if (url.scheme() == QLatin1String("code"))
0099         CodeNavigator::goTo(url);
0100     else if (url.scheme() == QLatin1String("elfmodel"))
0101         selectUrl(url);
0102 }
0103 
0104 void ElfStructureView::updateActionState()
0105 {
0106     ui->actionBack->setEnabled(m_historyIndex > 0);
0107     ui->actionForward->setEnabled(m_historyIndex + 1 < m_history.size());
0108 }
0109 
0110 void ElfStructureView::selectUrl(const QUrl& url)
0111 {
0112     auto idx = m_elfModel->indexForUrl(url);
0113     idx = m_proxy->mapFromSource(idx);
0114     ui->elfStructureView->selectionModel()->select(idx, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
0115     ui->elfStructureView->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
0116     ui->elfStructureView->scrollTo(idx);
0117 }
0118 
0119 bool ElfStructureView::eventFilter(QObject *receiver, QEvent *event)
0120 {
0121     if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) {
0122         auto mouseEv = static_cast<QMouseEvent*>(event);
0123         if (mouseEv->button() == Qt::BackButton) {
0124             if (ui->actionBack->isEnabled())
0125                 ui->actionBack->trigger();
0126             return true;
0127         } else if (mouseEv->button() == Qt::ForwardButton) {
0128             if (ui->actionForward->isEnabled())
0129                 ui->actionForward->trigger();
0130             return true;
0131         }
0132     }
0133     return QObject::eventFilter(receiver, event);
0134 }