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 "dependencyview.h"
0019 #include "ui_dependencyview.h"
0020 #include <dependencymodel/dependencymodel.h>
0021 #include <dependencymodel/usedsymbolmodel.h>
0022 #include <dependencymodel/unuseddependenciesmodel.h>
0023 #include <dependencymodel/filelistmodel.h>
0024 #include <dependencymodel/fileusermodel.h>
0025 
0026 #include <elf/elffile.h>
0027 #include <elf/elffileset.h>
0028 #include <optimizers/dependencysorter.h>
0029 
0030 #include <QDebug>
0031 #include <QSortFilterProxyModel>
0032 
0033 DependencyView::DependencyView(QWidget* parent):
0034     QWidget(parent),
0035     ui(new Ui::DependencyView),
0036     m_dependencyModel(new DependencyModel(this)),
0037     m_symbolModel(new UsedSymbolModel(this)),
0038     m_unusedDependenciesModel(new UnusedDependenciesModel(this)),
0039     m_fileListModel(new FileListModel(this)),
0040     m_fileUserModel(new FileUserModel(this)),
0041     m_inverseSymbolModel(new UsedSymbolModel(this))
0042 {
0043     ui->setupUi(this);
0044 
0045     // top down dependencies tab
0046     ui->dependencyView->setModel(m_dependencyModel);
0047     ui->dependencyView->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
0048     connect(ui->dependencySearchLine, &QLineEdit::textChanged, this, &DependencyView::search);
0049     connect(ui->dependencyView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &DependencyView::dependencySelected);
0050 
0051     auto proxy = new QSortFilterProxyModel(this);
0052     proxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
0053     proxy->setSourceModel(m_symbolModel);
0054     ui->symbolView->setModel(proxy);
0055     connect(ui->symbolSearchLine, &QLineEdit::textChanged, proxy, &QSortFilterProxyModel::setFilterFixedString);
0056 
0057     // inverse dependencies tab
0058     proxy = new QSortFilterProxyModel(this);
0059     proxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
0060     proxy->setSourceModel(m_fileListModel);
0061     ui->inverseFileList->setModel(proxy);
0062     connect(ui->inverseFileListSearchLine, &QLineEdit::textChanged, proxy, &QSortFilterProxyModel::setFilterFixedString);
0063     connect(ui->inverseFileList->selectionModel(), &QItemSelectionModel::selectionChanged, this, &DependencyView::inverseFileSelected);
0064 
0065     proxy = new QSortFilterProxyModel(this);
0066     proxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
0067     proxy->setSourceModel(m_fileUserModel);
0068     ui->inverseDependencyList->setModel(proxy);
0069     connect(ui->inverseDependencyListSearchLine, &QLineEdit::textChanged, proxy, &QSortFilterProxyModel::setFilterFixedString);
0070     connect(ui->inverseDependencyList->selectionModel(), &QItemSelectionModel::selectionChanged, this, &DependencyView::inverseUserSelected);
0071 
0072     proxy = new QSortFilterProxyModel(this);
0073     proxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
0074     proxy->setSourceModel(m_inverseSymbolModel);
0075     ui->inverseSymbolList->setModel(proxy);
0076     ui->inverseSymbolList->header()->setSortIndicator(0, Qt::AscendingOrder);
0077     connect(ui->inverseSymbolListSearchLine, &QLineEdit::textChanged, proxy, &QSortFilterProxyModel::setFilterFixedString);
0078 
0079     // unused dependencies tab
0080     proxy = new QSortFilterProxyModel(this);
0081     proxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
0082     proxy->setFilterKeyColumn(-1);
0083     proxy->setSourceModel(m_unusedDependenciesModel);
0084     ui->unusedDependencyView->setModel(proxy);
0085     ui->unusedDependencyView->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
0086     connect(ui->unusedSearchLine, &QLineEdit::textChanged, proxy, &QSortFilterProxyModel::setFilterFixedString);
0087     connect(ui->tabWidget, &QTabWidget::currentChanged, this, [this]{
0088         if (ui->tabWidget->currentWidget() == ui->unusedDependenciesTab)
0089             m_unusedDependenciesModel->findUnusedDependencies();
0090     });
0091 
0092     addAction(ui->actionOptimizeDependencyOrder);
0093     connect(ui->actionOptimizeDependencyOrder, &QAction::triggered, this, [this]() {
0094         const auto selection = ui->dependencyView->selectionModel()->selectedRows();
0095         if (selection.isEmpty())
0096             return;
0097         const auto idx = selection.first();
0098         const auto f = idx.data(DependencyModel::ProviderFileRole).value<ElfFile*>();
0099         if (f) {
0100             qDebug() << f->fileName();
0101             ElfFileSet set;
0102             set.addFile(f->fileName());
0103             DependencySorter sorter;
0104             sorter.sortDtNeeded(&set);
0105 
0106             // TODO reload file set!
0107         }
0108     });
0109 }
0110 
0111 DependencyView::~DependencyView() = default;
0112 
0113 void DependencyView::setFileSet(ElfFileSet* fileSet)
0114 {
0115     m_dependencyModel->setFileSet(fileSet);
0116     if (m_dependencyModel->rowCount() > 0)
0117         ui->dependencyView->expand(m_dependencyModel->index(0, 0));
0118     m_fileListModel->setFileSet(fileSet);
0119     m_unusedDependenciesModel->setFileSet(fileSet);
0120     if (ui->tabWidget->currentWidget() == ui->unusedDependenciesTab)
0121         m_unusedDependenciesModel->findUnusedDependencies();
0122 }
0123 
0124 void DependencyView::search(const QString& text)
0125 {
0126     if (text.isEmpty())
0127         return;
0128 
0129     const auto result = m_dependencyModel->match(m_dependencyModel->index(0, 0), Qt::DisplayRole, text, 1, Qt::MatchContains | Qt::MatchRecursive);
0130     if (result.isEmpty())
0131         return;
0132     const auto index = result.first();
0133     ui->dependencyView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
0134     ui->dependencyView->scrollTo(index);
0135 }
0136 
0137 void DependencyView::dependencySelected(const QItemSelection& selection)
0138 {
0139     if (selection.isEmpty())
0140         return;
0141     const auto idx = selection.first().topLeft();
0142 
0143     auto user = idx.data(DependencyModel::UserFileRole).value<ElfFile*>();
0144     auto provider = idx.data(DependencyModel::ProviderFileRole).value<ElfFile*>();
0145     m_symbolModel->setFiles(user, provider);
0146 }
0147 
0148 void DependencyView::inverseFileSelected(const QItemSelection& selection)
0149 {
0150     if (selection.isEmpty()) {
0151         m_fileUserModel->setFile(nullptr, nullptr);
0152         return;
0153     }
0154 
0155     const auto idx = selection.first().topLeft();
0156     m_fileUserModel->setFile(m_fileListModel->fileSet(), idx.data(FileListModel::FileRole).value<ElfFile*>());
0157 }
0158 
0159 void DependencyView::inverseUserSelected(const QItemSelection& selection)
0160 {
0161     if (selection.isEmpty()) {
0162         m_inverseSymbolModel->setFiles(nullptr, nullptr);
0163         return;
0164     }
0165 
0166     const auto idx = selection.first().topLeft();
0167     m_inverseSymbolModel->setFiles(idx.data(FileUserModel::FileRole).value<ElfFile*>(), m_fileUserModel->usedFile());
0168 }