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

0001 /*
0002    This file is part of Massif Visualizer
0003 
0004    Copyright 2014 Milian Wolff <mail@milianw.de>
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU General Public License as
0008    published by the Free Software Foundation; either version 2 of
0009    the License or (at your option) version 3 or any later version
0010    accepted by the membership of KDE e.V. (or its successor approved
0011    by the membership of KDE e.V.), which shall act as a proxy
0012    defined in Section 14 of version 3 of the license.
0013 
0014    This program is distributed in the hope that it will be useful,
0015    but WITHOUT ANY WARRANTY; without even the implied warranty of
0016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017    GNU General Public License for more details.
0018 
0019    You should have received a copy of the GNU General Public License
0020    along with this program.  If not, see <http://www.gnu.org/licenses/>.
0021 */
0022 
0023 #include "callgraphtab.h"
0024 
0025 #include "visualizer/dotgraphgenerator.h"
0026 #include "massifdata/filedata.h"
0027 
0028 #include <QVBoxLayout>
0029 #include <QAction>
0030 #include <QDebug>
0031 
0032 #include <KParts/ReadOnlyPart>
0033 #include <KStandardAction>
0034 #include <KActionCollection>
0035 #include <KLocalizedString>
0036 
0037 #include <kgraphviewer_interface.h>
0038 
0039 using namespace Massif;
0040 
0041 CallGraphTab::CallGraphTab(const FileData* data, KParts::ReadOnlyPart* graphViewerPart,
0042                            KXMLGUIClient* guiParent, QWidget* parent)
0043     : DocumentTabInterface(data, guiParent, parent)
0044     , m_graphViewerPart(graphViewerPart)
0045     , m_graphViewer(qobject_cast<KGraphViewer::KGraphViewerInterface*>(m_graphViewerPart))
0046     , m_dotGenerator(nullptr)
0047     , m_zoomIn(nullptr)
0048     , m_zoomOut(nullptr)
0049     , m_focusExpensive(nullptr)
0050 {
0051     setXMLFile(QStringLiteral("callgraphtabui.rc"), true);
0052     setupActions();
0053 
0054     Q_ASSERT(m_graphViewer);
0055     setLayout(new QVBoxLayout);
0056     layout()->addWidget(m_graphViewerPart->widget());
0057 
0058     connect(m_graphViewerPart, SIGNAL(graphLoaded()),
0059             this, SLOT(slotGraphLoaded()));
0060 
0061     showDotGraph(ModelItem(nullptr, data->peak()));
0062 }
0063 
0064 CallGraphTab::~CallGraphTab()
0065 {
0066     if (m_dotGenerator) {
0067         if (m_dotGenerator->isRunning()) {
0068             disconnect(m_dotGenerator.data(), nullptr, this, nullptr);
0069             connect(m_dotGenerator.data(), SIGNAL(finished()),
0070                     m_dotGenerator.data(), SLOT(deleteLater()));
0071             m_dotGenerator->cancel();
0072             m_dotGenerator.take();
0073         }
0074         m_dotGenerator.reset();
0075     }
0076     if (m_graphViewer) {
0077         m_graphViewerPart->closeUrl();
0078     }
0079     m_lastDotItem.first = nullptr;
0080     m_lastDotItem.second = nullptr;
0081 }
0082 
0083 void CallGraphTab::setupActions()
0084 {
0085     m_zoomIn = KStandardAction::zoomIn(this, SLOT(zoomIn()), actionCollection());
0086     actionCollection()->addAction(QStringLiteral("zoomIn"), m_zoomIn);
0087     m_zoomOut = KStandardAction::zoomOut(this, SLOT(zoomOut()), actionCollection());
0088     actionCollection()->addAction(QStringLiteral("zoomOut"), m_zoomOut);
0089     m_focusExpensive = new QAction(QIcon::fromTheme(QStringLiteral("flag-red")), i18n("Focus most expensive node"), actionCollection());
0090     connect(m_focusExpensive, SIGNAL(triggered()), this, SLOT(focusExpensiveGraphNode()));
0091     actionCollection()->addAction(QStringLiteral("focusExpensive"), m_focusExpensive);
0092 }
0093 
0094 void CallGraphTab::settingsChanged()
0095 {
0096 
0097 }
0098 
0099 void CallGraphTab::focusExpensiveGraphNode()
0100 {
0101     Q_ASSERT(m_graphViewer);
0102     Q_ASSERT(m_dotGenerator);
0103 
0104     m_graphViewer->centerOnNode(m_dotGenerator->mostCostIntensiveGraphvizId());
0105 }
0106 
0107 void CallGraphTab::showDotGraph(const ModelItem& item)
0108 {
0109     m_nextDotItem = item;
0110 
0111     if (item == m_lastDotItem && m_graphViewerPart->url().isValid()) {
0112         return;
0113     }
0114 
0115     if (!isVisible()) {
0116         return;
0117     }
0118     m_lastDotItem = item;
0119 
0120     Q_ASSERT(m_graphViewer);
0121 
0122     qDebug() << "new dot graph requested" << item;
0123     if (m_dotGenerator) {
0124         qDebug() << "existing generator is running:" << m_dotGenerator->isRunning();
0125         if (m_dotGenerator->isRunning()) {
0126             disconnect(m_dotGenerator.data(), nullptr, this, nullptr);
0127             connect(m_dotGenerator.data(), SIGNAL(finished()),
0128                     m_dotGenerator.data(), SLOT(deleteLater()));
0129             m_dotGenerator->cancel();
0130             m_dotGenerator.take();
0131         }
0132         m_dotGenerator.reset();
0133     }
0134     if (!item.first && !item.second) {
0135         return;
0136     }
0137     if (item.second) {
0138         m_dotGenerator.reset(new DotGraphGenerator(item.second, m_data->timeUnit(), this));
0139     } else {
0140         m_dotGenerator.reset(new DotGraphGenerator(item.first, m_data->timeUnit(), this));
0141     }
0142     m_dotGenerator->start();
0143     connect(m_dotGenerator.data(), SIGNAL(finished()), this, SLOT(showDotGraph()));
0144 }
0145 
0146 void CallGraphTab::setVisible(bool visible)
0147 {
0148     QWidget::setVisible(visible);
0149 
0150     if (visible) {
0151         showDotGraph(m_nextDotItem);
0152     }
0153 }
0154 
0155 void CallGraphTab::showDotGraph()
0156 {
0157     if (!m_dotGenerator || !m_graphViewerPart || !isVisible()) {
0158         return;
0159     }
0160     qDebug() << "show dot graph in output file" << m_dotGenerator->outputFile();
0161     const auto url = QUrl::fromLocalFile(m_dotGenerator->outputFile());
0162     if (url.isValid() && m_graphViewerPart->url() != url) {
0163         m_graphViewerPart->openUrl(url);
0164     }
0165 }
0166 
0167 void CallGraphTab::slotGraphLoaded()
0168 {
0169     Q_ASSERT(m_graphViewer);
0170 
0171     if (!m_dotGenerator) {
0172         return;
0173     }
0174     m_graphViewer->setZoomFactor(0.75);
0175     m_graphViewer->setPannerPosition(KGraphViewer::KGraphViewerInterface::BottomRight);
0176     m_graphViewer->setPannerEnabled(true);
0177     m_graphViewer->centerOnNode(m_dotGenerator->mostCostIntensiveGraphvizId());
0178 }
0179 
0180 void CallGraphTab::zoomIn()
0181 {
0182     m_graphViewer->zoomIn();
0183 }
0184 
0185 void CallGraphTab::zoomOut()
0186 {
0187     m_graphViewer->zoomOut();
0188 }
0189 
0190 void CallGraphTab::selectModelItem(const ModelItem& item)
0191 {
0192     showDotGraph(item);
0193 }
0194 
0195 #include "moc_callgraphtab.cpp"