File indexing completed on 2024-04-28 17:02:18
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 0030 #include <KDebug> 0031 #include <KParts/Part> 0032 #include <KStandardAction> 0033 #include <KActionCollection> 0034 #include <KAction> 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(0) 0047 , m_zoomIn(0) 0048 , m_zoomOut(0) 0049 , m_focusExpensive(0) 0050 { 0051 setXMLFile("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(0, data->peak())); 0062 } 0063 0064 CallGraphTab::~CallGraphTab() 0065 { 0066 if (m_dotGenerator) { 0067 if (m_dotGenerator->isRunning()) { 0068 disconnect(m_dotGenerator.data(), 0, this, 0); 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 = 0; 0080 m_lastDotItem.second = 0; 0081 } 0082 0083 void CallGraphTab::setupActions() 0084 { 0085 m_zoomIn = KStandardAction::zoomIn(this, SLOT(zoomIn()), actionCollection()); 0086 actionCollection()->addAction("zoomIn", m_zoomIn); 0087 m_zoomOut = KStandardAction::zoomOut(this, SLOT(zoomOut()), actionCollection()); 0088 actionCollection()->addAction("zoomOut", m_zoomOut); 0089 m_focusExpensive = new KAction(KIcon("flag-red"), i18n("Focus most expensive node"), actionCollection()); 0090 connect(m_focusExpensive, SIGNAL(triggered()), this, SLOT(focusExpensiveGraphNode())); 0091 actionCollection()->addAction("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 kDebug() << "new dot graph requested" << item; 0123 if (m_dotGenerator) { 0124 kDebug() << "existing generator is running:" << m_dotGenerator->isRunning(); 0125 if (m_dotGenerator->isRunning()) { 0126 disconnect(m_dotGenerator.data(), 0, this, 0); 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 kDebug() << "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 }