File indexing completed on 2024-04-28 08:27:05

0001 /* This file is part of KDevelop
0002  *  Copyright 2011 Sebastien Rannou <mxs@sbrk.org>
0003  *  Copyright 2008 Hamish Rodda <rodda@kde.org>
0004  *  Copyright 2011 Lucas Sarie <lucas.sarie@gmail.com>
0005  *  Copyright 2017 Anton Anikin <anton@anikin.xyz>
0006 
0007  This program is free software; you can redistribute it and/or
0008  modify it under the terms of the GNU General Public
0009  License as published by the Free Software Foundation; either
0010  version 2 of the License, or (at your option) any later version.
0011 
0012  This program is distributed in the hope that it will be useful,
0013  but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  General Public License for more details.
0016 
0017  You should have received a copy of the GNU General Public License
0018  along with this program; see the file COPYING.  If not, write to
0019  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020  Boston, MA 02110-1301, USA.
0021 
0022 */
0023 
0024 #include "callgrind_view.h"
0025 #include "ui_callgrind_view.h"
0026 
0027 #include "callgrind_config.h"
0028 #include "callgrind_model.h"
0029 #include "debug.h"
0030 #include "utils.h"
0031 
0032 #include <QSortFilterProxyModel>
0033 #include <QProcess>
0034 #include <QTemporaryFile>
0035 
0036 namespace Valgrind
0037 {
0038 
0039 CallgrindView::CallgrindView(KConfigGroup configGroup, QTemporaryFile* outputFile, CallgrindFunctionsModel* model, QWidget* parent)
0040     : QWidget(parent)
0041     , ui(new Ui::CallgrindView)
0042     , m_kcachegrindProcess(new QProcess)
0043 {
0044     ui->setupUi(this);
0045 
0046     Q_ASSERT(model);
0047     model->setParent(this);
0048 
0049     Q_ASSERT(outputFile);
0050     outputFile->setParent(this);
0051 
0052     for (const QString& eventType : model->eventTypes()) {
0053         ui->eventTypes->addItem(eventFullName(eventType));
0054     }
0055     connect(ui->eventTypes, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
0056             model, &CallgrindFunctionsModel::setCurrentEventType);
0057     model->setCurrentEventType(ui->eventTypes->currentIndex());
0058 
0059     connect(ui->percenageValues, &QCheckBox::stateChanged,
0060             model, &CallgrindFunctionsModel::setPercentageValues);
0061     model->setPercentageValues(ui->percenageValues->checkState());
0062 
0063     auto functionsProxyModel = new QSortFilterProxyModel(this);
0064     functionsProxyModel->setSourceModel(model);
0065     functionsProxyModel->setSortRole(SortRole);
0066     functionsProxyModel->setFilterKeyColumn(-1);
0067     ui->functionsView->setModel(functionsProxyModel);
0068     ui->functionsView->setSortingEnabled(true);
0069 
0070     connect(ui->searchEdit, &QLineEdit::textChanged,
0071             functionsProxyModel, &QSortFilterProxyModel::setFilterWildcard);
0072 
0073     auto eventsModel = new CallgrindFunctionEventsModel(model);
0074     ui->eventsView->setModel(eventsModel);
0075     ui->eventsView->header()->resizeSections(QHeaderView::ResizeToContents);
0076 
0077     auto callersModel = new CallgrindFunctionCallersCalleesModel(model, true);
0078     auto callersProxyModel = new QSortFilterProxyModel(this);
0079     callersProxyModel->setSourceModel(callersModel);
0080     callersProxyModel->setSortRole(SortRole);
0081     ui->callersView->setModel(callersProxyModel);
0082     ui->callersView->setSortingEnabled(true);
0083 
0084     connect(callersModel, &CallgrindFunctionCallersCalleesModel::headerDataChanged,
0085             this, [this](Qt::Orientation, int, int) {
0086         ui->callersView->header()->resizeSections(QHeaderView::ResizeToContents);
0087     });
0088 
0089     auto calleesModel = new CallgrindFunctionCallersCalleesModel(model, false);
0090     auto calleesProxyModel = new QSortFilterProxyModel(this);
0091     calleesProxyModel->setSourceModel(calleesModel);
0092     calleesProxyModel->setSortRole(SortRole);
0093     ui->calleesView->setModel(calleesProxyModel);
0094     ui->calleesView->setSortingEnabled(true);
0095 
0096     connect(calleesModel, &CallgrindFunctionCallersCalleesModel::headerDataChanged,
0097             this, [this](Qt::Orientation, int, int) {
0098         ui->calleesView->header()->resizeSections(QHeaderView::ResizeToContents);
0099     });
0100 
0101     connect(ui->functionsView->selectionModel(), &QItemSelectionModel::currentChanged,
0102             this, [=](const QModelIndex& currentProxyIndex, const QModelIndex&) {
0103 
0104         auto sourceIndex = functionsProxyModel->mapToSource(currentProxyIndex);
0105         auto function = static_cast<CallgrindFunction*>(sourceIndex.internalPointer());
0106 
0107         eventsModel->setFunction(function);
0108         callersModel->setFunction(function);
0109         calleesModel->setFunction(function);
0110 
0111         if (function) {
0112             ui->binaryLabel->setText(function->binaryFile);
0113             ui->sourceLabel->setText(function->sourceFiles.join('\n'));
0114         } else {
0115             ui->binaryLabel->clear();
0116             ui->sourceLabel->clear();
0117         }
0118     });
0119     ui->binaryLabel->clear();
0120     ui->sourceLabel->clear();
0121 
0122     if (functionsProxyModel->rowCount()) {
0123         ui->functionsView->setCurrentIndex(functionsProxyModel->index(0,0));
0124     }
0125 
0126     auto startVisualizer = [this, outputFile]() {
0127         m_kcachegrindProcess->start(CallgrindConfig::kcachegrindExecutablePath(),
0128                                     { outputFile->fileName() });
0129     };
0130 
0131     CallgrindConfig config;
0132     config.setConfigGroup(configGroup);
0133     config.load();
0134 
0135     setupVisualizerProcess(m_kcachegrindProcess.data(),
0136                            ui->launchKCachegrindButton,
0137                            startVisualizer, config.launchKCachegrind());
0138 }
0139 
0140 CallgrindView::~CallgrindView()
0141 {
0142     m_kcachegrindProcess->disconnect(); // FIXME is this really needed ?
0143 }
0144 
0145 }